Roppongi.vue #4 参加レポート
Vue.js + a11y
- @yamanoku さん, @rhirayamaaan さん
- www.youtube.com
- Web アクセシビリティ
- アクセ渋るな実装・コンポーネント
- アクセシビリティのチェック・テスト
- Storybook
- eslint-plugin-vue-a11y
- vue-axe
- ユーザテスト
- Vue.jsとアクセシビリティの関わりについて
- 参加しやすさ
- 日本語翻訳があったのがでかい
- 公式ドキュメントであまり言及されていない話
- アクセシビリティに対して言及があまりない
- issueは立っていた
- Reactは結構豊富
- アクセシビリティに対して言及があまりない
- Vue3.0でのFragment
- ReactでいうFragmentが実装される
- Vue A11Yグループができている
- https://vue-a11y.com/
- Comming soonであったり、これから作っていくところが多そう?
- アクセシビリティの課題とこれからの展望
- 重要度の認知不足
- コメント: 海外だと裁判沙汰になってりもするみたいなので、重要性は増していきそう。https://www.mitsue.co.jp/knowledge/column/20190125.html
- 対応を継続していく難しさ
- 多様性が発展の鍵になる
- 重要度の認知不足
- 参加しやすさ
Vueで着せ替えアプリ作ろうとしてハマったこと & リアクティブなコンポーネント設計とpropsの話
- docs.google.com
- @yuneco さん
- フロントエンドエンジニア
- Vueで着せ替えアプリ作ろうとしてハマったこと
- リアクティブなコンポーネント設計とprops
コメント
イラストがかわいくてすごい!!
ポートフォリオサイトもすごい!! https://pf.nekobooks.com/
サーバーレスアーキテクチャとNuxtで特設サイトを作った話
- speakerdeck.com
- @potproject さん
- 株式会社アイスタイルメディア
- cosmeサイトの名でもエンジニア
- @cosme Beauty Day
- https://beautyday.cosme.net/
- サーバレスアーキテクチャ
- Nuxt.js
- BDDのためAPIも共存していた
- 採用した理由
- デプロイ
- サーバーレス+Nuxt.jsでSSRを実現するには?
- Serverless Framework
- CI/CD
- yamlに構成を書くとデプロイできる
- パフォーマンスチューニング
- Vue-lazyload
- 画像を遅延読み込みにできる
- Vue-lazyload
- 当日
- アクセスが20倍になった
- 応答時間が変わらず表示できていた
- Nuxt.jsでは問題なかったけど、FBBとかで障害などがあった
- アクセスが20倍になった
VeeValidate 3.0について
- @igayamaguchi さん
- 株式会社 一休
- VeeValidate
- https://logaretm.github.io/vee-validate/
- Vueのバリデーションライブラリ
- できること
- コンポーネントの組み合わせでバリデーションができる
- VeeValidate 3.0
- 1年半腰にアップデートがきた
- やること
- 初期設定
- 必要最低限にバリデーションルールもある
- ValidationProvider
- inputに設定されたv-modelを監視してくれる
- ValidationObserver
- VeeValidate
- RuleはView側に寄っていく
- 素のVue.jsで書いていくのであれば、watchになりそう?
- RuleはView側に寄っていく
コメント
あまり聞きなれない単語ばかりで、ついていくのが大変だった。(一部ついていけなかった) 勉強しないと・・・
Vueのリアクティブシステムを理解してパフォーマンス低下を防ごう
@ninjinkun さん
- 株式会社 一休
- 問題
- 一休レストランの管理画面
- 体感速度が遅い
- 1万個のチェックボックスが重い
- 体感速度が遅い
- 一休レストランの管理画面
- 一つのチェックボックスを更新するたび、毎回全部更新していた
- コンポーネントに渡すオブジェクトを毎回再生性していた
- オブジェクトはイミュータブルに更新したほうが早いと思っていた
- 根本原因
- Vueのリアクティブシステム
- props, dataが更新されると画面が自動更新される
- これを支えるのがリアクティブシステム
- props, dataが更新されると画面が自動更新される
- リアクティブシステムの実装
- オブジェクトの変更監視はプロパティのgetter/setterベース
- オブジェクトを入れ替えると、全部見直すことになる
- 遅い原因
- イミュータブル
- 再代入すると遅い
- 変更したオブジェクトをミュータブルに更新する
Reactはイミュータブルが主流
- Reactにはリアクティブシステムがない
まとめ
- 変更したプロパティだけをmutableに更新する
- Vueのリアクティブシステムを理解すると捗る
コメント
ReactとVueの変更点を具体的に一つ知れた!(React全く触ったことがない)
あとがき
- ライブ配信の仕方も実況動画っぽくて面白かったです。GameWithさんのゲーム会社ならではの設備があってこそなのかな〜と思いました。
- Vue.js
- まだライブラリなどが出揃っていないのかな?といった印象を受けました。(まだ出て5年ということもあると思いますが)
- これからもどんどん増えていくのかなと思います。
平成Ruby会議 参加レポート
はじめに
平成Ruby会議・スタッフ・スピーカーの皆様、こんなに素晴らしいイベントを企画・開催してくださりありがとうございます! 大変楽しかったです!!
平成Ruby会議、参加レポート
平成Ruby会議に参加してきました!
どういう話だったか、簡単に「どういう話だったか」と「感想」をそれぞれ書いてみました。
もしニュアンスなど違うよ!という話があれば、コメントやツイッターのリプ(@s4na_penguin)で教えてくださると助かります!
※残念ながら、何件かネット上で見つけることができなかった資料を載せることができていません。申し訳ないです🙇♂️
聞いてきた話
What is expected?
Rubyのパーサーがいかにして、人間によって記述された.rb
ファイルを読み解いているか
人間のメンテナンスと自動生成の協調
感想
いくらRubyという有名なOSSでも、現実的にどうやって実装していくか考えると、人間のリソースについても考えなければならないんだな〜と思いました。(考えてみれば当たり前の話ではあるんですけど)
ActiveSupport::Concernで開く メタプログラミングの扉
メタプログラミングというと、ひとえに嫌煙されがちだけど、大きな価値を見逃している。
例えばRailsを使っているとActiveSupportのConcernという名前を一度は聞いたことがあるはず。
そんな便利なConcernですが、実はメタプログラミングで実装されていて、しかもシンプルな50行で書かれているのです!
今回の発表では、Concernのソースコードについて読み解いていました。
感想
Concern、名前しか聞いたことないですが、メタプログラミングを勉強する段階になったら、私も読んでみたいな〜と思いました。
新規プロジェクトのリードエンジニアになるために
新規プロジェクトのリードエンジニアと言われると、色々任される役割を想像すると思います。
今回は過去の経験も踏まえて、「技術選定と見積もり」「rails new コードの規約作成」という2点に絞って話をされていました。
感想
OSSとしてRailsのtemplateを公開しているなど、平成Ruby会議が終わってからも持ち帰れるものがあって良い発表だな〜と思いました。
HotateさんのLTは過去に2回聞いたことがあり、いずれもすぐ自分の開発に持ち帰れるものがあり、大変勉強になります👏
Procのススメ
「「Procを使っていますか?」と言われて、Procを使っていると答える人は多くないかもしれません。
ですが、Procは隠れたところで使っていたりするので、どう便利なのか紹介します!」という話をされていました。
感想
Procとラムダの違いがいまだにわからないので。調べてみようと思いました。
調べた結果
- 参考: https://qiita.com/ryo-ma/items/24c46592b45775e8644d
- {}
- ブロック。オブジェクトではない
- Proc
- ブロックをオブジェクト化したもの
- ラムダ
- 正直、まだ違いがちょっとよくわからない
既存プロダクトにRSpecを導入していく
テストコードのカバレッジが5%な状態から、15%にあげた話
感想
もともとテストコードがほとんどないということは、文化作りから行なったということで、大変行動力がある!と勇気をもらえました。
やわらか増税 はじめての増税対応
軽減税率対応した話。税率の適応タイミングは、ちゃんと読まないと誤った判断をしてしまう。
感想
時間をかけて準備していても、どうしても漏れてしまうものなのだな〜。ソフトウェア開発、難しい。
真のREST
RESTとはURL設計ではない RESTとはCRUDではない
REST厨を自称する @tkawa さんによる、真のRESTの話。
感想
RESTというとRESTfule APIの話を思い浮かべてきたので、結構衝撃的な話でした。
「技術は振り子ではなく螺旋」など、大変勉強になりました👏
Breaking Change[破壊的変更]
破壊的変更をRubocopという一芸で乗り越えた話
※破壊的変更 = 利用コードへの後方互換をなくす変更
感想
一芸は身を助けると言いますよね・・・一芸が欲しい・・・
OSSで結果を出す方法
- OSSにバッチを当てるときは、相手のことを考えることが必要。
- OSSのパッチを受け取る人は、受け取ったパッチのことを一生メンテナンスしなければならない。
- ユーザーにとって価値のないパッチを受け取ることは、負担でしかない。
感想
つい先日もOSSにパッチを投げたいな〜と思っていたりしたので、私的にタイムリーで勉強になる話でした。
飛び込みLT
SimpleDelegator活用のご提案
RubyとLispの切っても切れない関係
残念ながら、聞けなかった話
今回平成Ruby会議では一度に2つの発表が別会場で行われていたので、残念ながら聞けなかったLTもありました😢
階層的クラスタリングをRubyで表現する
Good to know yaml
Ruby on Jeeeeeeeeets!!✨🚀✨
Play with Ruby
TextbringerでつくるTextbringer
RubyでGemを作ろう
スポンサー様LT
What's Drecom in 5 min
ラクマさん「平成Ruby会議にてコーヒースポンサーを行いました!」
SmartHR会社紹介資料
STORES.jpがクリエイディブスポンサーをしてみた!
スマートキャンプのBOXILについて
RailsにPRを送って発見したOSS貢献への気づき
感想
RailsにPRすごい👏
まとめ
今後の自分に活かすため、一つ一つキャッチアップしていきたいと思いました👍
Apache Arrow東京ミートアップ2019参加時のメモ、走り書き
まえがき
銀座RailsでRubyコミッターのMurataさんが登壇された際、「Apache Arrowがすごい!近日1.0.0のリリースをするので、それに向けてイベントがある。ぜひ参加してほしい!」と話をされていたので、面白そうなので参加してみました。
素晴らしいイベントに会場を提供してくださったSpeeeさんありがとうございます!!
イベントの内容
今日のイベントについて
- https://speee.connpass.com/event/152887/
- 大まかな流れ
- 最新情報
- どうやって使い始めるか検討・・・ユースケース
発表:Apache Arrowの最新情報 須藤功平さん
- https://slide.rabbit-shocker.org/authors/kou/apache-arrow-tokyo-meetup-2019/
- 1,2月あたりApache Arrow 1.0.0が出る!
- 使い始めるなら今!
- 今使ってない人でも、1.0.0出たら使い始めるので、今から触っているといい
- https://github.com/apache/arrow
- みんなで力を合わせたら使える
- 発表:Apache Arrowの最新情報 村田賢太さん
- https://speakerdeck.com/yutannihilation/r-and-apache-arrow
- Apache Arrow
- 発表:Apache Arrow Datasets C++ 須藤功平さん
- RとApache Arrow 湯谷啓明さん
- Apache ArrowでRの開発が進んでいる理由
- 発表:PostgreSQLとApache Arrowの利用事 海外浩平さん
- 発表:Apache SparkとApache Arrowの連携 Takeshi Yamamuroさん
- 発表:TensorFlowとApache Arrowの連携 石崎一明
- 発表:TensorFlowとBigQuery Storage APIとApache Arrowの連携評価事例 漆山和樹さん
- 個人的に
- Featherって?
- Parquestって?
- アノテーション?
あとがき
走り書きなので、誤字脱字などあるかとは思いますが、見つけた際はご連絡いただけるとありがたいです。
フィヨルドブートキャンプのWebアプリで使っている、Vue.jsのコードリーディング
はじめに
今回はVue.jsで書かれたコードを読んでいきたいと思います!
Vue.jsは少ししか触ったことがないので、読み間違えているところなどあったら申し訳ないです😥
また、私は初学者なので、わからないことは「わからない」であるとか「?(疑問符)」を付けて書いています。
教えてくださる方がいらっしゃれば嬉しいです🙇♂️
わかったことがあれば随時追記していきます!
本記事にはrequestの結果などが記載されていますが、全てテスト環境のテストデータが元になっています。
今回読むコードについて
今回読んでいくソースは、フィヨルドブートキャンプ本体のWebアプリケーションです。
使っているフレームワークはRails + Vue.jsです。また、Railsのテンプレートエンジンはslimを使用しています。そのため今回はslimで書かれたコードが多く登場します。
コード本体がこちら(fjord/bootcamp)で、OSSになっており誰でも読めます。
ライセンスについて
ライセンスはまだついておりませんが、今後付ける予定です。また、フィヨルドブートキャンプへの許可は取得しております。
今回読む箇所
今回はコメントをVue.js化 #1017を読んでいきます。
Vue.jsのコードリーディング
まずは日報(report)機能から読んでいきます。
読みたいのはコメント(comment)機能なのですが、コメント機能は独立で存在していないので、私としてはなじみのある日報のコメントから読んでいこうと思います。
/app/views/reports/show.html.slim
# 略 #js-comments(data-commentable-id="#{@report.id}" data-commentable-type="Report" data-current-user-id="#{current_user.id}") = render "footprints/footprints", footprints: @footprints
#js-comments
にdata-commentable-id
,data-commentable-type
,data-current-user-id
を渡す- 疑問:Vue.jsのjsがなければ
#〜
はそのまま表示される?
- 疑問:Vue.jsのjsがなければ
/app/javascript/packes/application.js
/* eslint no-console:0 */ // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. // // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate // layout file, like app/views/layouts/application.html.erb require('./markdown.js') require('./markdown-it.js') require('./autosize.js') require('../shortcut.js') require('../learning.js') require('../learning-status.js') require('../check.js') require('../check-stamp.js') require('../comments.js') require('../category-select.js') require('../grass.js') // 略
- Rails5.2のため、webpacker(
Sprockets)でJavaScriptが管理されている require('../comments.js')
により、/app/javascript/comments.js
にアクセスが可能となる
/app/javascript/comments.js
import Vue from 'vue' import Comments from './comments.vue' document.addEventListener('DOMContentLoaded', () => { const comments = document.getElementById('js-comments') if (comments) { const commentableId = comments.getAttribute('data-commentable-id') const commentableType = comments.getAttribute('data-commentable-type') const currentUserId = comments.getAttribute('data-current-user-id') new Vue({ render: h => h(Comments, { props: { commentableId: commentableId, commentableType: commentableType, currentUserId: currentUserId } }) }).$mount('#js-comments') } })
- jsでhtmlの情報を取得してvueをレンダリング
- 疑問:そういえばこれは、サーバー側で処理している?
- もしそうなら、htmlの出力データをテンプレートエンジン代わりにしている?
- 疑問:そういえばこれは、サーバー側で処理している?
- element.getAttribute
- 疑問:current-userのidをフロントのjsで判定したら、好きなユーザーとしてコメントを投稿できるのでは?
- この疑問は、初めレンダリングをフロントで行なっていると想定していたため発生しました。実際はサーバーサイドで行なっているので、書き換えはできない状態でした。
- 下記部分で
comment.vue
を呼び出している
new Vue({ render: h => h(Comments, { props: { commentableId: commentableId, commentableType: commentableType, currentUserId: currentUserId } }) }).$mount('#js-comments')
/app/javascript/comments.vue
- 「なんかたくさんあるけどなんだっけ?」と一瞬思ったけど、Vue.jsにはライフサイクルがあったことを思い出した
- 変数と
date: () => {}
の違いってなんだっけ?課題で、dateに書くか書かないかでとても違いが出たことしか覚えていない・・・- Vue.js入門を読んだら、
date: () => {}
はdataプロパティと書いてあった- UIの状態を置く場所
- Vue.js入門を読んだら、
- script以外に、scriptと一緒にtempleteが書かれた
.vue
ファイルを読み書きしたことがないことに気づく😲‼️- Vue.js入門を再度読み返した
- 3章のコンポーネントまで理解できれば良さそうなので、読んでみた
- Vue.js入門を再度読み返した
props
export default { props: ['commentableId', 'commentableType', 'currentUserId'], components: { 'comment': Comment, 'markdown-textarea': MarkdownTextarea },
- props
- 親コンポーネントからデータを受け取るところ
data
data: () => { return { currentUser: {}, comments: [], description: '', tab: 'comment' } },
- そういえば、props, dataの違いがわからないので、調べてみた
import
import Comment from './comment.vue' import MarkdownTextarea from './markdown-textarea.vue' import MarkdownIt from 'markdown-it' import MarkdownItEmoji from 'markdown-it-emoji' import MarkdownItMention from './packs/markdown-it-mention'
- 疑問:なぜ
comments.vue
の中で、自分自身をCommentにimportしている?comments.vue
とcomment.vue
が別ファイルでした(この時点では気づかず、だいぶ後にになって気づく・・・)
created
created: function() { fetch(`/api/users/${this.currentUserId}.json`, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest', }, credentials: 'same-origin', redirect: 'manual' }) .then(response => { return response.json() }) .then(json => { for(var key in json){ this.$set(this.currentUser, key, json[key]) } }) .catch(error => { console.warn('Failed to parsing', error) }) fetch(`/api/comments.json?commentable_type=${this.commentableType}&commentable_id=${this.commentableId}`, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest', }, credentials: 'same-origin', redirect: 'manual' }) .then(response => { return response.json() }) .then(json => { json.forEach(c => { this.comments.push(c) }); }) .catch(error => { console.warn('Failed to parsing', error) }) },
fetch
- MDN/Fetch API
- request, responseするためのAPI
- MDN/Fetch を使う
従来、このような機能は XMLHttpRequest を使用して実現されてきました。 Fetch はそれのより良い代替となるもので、サービスワーカーのような他の技術から簡単に利用することができます。 Fetch は CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義する場所でもあります。
- つまり、XMLHttpRequestとかAJaxは違う?🤔
- fetch() から返される Promise は レスポンスが HTTP 404 や 500 を返して HTTP エラーステータスの場合でも拒否されません。代わりに (ok ステータスが false にセットされて) 正常に解決し、拒否されるのはネットワークのエラーや、何かがリクエストの完了を妨げた場合のみです。
- MDN/Fetch API
then
- 初めてPromiseの実装コードを見た(MDNで軽く読んだことしかなかった)
- 前から順番に流れていくので便利
- Promiseを使う
/api/users/${this.currentUserId}.json
から情報を取得している。/api/users/:id
は名前の通り、api
- credentials: 'same-origin'とは?
- Request.credentials
same-origin:URL が呼び出し元のスクリプトと同一オリジンだった場合のみ、クッキーを送信する。
- 流れ
currentUserId
でユーザー情報取得commentable_id
、commentable_type
でコメントの親クラスについているコメントの情報を取得している
createdで呼び出しているAPIで受信する内容
http://localhost:3000/api/users/459775584.json
の結果
{ id: 459775584, login_name: "komagata", url: "http://localhost:3000/users/459775584", role: "admin", avatar_url: "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRibEJ0UlhsV2VVSkdObXBRUjBRemFsRjZaWE5VVjBaakJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkRhVzVzYVc1bE95Qm1hV3hsYm1GdFpUMGlhMjl0WVdkaGRHRXVhbkJuSWpzZ1ptbHNaVzVoYldVcVBWVlVSaTA0SnlkcmIyMWhaMkYwWVM1cWNHY0dPd1pHT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVSIsImV4cCI6IjIwMTktMTAtMzFUMTM6Mjk6NTQuNzc2WiIsInB1ciI6ImJsb2Jfa2V5In19--def46e9c9ea6a11afef8c3c0234562fbbf2d54f1/komagata.jpg?content_type=image%2Fpng&disposition=inline%3B+filename%3D%22komagata.jpg%22%3B+filename%2A%3DUTF-8%27%27komagata.jpg" }
http://localhost:3000/api/comments.json?commentable_type=Report&commentable_id=1017786020
の結果- コメントだけじゃなくて、reactionのデータも持っていた!発見
[ { id: 1064126206, description: "te", created_at: "2019-10-31T15:25:28.271+09:00", updated_at: "2019-10-31T15:25:28.271+09:00", commentable_type: "Report", commentable_id: 1017786020, commentable: { created_at: "2019-10-31T14:56:12.076+09:00" }, user: { id: 459775584, login_name: "komagata", url: "http://localhost:3000/users/459775584", role: "admin", avatar_url: "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRibEJ0UlhsV2VVSkdObXBRUjBRemFsRjZaWE5VVjBaakJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkRhVzVzYVc1bE95Qm1hV3hsYm1GdFpUMGlhMjl0WVdkaGRHRXVhbkJuSWpzZ1ptbHNaVzVoYldVcVBWVlVSaTA0SnlkcmIyMWhaMkYwWVM1cWNHY0dPd1pHT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVSIsImV4cCI6IjIwMTktMTAtMzFUMTM6MzM6MjAuODc0WiIsInB1ciI6ImJsb2Jfa2V5In19--894cdfc20c4bedc6ba2c9f3276eef453b212bccb/komagata.jpg?content_type=image%2Fpng&disposition=inline%3B+filename%3D%22komagata.jpg%22%3B+filename%2A%3DUTF-8%27%27komagata.jpg" }, reaction: [ ], reaction_count: [ { kind: "thumbsup", value: "👍", count: 0, login_names: [ ] }, // 略 { id: 1064126207, description: "a", created_at: "2019-10-31T22:27:13.414+09:00", updated_at: "2019-10-31T22:27:13.414+09:00", commentable_type: "Report", commentable_id: 1017786020, commentable: { created_at: "2019-10-31T14:56:12.076+09:00" }, user: { id: 459775584, login_name: "komagata", url: "http://localhost:3000/users/459775584", role: "admin", avatar_url: "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9JYTJWNVNTSWRibEJ0UlhsV2VVSkdObXBRUjBRemFsRjZaWE5VVjBaakJqb0dSVlE2RUdScGMzQnZjMmwwYVc5dVNTSkRhVzVzYVc1bE95Qm1hV3hsYm1GdFpUMGlhMjl0WVdkaGRHRXVhbkJuSWpzZ1ptbHNaVzVoYldVcVBWVlVSaTA0SnlkcmIyMWhaMkYwWVM1cWNHY0dPd1pHT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVSIsImV4cCI6IjIwMTktMTAtMzFUMTM6MzM6MjAuODgyWiIsInB1ciI6ImJsb2Jfa2V5In19--a45376882bdb1078327ba7d83abfc021f2ada912/komagata.jpg?content_type=image%2Fpng&disposition=inline%3B+filename%3D%22komagata.jpg%22%3B+filename%2A%3DUTF-8%27%27komagata.jpg" }, // 略
createdで呼び出しているAPIの送信コード
APIの構成の確認
- APIはjbuilderで作成されている
- Rails6.0からはRailsを新規作成したら付いてくるので馴染みがある
- Action Viewの概要/jbuilder
- コメント機能に関係がありそうなAPIの構成
/app/controllers/api/users_controller.rb
# frozen_string_literal: true class API::UsersController < API::BaseController def index users = User.select(:login_name, :first_name, :last_name) .order(updated_at: :desc) .as_json(except: :id) render json: users end def show @user = User.find(params[:id]) end end
- index, showが来ると、それぞれ
_users.json.jbuilder
,show.json.jbuilder
にリクエストを飛ばしている- 疑問:なぜindexに飛ばさない?
render json: XXX
- jsonでrenderに渡す
/api/views/api/users/_user.json.jbuilder
json.(user, :id, :login_name, :url, :role) json.avatar_url user.avatar_url
- APIが簡単に書けるjbuilder素晴らしい
- rails/jbuilderでStarを押しました✌️
- amatsuda/jbも良いという話を聞くので、今度触ってみたい
- メモ:
avatar
のように、画像の場合はurl
だけを渡す
/api/views/api/users/show.json.jbuilder
json.partial! "api/users/user", user: @user
- 疑問:
json.partial!
とは?- パーシャルが展開できる
- この場合、user毎に
/api/views/api/users/_user.json.jbuilder
を呼び出している
- 疑問:コントローラーの
users
が@user
で呼び出せているのはなぜ?どこで展開している?
You can use partials as well. The following will render the file views/comments/_comments.json.jbuilder, and set a local variable comments with all this message's comments, which you can use inside the partial.
ruby json.partial! 'comments/comments', comments: @message.comments
mounted
- Vue.js/mounted
- Vue.js/ライフサイクルダイアグラム
- mountedはVue.jsがエレメントを置き換えるにあたり、エレメントを表示するまでの最後に行う処理が書ける(ということだと思います)
- 疑問:
textareaAutoSize()
謎のメソッドが呼ばれている- importされている
markdown-textarea.vue
が怪しいimport 'textarea-autosize/dist/jquery.textarea_autosize.min'
5行目でそれらしいjQueryを呼んでいた
- importされている
methods
methods: { token () { const meta = document.querySelector('meta[name="csrf-token"]') return meta ? meta.getAttribute('content') : '' }, isActive: function(tab) { return this.tab == tab }, changeActiveTab: function(tab) { this.tab = tab }, createComment: function(event) { if (this.description.length < 1) { return null } let params = { 'comment': { 'description': this.description }, 'commentable_type': this.commentableType, 'commentable_id': this.commentableId } fetch(`/api/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8', 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': this.token() }, credentials: 'same-origin', redirect: 'manual', body: JSON.stringify(params) }) .then(response => { return response.json() }) .then(json=> { this.comments.push(json); this.description = ''; }) .catch(error => { console.warn('Failed to parsing', error) }) }, deleteComment: function(id) { fetch(`/api/comments/${id}.json`, { method: 'DELETE', headers: { 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': this.token() }, credentials: 'same-origin', redirect: 'manual' }) .then(response => { this.comments.forEach((comment, i) => { if (comment.id == id) { this.comments.splice(i, 1); } }); }) .catch(error => { console.warn('Failed to parsing', error) }) } },
- Vueインスタンスのメソッド
createComment
createComment: function(event) { if (this.description.length < 1) { return null } let params = { 'comment': { 'description': this.description }, 'commentable_type': this.commentableType, 'commentable_id': this.commentableId } fetch(`/api/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8', 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': this.token() }, credentials: 'same-origin', redirect: 'manual', body: JSON.stringify(params) }) .then(response => { return response.json() }) .then(json=> { this.comments.push(json); this.description = ''; }) .catch(error => { console.warn('Failed to parsing', error) }) },
- プログラムの内容
null
なら何もしない- paramsでデータ受け取り
- fetchで
comments
のレスポンス取得 - レスポンスjson化
- commentsにデータ保管
- エラーが発生したらキャッチし、consoleに出力
computed
computed: { markdownDescription: function() { const md = new MarkdownIt({ html: true, breaks: true, linkify: true, langPrefix: 'language-' }); md.use(MarkdownItEmoji).use(MarkdownItMention) return md.render(this.description); }, validation: function() { return this.description.length > 0 } }
- Vue.js/computed
- Vueインスタンスの算出プロパティ
- 型
{ [key: string]: Function | { get: Function, set: Function } }
markdownDescription
- 疑問:markdownが使えるようにしていそうだけど、どうやって?
- 絵文字を使えるようにしている
templete
<template lang="pug"> .thread-comments-container h2.thread-comments-container__title コメント .thread-comments comment(v-for="(comment, index) in comments" :key="comment.id" :comment="comment", :currentUser="currentUser", @delete="deleteComment") .thread-comment-form .thread-comment__author img.thread-comment__author-icon(:src="currentUser.avatar_url") .thread-comment-form__form.a-card .thread-comment-form__tabs.js-tabs .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('comment')}" @click="changeActiveTab('comment')") | コメント .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('preview')}" @click="changeActiveTab('preview')") | プレビュー .thread-comment-form__markdown-parent.js-markdown-parent .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('comment')}") markdown-textarea(v-model="description" id="js-new-comment" class="a-text-input js-warning-form thread-comment-form__textarea js-markdown" name="comment[description]") .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('preview')}") .js-preview.is-long-text.thread-comment-form__preview(v-html="markdownDescription") .thread-comment-form__actions .thread-comment-form__action button#js-shortcut-post-comment.a-button.is-lg.is-warning.is-block(@click="createComment" :disabled="!validation") | コメントする </template>
投稿されたコメントの表示
comment(v-for="(comment, index) in comments" :key="comment.id" :comment="comment", :currentUser="currentUser", @delete="deleteComment")
- 投稿されたコメントの表示は
comment()
内での処理が行なっています comments
自体のデータは、data: () => { comments: [] }
で定義され、created
のfetch
で/api/comments.json
からの返りを受け取ったものをthis.comments.push(c)
しています
- 実際の表示自体は
comment.vue
が行なっています
コメント新規投稿用フォーム
.thread-comment-form .thread-comment__author img.thread-comment__author-icon(:src="currentUser.avatar_url") .thread-comment-form__form.a-card .thread-comment-form__tabs.js-tabs .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('comment')}" @click="changeActiveTab('comment')") | コメント .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('preview')}" @click="changeActiveTab('preview')") | プレビュー .thread-comment-form__markdown-parent.js-markdown-parent .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('comment')}") markdown-textarea(v-model="description" id="js-new-comment" class="a-text-input js-warning-form thread-comment-form__textarea js-markdown" name="comment[description]") .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('preview')}") .js-preview.is-long-text.thread-comment-form__preview(v-html="markdownDescription") .thread-comment-form__actions .thread-comment-form__action button#js-shortcut-post-comment.a-button.is-lg.is-warning.is-block(@click="createComment" :disabled="!validation") | コメントする
.thread-comment-form__tab.js-tabs__tab
.thread-comment-form__tabs.js-tabs .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('comment')}" @click="changeActiveTab('comment')") | コメント .thread-comment-form__tab.js-tabs__tab(:class="{'is-active': isActive('preview')}" @click="changeActiveTab('preview')") | プレビュー
- 「コメント」と「プレビュー」の表示を制御しています
- アクティブな方に
is-active
を付与して表示を制御しているみたいです
- アクティブな方に
.thread-comment-form__markdown-parent.js-markdown-parent
.thread-comment-form__markdown-parent.js-markdown-parent .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('comment')}") markdown-textarea(v-model="description" id="js-new-comment" class="a-text-input js-warning-form thread-comment-form__textarea js-markdown" name="comment[description]") .thread-comment-form__markdown.js-tabs__content(:class="{'is-active': isActive('preview')}") .js-preview.is-long-text.thread-comment-form__preview(v-html="markdownDescription")
- 「コメント」「プレビュー」の表示を行なっています
- 両方ともデータは常に持っていて、アクティブな方に
is-active
をつけて、表示しているみたいです
.thread-comment-form__actions
.thread-comment-form__actions
.thread-comment-form__action
button#js-shortcut-post-comment.a-button.is-lg.is-warning.is-block(@click="createComment" :disabled="!validation")
| コメントする
- コメント投稿機能です
#js-shortcut-post-comment
- もしかしたら、
comment.vue
をimportしていたのはこのためかも?
- もしかしたら、
:disabled="!validation"
で空白だったら、computed
のvalidation: cunftion() {}
が呼び出されて、投稿ボタンがdisabled
される
computed: { // 略 validation: function() { return this.description.length > 0 } }
/app/javascript/comment.vue
import
import Reaction from './reaction.vue' import MarkdownTextarea from './markdown-textarea.vue' import MarkdownIt from 'markdown-it' import MarkdownItEmoji from 'markdown-it-emoji' import MarkdownItMention from './packs/markdown-it-mention' import Tribute from 'tributejs' import TextareaAutocomplteEmoji from 'classes/textarea-autocomplte-emoji' import TextareaAutocomplteMention from 'classes/textarea-autocomplte-mention' import moment from 'moment'
reaction.vue
とmarkdown-textarea.vue
はコメント機能への追加機能なので、今回は追わないことにします
props
props: ['comment', 'currentUser', 'availableEmojis'], components: { 'reaction': Reaction, 'markdown-textarea': MarkdownTextarea },
props
- コメント、ユーザー、絵文字を保持している
components
data
data: () => { return { description: '', editing: false, tab: 'comment' } },
templete
<template lang="pug"> .thread-comment .thread-comment__author a.thread-comment__author-link(:href="comment.user.url" itempro="url") img.thread-comment__author-icon(:src="comment.user.avatar_url" v-bind:class="userRole") .thread-comment__body.a-card(v-if="!editing") header.thread-comment__body-header h2.thread-comment__title a.thread-comment__title-link(:href="comment.user.url" itempro="url") | {{ comment.user.login_name }} time.thread-comment__created-at(:datetime="commentableCreatedAt" pubdate="pubdate") | {{ updatedAt }} .thread-comment__description.js-target-blank.is-long-text(v-html="markdownDescription") reaction( v-bind:reactionable="comment", v-bind:currentUser="currentUser") footer.card-footer(v-if="comment.user.id == currentUser.id") .card-footer-actions ul.card-footer-actions__items li.card-footer-actions__item button.card-footer-actions__action.a-button.is-md.is-primary.is-block(@click="editComment") i.fas.fa-pen | 編集 li.card-footer-actions__item button.card-footer-actions__action.a-button.is-md.is-danger.is-block(@click="deleteComment") i.fas.fa-trash-alt | 削除 .thread-comment-form__form.a-card(v-show="editing") .thread-comment-form__tabs.js-tabs .thread-comment-form__tab.js-tabs__tab(v-bind:class="{'is-active': isActive('comment')}" @click="changeActiveTab('comment')") | コメント .thread-comment-form__tab.js-tabs__tab(v-bind:class="{'is-active': isActive('preview')}" @click="changeActiveTab('preview')") | プレビュー .thread-comment-form__markdown-parent.js-markdown-parent .thread-comment-form__markdown.js-tabs__content(v-bind:class="{'is-active': isActive('comment')}") markdown-textarea(v-model="description" :class="classCommentId" class="a-text-input js-warning-form thread-comment-form__textarea js-comment-markdown" name="comment[description]") .thread-comment-form__markdown.js-tabs__content(v-bind:class="{'is-active': isActive('preview')}") .js-preview.is-long-text.thread-comment-form__preview(v-html="markdownDescription") .thread-comment-form__actions .thread-comment-form__action button.a-button.is-md.is-warning.is-block(@click="updateComment" v-bind:disabled="!validation") | 保存する .thread-comment-form__action button.a-button.is-md.is-secondary.is-block(@click="cancel") | キャンセル </template>
.thread-comment__author
.thread-comment__author a.thread-comment__author-link(:href="comment.user.url" itempro="url") img.thread-comment__author-icon(:src="comment.user.avatar_url" v-bind:class="userRole")
- 投稿者アイコン(avatar)の表示
.thread-comment__body.a-card(v-if="!editing")
comments.vue
とほぼ変わらず、コメント表示機能
.thread-comment__body.a-card(v-if="!editing") header.thread-comment__body-header h2.thread-comment__title a.thread-comment__title-link(:href="comment.user.url" itempro="url") | {{ comment.user.login_name }} time.thread-comment__created-at(:datetime="commentableCreatedAt" pubdate="pubdate") | {{ updatedAt }} .thread-comment__description.js-target-blank.is-long-text(v-html="markdownDescription") reaction( v-bind:reactionable="comment", v-bind:currentUser="currentUser") footer.card-footer(v-if="comment.user.id == currentUser.id") .card-footer-actions ul.card-footer-actions__items li.card-footer-actions__item button.card-footer-actions__action.a-button.is-md.is-primary.is-block(@click="editComment") i.fas.fa-pen | 編集 li.card-footer-actions__item button.card-footer-actions__action.a-button.is-md.is-danger.is-block(@click="deleteComment") i.fas.fa-trash-alt | 削除
v-bind
とは?- Vue.js/v-bind
1つ以上の属性またはコンポーネントのプロパティと式を動的に束縛します。
- Vue.jsで属性かv-bindかの応用
- 公式の文章では正直意味がわからなかったが、
templete
で変数や式を使うことで、動的な文字列を作成できるということらしい
- 公式の文章では正直意味がわからなかったが、
- Vue.js/v-bind
.thread-comment-form__form.a-card(v-show="editing")
comments.vue
とほぼ変わらず、コメント投稿機能
li.card-footer-actions__item
- 「編集ボタン」、「削除ボタン」を提供しています
- ボタンをクリックすると、
editComment
,deleteComment
が呼び出されます
methods
updateComment
updateComment: function() { if (this.description.length < 1) { return null } let params = { 'comment': { 'description': this.description } } fetch(`/api/comments/${this.comment.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json; charset=utf-8', 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': this.token() }, credentials: 'same-origin', redirect: 'manual', body: JSON.stringify(params) }) .then(response => { this.editing = false; }) .catch(error => { console.warn('Failed to parsing', error) }) },
null
の時は何もしないdescription
をcomment
の内容として保管
その他
- あまり変わらなさそうなので、軽くだけ目を通した
おわりに
思ったこと
結構読むのに時間がかかりました。
途中、コードを書き始めながら実装しなかったので、issue消化がこの記事を投稿してからになります・・・(これは明確な失敗だ・・・)
アウトプットはしていきたいですが、進捗も出したいので、今後も工夫して上手く両立させていきたいです。
アジャイルソフトウェア開発とスクラムについてまとめた
まえがき
今週からフィヨルドブートキャンプのスクラムチームに参加します。
そのため、スクラムチームに参加する前に、「アジャイルソフトウェア開発とは?」「スクラムとは?」という概念について、知っていることを調べ補足しつつまとめたので公開します。
アジャイルソフトウェア開発
- ソフトウェア開発手法の一種
- 通称アジャイル
- アジャイルソフトウェア開発はソフトウェア開発手法群の総称であり、スクラム、XP開発など複数の開発手法が属する。そのため、スクラムだけがアジャイルではない
- ウォーターフォール開発手法とよく比較される
- ウォーターフォール開発手法が「計画、設計〜テスト、リリース」までのフェーズを1段階ずつこなしていく手法。動くソフトウェアは一番最後にならないと見れない
- 動くソフトウェアとは、フィーチャ(ユーザー側の視点で記述された、ユーザーにとってのソフトウェアの価値を表現したもの)を提供するソフトウェア。1レイヤー単位の実装(モジュール単位など)ではなく、1部分だけでもいいので、全レイヤーを通したソフトウェアを作成すること
- アジャイルは1イテレーション(開発単位)ごとに動くソフトウェアをインクリメント(成果物)として出していく
- アジャイルは1イテレーションごとにインクリメントを出すことで、適宜計画や方針を検討できる
- アジャイルはプロダクトオーナーと開発チームとの情報非対称性を減らす
- アジャイルはチーム内での情報非対称性を減少させる
価値観と原則
- アジャイルの考え方は価値観と原則により規定されている
- アジャイルはアジャイルのチーム全員が価値観と原則を共有し実践することで、品質の高いソフトウェア開発が行える
- ここでいう品質とは、ユーザーに対して価値を提供できるソフトウェア開発のことを指し、絶対的な価値観ではない
4つの価値(左より右に価値を置く。※左に価値がないということではない)
- 「プロセスやツール」よりも「個人と対話」
- アジャイルでは、プロセスやツールにのったコミュニケーションではなく、個人を一個人として尊敬し尊重し対話することに重きが置かれる。また、対面でのコミュニケーションによる相互理解で、より良いチームが作られる
- 「包括的なドキュメント」より「動くソフトウェア」
- 「契約交渉」より「顧客との協調」
- 「計画に従うこと」よりも「変化への対応」
- 計画していた当初と前提条件が変化することもある。アジャイルでは、変化に合わせて顧客にフィーチャを提供していく
12の原則
- 顧客の満足を求め続ける
- 要求の本質を見抜き、変更を前向きに
- 成果物を2,3週間で、リリースし続ける
- 全員で共通の目標に向かおう
- 人の意欲は信頼から
- 顧客も開発チームも直接対話で
- 進捗も品質も現物で
- 一定のペースでプロジェクトにリズムを
- よい技術、よい設計、よい品質の追求
- 無駄=価値を生まない、を探してやめる
- よいモノはよいチームから
- 自分たちのやり方を毎週、調整する
スクラム
スクラムを支える3本柱
価値基準
- 確約
- 個人はスクラムチームのゴールの達成を確約しなければならない
- 勇気
- スクラムチームのメンバーは正しいことをする勇気を持ち、困難な問題に取り組まなければならない
- 集中
- 公開
- 尊敬
- スクラムチームのメンバーはお互いを能力のある独立した個人として尊敬しなければならない
スクラムチームの役割
- プロダクトオーナー
- バックログの管理に責任を持つ人
- スクラムマスター
- プロジェクトを円滑に進める責任を持つ人
- 開発チーム
- 動くソフトウェアを開発する人
- 1チームは10人以下が望ましい
- スクラムチーム
- スクラムを行う全員
スクラム開発の流れ
- プロダクトバックログからバックログを選び、スプリントバックログに入れる
スプリントバックログをもとにスプリント
プロダクトバックログの意味: プロダクトの機能を記述したもの。プロダクトオーナーが優先順位を変更する
- スプリントバックログの意味: スプリント期間中に行うタスクのリスト
スプリントの流れ
注意
- スプリント期間中タスクの追加はできない
スプリントの流れ
- スプリントプランニング
- スプリント期間中に何を行うか決める
- デイリースクラム
- 毎日1日の作業開始前に開発チームで行う活動
- 誰がどのスプリントバックログに着手するか、問題が発生していないかを15分で行う
- スプリント実施
- スプリントバックログを消化する
- スプリントレビュー
- スプリントで作成したインクリメントの検査、プロダクトバックログの適応を行う
- スプリントレトロスペクティブ
- チームの成長、プロセスの改善を目的に、振り返りを行う
- リファインメント(旧名称: グルーミング)
- 優先順位の見積もり、修正を行う
作業単位
ユーザーストーリー
- ユーザーにとって実現したいこと、価値のあること
ストーリーの書き方
- ユーザーストーリー
- DONEの定義(完了の定義)
- ストーリーポイント
タスク
- ユーザーストーリーを実現するために分解したもの
- タスクをこなすことでユーザーストーリーの実現に近くが、ユーザーストーリー全体を完了させなければユーザーにとって価値が生まれない
タスクの書き方
- タイトル
- 作業内容
- 割り込みかどうか
- 誰が担当するか
- ポイント
見積もり方法
見積もりは複数作らない。
プランニングポーカー
- やり方
- 参加者にフィボナッチ数列が書かれたカードを配布
- 基準となる数値を決めるため、簡単なタスクに1を割り当て、共通の基準とする
- タスクを一つ選び、仕様がわからない人がいれば、その場で説明
- 他のタスクは基準のポイントを基準に、一斉にカードを出す
- 最小値、最大値を出した人の意見に聞く
- 全員が納得できるまで続ける
- やり方
ポイント振りが難しい場合、スパイクする
- スパイクの意味: タスクを分解すること
参考
銀座Rails#12@DeNAに参加してきました!
TechRachoの@hachi8833さん、@morimorihogeさん
- TechRachoを書いたり、RAILS GUIDESを翻訳している方々
- いつも見ているサイトを書いている人がいらっしゃった。
- 事前アンケートの結果について(Rails,Rubyの使い方、使っている用途など)
- ※あとで掲載されるらしい銀座Rails#12@DeNA
- Rails 6.0
- 複数DBがgemの追加なしでできるようになった
- 話題のGem
Rails使いのNuxt.js @ssh_nofさん
プログラマーがコードを書きながら考えること @jnchitoさん
- プロを目指す人のためのRuby入門(通称:チェリー本)の著者。私ももちろん持っている。
- ライブコーディング(録画)での発表で、考えていることを字幕や補足を交えつつ説明してくださった。
- また、ライブコーディングを見るにあたって、「自分と同じところ」「自分と違うところ」などを探すようにアドバイスしてくださったりした。
- ライブコーディングで考えたこと
- 今回のプレゼンテーションで使用した動画などは後日何か下の形でアップロードを予定しているそうです。気になる。
# あとがき
参加中に次回のアナウンスがあったんですけど、もう既に13回目の予約が定員超えているなど人気が凄かったです。
実際に参加してみて、普段読んでいる本やサイトの著名など、情報の発信源とも言えるような方々が実際目の前で話をしてくれたり、質問に答えてくださったりするので、大変ありがたい機会だなと感じました。
また、そういったこともあり普段仕事でRailsを書いている方々と直接交流でき、今回であれば「どういう仕事・業界があるか」「新人の育成方法」「ペアプロの効果」「おすすめのサイト・本・イベント」などの話が出来て良かったです。
Shinjuku.rb #74 Extreme Fish Bowlに参加してきました!
Shinjuku.rbに参加
Shinjuku.rb #74 Extreme Fish Bowlに参加してきました。
やったこと
- 自己紹介
- テーマ説明
- 今回は「ブラックジャックを1からプログラミング」する
- Extreme Fish Bowl
- モブプロ形式でペアプロをする
- 時間は5分交代
- 交代方法
- 初めは指名制
- ナビゲーターがドライバーに移動
- ドライバーが次のナビゲーターを指名
- 備考
- ペアプロ
- ナビゲーター(指示者)とドライバー(コードを書く人)で別れて
- モブプロ
- プロジェクターなどに写しながらプログラミングをすること
- 周りの人はプログラムについて意見を雑談形式で述べる
- 登壇者は周りの意見を踏まえた上で考えながらコードを書く
- ペアプロ
- 感想戦
- Extreme Fish Bowlのコミットログを見ながら、雑談する
- 振り返り
- KPTで振り返りつつ、次回のテーマ決め
- 次回はあっち向いてホイになりました!
- KPTで振り返りつつ、次回のテーマ決め
- 参考
- 当日の資料などのあるリポジトリ
あとがき
長年プログラムを書いてきた方々と、一緒に考えながらプログラムが書けて大変貴重な時間でした。
私は人とリアルタイムで一緒にプログラムを書いた経験がほぼ皆無だったので、人前でコードを書く緊張感を感じつつ、時間を分単位で気にして書くのが大変刺激的で楽しかったです。
また、二次会ということで、Shinjuku.rbのメンバーでRepro株式会社様のボードゲームをお借りして楽しめたのも良かったです。
コードネーム 日本語版というゲームで、プログラミングでいうところの抽象クラスを作るゲームなので、エンジニアにはぴったりな遊びだなと思いました。
ただ、人数は6人以上いた方が楽しめそうなので、その点だけ気をつけておく必要があると思います。
Extreme Fish Bowl初回参加時、事前にしておきたかったこと
- 事前に作成するプログラムのテーマ(ゲーム)が提示されていたので、ルールを詳しく把握しておく
- ローカルルールなどあり限られた時間内で作るとなると、素早い判断が求められるため
- 変数名、関数名などを事前に想定しておく
- 名付け慣れている人なら別かもしれないが、人前で緊張する&時間が限られており中で、作っていくのは大変。特にお酒も可な勉強会なので・・・
「プロになるためのRuby入門」を読みながら「TDDで改札機プログラムを実装」してみた
- test-unit実践
- まずは要件を文章化
- 要件を満たすシナリオの作成
- ディレクトリ準備
- クラスオブジェクトの作成
- シナリオ1の実装
- テストメソッドに処理の順番を仮置きする
- 実装したいコードの確認
- シナリオ1のタスク細分化
- Task1. Gate.new(:ikebukuro)できる, 2. Gate.new(:sinjyuku)できる
- Task3. Ticket.new(120)できる
- Task4. ikebukuro.enter(ticket)できる
- Task5. ticket.stamp(駅名)で乗車駅を保存
- Task6. ikebukuro.enter(ticket)した後、sinjyuku.exit(ticket) #=> falseになる
- Task7. ticket.stamped_atで乗車駅を参照できるように
- Task8. Gateのcalc_fireで生産できるかテスト(あとでプライベート化するかもしれないがその前にテスト)
- シナリオ2
- 疑問点の検討(自問自答)
- 参考にした本について
- あとがき
test-unit実践
今回は昨日学んだテスト駆動開発(以下、TDD)について、test-unitを使いつつ実装してみます。 内容は「プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)」に書いてある改札機のプログラムです。
単にコピペしても勉強にならないと思ったので、なるべく本を読まないようにして作ってみました。(とはいえわからないところ含め、変数名などはだいぶ似てしまっている)
まずは要件を文章化
# 改札機プログラム ## 作りたいもの 改札機のプログラム - チケットをお金で買うことができる - 改札機から入ることができる - 料金が正しければ、降りた駅で改札機から出れる - 料金が間違っていれば、改札機から出れない ## 要件 - 山手線 - 駅 - 池袋 - 新宿 - 渋谷 - 値段 - 120yen: 池袋 〜 新宿 - 120yen: 新宿 〜 渋谷 - 200yen: 池袋 〜 渋谷 ## 動作する仕様 `` ikebukuro = Gate.new(:ikebukuro) sibuya = Gate.new(:sibuya) ticket = Ticket.new(120) ikebukuro.enter(ticket) sibuya.exit(ticket) #=> false ticket = Ticket.new(200) ikebukuro.enter(ticket) sibuya.exit(ticket) #=> true ``
要件を満たすシナリオの作成
シナリオ1
- 120円の切符を購入
- 池袋で入場、新宿で出場
- 出場できる
シナリオ2
- 120円切符を購入
- 池袋で入場、渋谷で出場
- 出場できない
シナリオ3
- 200円の切符を購入
- 池袋で入場、渋谷で出場
- 出場できる
シナリオ4
- 120円の切符を購入
- 新宿で入場、渋谷で出場
- 出場できる
ディレクトリ準備
ruby_ticket_machine - lib - gate.rb - test - gate_test.rb
クラスオブジェクトの作成
Redにする(テストから書き始める)
クラスオブジェクト作成の確認から
# frozen_string_literal: true require "test/unit" require "./lib/gate" class GateTest < Test::Unit::TestCase def test_gate assert Gate.new end end
Greenにする
# frozen_string_literal: true class Gate end
Refactor
今回は特に必要がなさそうなので終了
シナリオ1の実装
テストメソッドに処理の順番を仮置きする
def test_gate # 前準備 # 実行 # 検証 # 後片付け(状況により必要) end
実装したいコードの確認
ikebukuro = Gate.new(:ikebukuro) sinjyuku = Gate.new(:sinjyuku) ticket = Ticket.new(120) ikebukuro.enter(ticket) sinjyuku.exit(ticket) #=> true
シナリオ1のタスク細分化
Gate.new(:ikebukuro)
できるGate.new(:sinjyuku)
できるTicket.new(120)
できるikebukuro.enter(ticket)
できるticket.stamp(駅名)
で乗車駅を保存ikebukuro.enter(ticket)
した後、sinjyuku.exit(ticket) #=> false
になるticket.stamped_at
で乗車駅を参照できるようにGate
のcalc_fire
で生産できるかテスト(あとでプライベート化するかもしれないがその前にテスト)
Task1. Gate.new(:ikebukuro)
できる, 2. Gate.new(:sinjyuku)
できる
過去のコードで対応できているので省略
Task3. Ticket.new(120)
できる
Red
# ./test/ticket_test.rb # frozen_string_literal: true require "test/unit" require "./lib/ticket" class TicketTest < Test::Unit::TestCase def test_new assert Ticket.new(120) end end
Green
# ./lib/ticket.rb # frozen_string_literal: true class Ticket def initialize(fare) @fare = fare end end
Refactor
なし
Task4. ikebukuro.enter(ticket)
できる
Red
# ./test/gate_test.rb # 省略 class GateTest < Test::Unit::TestCase # 中略 def test_enter ikebukuro = Gate.new(:ikebukuro) ticket = Ticket.new(120) ikebukuro.enter(ticket) end # 省略
Green
# ./lib/gate.rb # frozen_string_literal: true class Gate # 中略 def enter(ticket) true end end
Refactor
なし
Task5. ticket.stamp(駅名)
で乗車駅を保存
Red
# ./test/ticket_test.rb # 中略 class TicketTest < Test::Unit::TestCase # 中略 def test_stamp ticket = Ticket.new(120) assert ticket.stamp(:ikebukuro) end
Green
# ./lib/ticket.rb # 中略 class Ticket # 中略 def stamp(station) @boarding_station = station end end
Refactor
なし
Task6. ikebukuro.enter(ticket)
した後、sinjyuku.exit(ticket) #=> false
になる
Red
# ./test/gate_test.rb # 中略 class GateTest < Test::Unit::TestCase # 中略 def test_exit # 前準備 ikebukuro = Gate.new(:ikebukuro) sinjyuku = Gate.new(:sinjyuku) # 実行 ticket = Ticket.new(120) ikebukuro.enter(ticket) # 検証 assert sinjyuku.exit(ticket) # 後片付け(状況により必要) end end
Green
# ./lib/gate.rb # 中略 class Gate # 中略 def exit(ticket) true end end
Refactor
なし
Task7. ticket.stamped_at
で乗車駅を参照できるように
Red
# ./test/ticket_test.rb # 中略 class TicketTest < Test::Unit::TestCase # 中略 def test_stamped_at ticket = Ticket.new(120) ticket.stamp(:ikebukuro) assert_equal(:ikebukuro, ticket.stamped_at) end end
Green
# ./lib/ticket.rb # 中略 class Ticket # 中略 def stamped_at @boarding_station end end
Refactor
なし
Task8. Gate
のcalc_fire
で生産できるかテスト(あとでプライベート化するかもしれないがその前にテスト)
Red
あとでプライベート化するかもしれないがその前にGate.calc_fire
のテスト
# ./test/gate_test.rb # 中略 class GateTest < Test::Unit::TestCase # 中略 def test_calc_fire # 前準備 ikebukuro = Gate.new(:ikebukuro) sinjyuku = Gate.new(:sinjyuku) # 実行 ticket = Ticket.new(120) ikebukuro.enter(ticket) # 検証 assert sinjyuku.calc_fire(:sinjyuku) end end
Green
※追加行は+
、削除行は-
を先頭に付与しています
# frozen_string_literal: true class Gate STATIONS = [:ikebukuro, :sinjyuku, :sibuya] FARES = [120, 200] # 中略 def exit(ticket) - true + calc_fire(ticket.stamped_at) end def calc_fire(exit_station) distance = (STATIONS.index(@station) - STATIONS.index(exit_station)).abs FARES[distance - 1] end end
Refactor
Gate.exit
が成否ではなく、計算結果を返しているようになっているので修正
# ./lib/gate.rb # 中略 class Gate # 中略 def exit(ticket) pay_of(ticket) end private def pay_of(ticket) 0 <= (ticket.fare - calc_fire(ticket.stamped_at)) ? true : false end end
# ./lib/ticket.rb # 中略 class Ticket attr_reader :fare # 中略 end
シナリオ2
# ./test/gate_test.rb # 中略 class GateTest < Test::Unit::TestCase # 中略 def test_exit_scenario_2 # 前準備 ikebukuro = Gate.new(:ikebukuro) sibuya = Gate.new(:sibuya) # 実行 ticket = Ticket.new(120) ikebukuro.enter(ticket) # 検証 assert_equal(false, sibuya.exit(ticket)) # 後片付け(状況により必要) end def test_exit_scenario_3 # 前準備 ikebukuro = Gate.new(:ikebukuro) sibuya = Gate.new(:sibuya) # 実行 ticket = Ticket.new(200) ikebukuro.enter(ticket) # 検証 assert sibuya.exit(ticket) # 後片付け(状況により必要) end def test_exit_scenario_4 # 前準備 sinjyuku = Gate.new(:sinjyuku) sibuya = Gate.new(:sibuya) # 実行 ticket = Ticket.new(120) sinjyuku.enter(ticket) # 検証 assert sibuya.exit(ticket) # 後片付け(状況により必要) end end
疑問点の検討(自問自答)
- 他のクラスをテストする必要があったらどうすればいい?
- 例
- シナリオ1でgateクラスのtestをしている際、tickeクラスの話が登場してきた
- しょうがない時もある
- どういう場合はどっちのクラスに書いたほうがいいなどルールはある?
- シナリオ1でgateクラスのtestをしている際、tickeクラスの話が登場してきた
- 例
参考にした本について
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)
めっちゃオススメです!
Ruby初学者の方にオススメなので、本屋さんなどでぜひ手にとってみてはいかがでしょうか?
著者の方について、ブログなどにもたくさん情報が載っているので貼っておきます。
give IT a try - 伊藤淳一 (id:JunichiIto)
あとがき
やり方が悪かったのか、正直「TDDのサイクルが回っている実感」はありませんでした。
もう少しテストの粒度を大きくした方がいいのか(今回は初めてなのであえて小さくしましたが)、それともRefactorできるところがあったのか。
テスト駆動開発について書かれた本ではないので、そういった本に書かれているプログラムを作ってみたらまた違ったのかもしれません。
明日以降はRailsのテストを書く予定なので、そこでまた検討してみたいと思います。
テスト駆動開発とは
本文について
昨日テスト駆動開発について学んだので、その内容をまとめてみました。
わからないところもあるので、その点については正直に「わからない旨」と記載しております。
「テスト駆動開発」に入る前に、知っておいた方が良い「テスト」について書き、その後に「テスト駆動開発」について書いております。
誤字脱字ご指摘など連絡先
テストとは
1. テストの最小単位
- 不安
- 正しく動かないことに対する不安の解消
2. 注意事項
- テストの状態
- Greenにするか消すかの二択
- 放置してはいけない
- Greenにするか消すかの二択
- テストのメンテナンスコスト
- プロジェクト後半に発生する
3. 資産価値
- 大きいテストの方が価値がある
- 小さいテストは大きいテストをGreenにするためにある
- 大きいテストの価値=小さいテストを積み上げていったもの
4. 分類
- 目的別に分類されるテスト
- 領域別の分類(TDD)
- 「Developer Test」「Customer Test」「QA Test」
- 重複はない
5. テストという言葉の持つ障害
- 各々がテストという単語に対して、それぞれの立場で別の認識があるため、目的を明確にしていないと方向性にズレが出やすい
- プロジェクトでテストという言葉は再定義しなければならない
6. テストの書き方
- 2つの方針
- 重複はあっても良い
- テストコードはその部分だけ見ればある程度何をやってるかわかるコード,重複があってもいいから何をやってるかわかるノッペリとした書かれ方がいい
- 重複はない方が良い
- テストコードもコードはコード,テストコードにもプロダクトコードと同様にDRY原則が満たされなければならない
- 重複はあっても良い
- 重複があること
- メリット
- テストだけでやってることがわからないと、どこを探したら良いかわからないと大変
- デメリット
- 何か一つ修正したタイミングで、一気にRedが出ることがある
- 修正にも時間がかかる
- 何か一つ修正したタイミングで、一気にRedが出ることがある
- メリット
テスト駆動開発とは
1. 背景
- 歴史
- 用途
- 支える環境
- 軽快なテスト
- 簡潔なテストコードでテストが実装・実行できる
- 明快にテスト結果をみれる
- 製品コードと開発環境の切り替えが容易
2. 概要
- テストファーストな開発手法
- テストから先に書く
3. 目的
- すばやいフィードバックの確保
- 設計改善
- ユニットテストの確保
4. 目標(ゴール)
- ゴール
- 動作するきれいなコード
- 「動作する」「きれいなコード」
- 道は2つある
- 「きれい」にしてから「動作する」
- 伝統的なソフトウェア開発手法なこれを採用してきた
- きれいな設計を作ってから実装する
- 作り始めてから設計が複雑であるなど気づいたりする
- 作ってみたら遅くて使い物にならないなどあったりする
- 「動作する」にしてから「きれい」にする
- TDDが採用している手法
- 現在は予測可能性が低いので、「きれいな設計」を作ってからだと「動かしてみてからわからないこと」についていけない
- できるできないではなく、正しく見ていかないといけない
- 「きれい」にしてから「動作する」
- 道は2つある
5. テスト駆動開発は「恐れ」を突破するための技術
- テストの罠
- 堕落
- 動いたからよしとしたい感情がある
- 焦り
- 他にも作らなきゃいけないものがあるから後回しになる
- 恐れ
- せっかく動くところまで来たのに、綺麗にするためにコードを書いたら動かなくならなくなるので、コードに手を入れたくない
- 「動くコードに触れるな」みたいな言葉はここに由来する
- 堕落
- テスト駆動開発は「テストが安心を担保してくれる」
6. 注意点
- TDDのテストは品質を担保するわけではない
- 結果的に品質は高まるが、目的ではない
- テストのポイント
- 特定の条件下で検証する
- 本来はどうあるべきか?
- 実際にどうなっているか?
- リファクタリング
- privateテストのテストは行わない
7. メリット・デメリット
メリット
デメリット
- まだ不明
8. 構成
9. TDDでのテストの分類
- 開発促進・設計行為
- Developer Test
- 目的
- 開発者が開発者のために行うテスト
- 進捗管理・機能要件
- Customer Test
- 目的
- お客様から見て機能がどれくらいできあがっているか示す
- 品質保証・非機能要件
- QA Test
- 目的
- ソフトウェアの信頼性をあげるテスト
10. サイクル
用語の説明
- RED
- どう動いて欲しいかという(失敗する)テストを書く
- GREEN
- テストを成功させる最低限のコードを書く
- REFACTOR
- コードをリファクタリングしてきれいにする
- RED
実際のサイクル
- 次の目標を考える
- その目標のテストを書く
- そのテストを実行して失敗させる(Red)
- 目的のコードを書く
- テストを成功させる(Green)
- テストが通るまでリファクタリングを行う(Refactor)
- 繰り返す
- アンチパターン(起こりがちな失敗)
11. リファクタリング
12. 実際のやり方
- まずは実装を箇条書き
- 優先順位を決める
- 次にテストを書こうとする
- テストの区切りを考えるのは難しい
- どこまでやるのか?プリントできるかなど考えると難しい
- 「明白な実装」といって、わざわざ細かく書く必要はない。
- 実装が見えているなら書いてしまう
- テストの区切りを考えるのは難しい
- テストコードから書く
- テストを書くには具体的に考えないといけない
- テストを書くと掘り下げの甘さに気づける
- 初めは重複しても良い
- 重複はリファクタリングで消す
- 重複数がいくつでアウトかは開発のルールに従う
- だいたい2か3
- 重複数がいくつでアウトかは開発のルールに従う
- 重複はリファクタリングで消す
- テストを書くには具体的に考えないといけない
- テストは予想通り落ちるのが大事
- そのためにはモックオブジェクト技法を使っても良い
- モックオブジェクト技法
- 偽物のオブジェクトをテストに使う技法
- モックオブジェクト
- テスト対象と協調動作するオブジェクトの偽物を使う
- 利点
- 開発前にテストができる
- テストのテストができる
- モックオブジェクト技法
- そのためにはモックオブジェクト技法を使っても良い
13. アンチパターン
- テスト熱中症
- 手段の目的化
- 「GUI」「データベース」のテストが難しい
- データベースのテスト
- テストを動かす度にデータベースの中身が変わってしまって、Greenなのにテスト実行中はRedになったりする
- テスト同士が暗黙の依存関係を持ってしまうことがある
- ツール探しが大事
- テストを動かす度にデータベースの中身が変わってしまって、Greenなのにテスト実行中はRedになったりする
- GUIのテスト
- 問題点
- 画面仕様は変わりやすいので資産価値が低い
- 複雑になりやすくテストしにくい
- ユーザビリティや画面のデザインはテストできないことも多々ある
- 問題点
14. How to
- テストを書き始められなかったら
- ゴール(検証)から書く
- テストコードに慣れないうちや、何をテストしていいかわからなければ
- ゴール(検証)から書く
- テストメソッド
- テストメソッドの中身の構成
- 前準備
- 実行
- 検証
- 後片付け(状況により必要)
- テストメソッドの中身の構成
- テストコードの書き方
- 個別の具体的なコードしか書かないと「仕様が読み取れない」
- 名前から仕様が読み取れるようにしないといけない
- 案1:テスト名は長くてもいいから仕様を示す長い名前にする
- 案2:テストコードを入れ子にする
- 名前から仕様が読み取れるようにしないといけない
- 個別の具体的なコードしか書かないと「仕様が読み取れない」
- テストコードにバグがあったら
- 実装側にやらせる
- ミューテーションテスティング
- テストコードのテストを一番最初にしとめる
- 必ず成功する状態で実行する
- 最小テストの方向性を正したい
- 三角測量テスト
- 最小テストを書いた後で、テストの方向性を正すために他のテストを書くこと
- テスト毎にテストは1つ
- アンチパターン
- どこで落ちたかわからなくなる
- アンチパターン
- 三角測量テストは「対称性の破れ」があるので後で消すようにする
- 対称性の破れ
- 三角測量のテストは消す
- テストのテストは確認できた時点で消せるので
- 三角測量のテストは消す
- 三角測量テスト
- テストは消すのが難しい。消せるタイミングがあれば消す
- 公布済みインタフェースのリファクタリング
- 公布済み
- publishedインタフェース
- 他のチームや他の組織に使ってもらうためのインタフェース
- 手順
- 変更のアナウンス
- 旧インタフェースが呼ばれたら新インタフェースにそのまま呼び出しを行うようにする
- TDD
- 大きいプロジェクトになると適応しにくくなる
- 「先にクライアントとサーバの取り決めから始める」となるとpublishedインタフェースの中だけでしかTDDで自由に開発できなくなる
- 大きいプロジェクトになると適応しにくくなる
- 公布済み
参考
Sendagaya.rb #286に参加してきました
そろそろ地域.rb(地域毎のRubyコミュニティ)に参加したいと思っていたところ、フィヨルドミートアップで@machidaさんがSendagaya.rbをおすすめしていたので参加してきました
Sendagaya.rbでやっていること
※私が参加したのは今回初ですが、毎回やっている流れはほぼ同じそうです。今後参加される方にはご参考になるかと思います。
- 初めに自己紹介をする
- 名前・ニックネーム
- 今やっていること
- 今気になっていること
- 今日話をしたいこと
- その中からテーマを決め、30分程度毎に話し合ったり問題解決していく
Sendagaya.rb #286
今回は私を含め初参加の方が何名か居たので、初参加メンバーのテーマを優先させていただけました。
話をした内容は以下の通りです。個別のテーマについて、話したことを簡単に書いてみました。
- フォロー・フォロワー機能について相談
- viewに表示するmodelの件数についてどこに書くと嬉しいか
- 某APIを使ったシステムの設計方法について相談・検討
- プロジェクトの提案方法について
フォロー・フォロワー機能について相談
viewに表示するmodelの件数についてどこに書くと嬉しいか
- viewに関することはcontrollerに定数として書くことが多い
- showメソッドでしか使わない定数の場合は、showメソッドの真上に書いたりすることもある(とはいえ定数は一番上にまとめて書くことが多い)
- ただ数字を代入するような、マジックナンバーは作らないようにする
- 情報をまとめる時は、まとめた結果何が嬉しいのか(どんな価値があるのか)考えるのが大事
某APIを使ったシステムの設計方法について相談・検討
- 全体の構成について
- エラーハンドリングについて
- DBの設計について
- メモ帳やエディターで書いてみて、シュミレーションしてみる
- 頭だけで考えると抜け漏れが出てしまうかも
- 外部APIへの接続IPアドレスを固定したい場合、プロキシサーバーを使うとIPアドレスが固定できる
プロジェクトの提案方法について
- MVPを作る
- 顧客への提案方法について、まずは小さいところから作って見せて確認を取っていく
- プロジェクトの進行は1週間毎に成果を見せれるように作ることで、顧客と随時方針を修正しながら作り込める(顧客の仕様がまとまりきってないこともありうるので)
- リーンスタートアップが参考になる
- 良い機能はあるけど、必要だけど動かない機能があるというのは困る
- 一番複雑な例を聞くことが大事。最初に一番複雑な例を知っておきたい
- 何より動くことが大事。動くということはある程度設計が保証されているという証でもある
あとがき
分からないことや悩んでることについて一緒に考えてくれるコミュニティなので、とってもありがたかったです。
定期的に参加したいです😊
Ruby on RailsでSpringの全プロセスを一行で終了するコマンド
使用上の注意事項
spring
というキーワードのプロセスがkillされてしまうので、その点ご理解の上、ご使用ください。
使用する際に終了するプロセスの確認方法やコマンドの動作については、下記「仕組みについて」をご参照ください
環境
結論
下記コードが成果物になります。
下記説明を理解の上ご使用ください。
特に kill
コマンドは強力なコマンドなので、コマンドのアクションを理解しておく必要があります。
$ pgrep -f spring | xargs kill -9
仕組みについて
まずはターミナルを起動しましょう
次に、下記コマンドを入力しましょう。
$ pgrep -lf spring
入力するとプロセス名が表示されます。
※画像は$ ps -ef | grep spring
の実行結果だが、似たような情報が表示される
次に下記コードを入力しましょう
$ pgrep -f spring
入力すると、プロセスIDだけが表示されることが確認できます ※スペルミスなどで誤ったプロセスを終了しないように確認できる。安心
そして上記コードで表示できた数値を元にプロセスを強制終了させるのが下記コードです
$ pgrep -f spring | xargs kill -9
参考
おまけ
こういう一行で実行してくれるコマンドをのことをワンライナーと言います。
他にもワンライナーが知りたい場合は、下記リンクに乗っているので、ご参考にされても良いかもしれません
さくらVPSのDebian 9にPostgreSQLを導入するまでの手順書を作ってみた【環境セットアップ手順書その2】
前回に書いた手順書に引き続きまして、PostgreSQLを導入する手順書を作成しました!
手順書
さくらVPS設定その2:PostgreSQLの導入.md · GitHub
あとがき
松本亮介さんの記事を見て、アウトプットは質より量だ!ということで、とりあえず公開してみました!
公開しないまま時間が過ぎていくなら、公開してから編集です!
まずは公開!公開!公開というスタンスでやっていこうかなと思ってます。
さくらVPSのVNCコンソールで、記号が入力できなくなってしまったら
背景
さくらVPSで作業していて、「キーボードから記号の入力ができない!」
そういった声をよく聞くので、対処法をまとめました。
概要
VNCコンソールやめて、シリアルコンソールを使おう
手順
まずはさくらVPSの「コントロールパネル」にログインして、「サーバー」を選択
次に「コンソール」から「シリアルコンソール」を選択
こんな画面が表示されます
少し待つと下記のように「ユーザIDを用いたログイン要求(login:
)」が表示されるので、ここから作業ができるようになります!
あとがき
リモートの作業となると、SSHが基本になってくると思うのですが、それまでの繋ぎとして「Webサービス備え付けのコンソール」を使うことって多々あると思います。
私はパソコンのキーボードが日本語配列だったこともあり、だいぶ苦しめられたので、後進の一助になればと思います。
今後も情報共有は積極的にやっていきたい(やれたらいいな)と思っているので、今後も当ブログをよろしくお願いいたします。
以上、簡単な説明でした。
誤字脱字や意見などがございましたら、お気軽にコメント頂きたいです!(待ってます😆)
さくらVPSにDebian 9をインストールしてからsudo、root、SSHを設定するまでの手順書を作ってみた【環境セットアップ手順書その1】
はじめに
Linuxに限らず、CLIで操作する時一番怖いのは、「適応されていない設定に気づけないこと」だと思います。
なので私は「コマンド実行後のチェック作業付き」で手順書を作成しました。
この手順書を使うことで、みなさんの「コマンドを実行したが、上手くいってるかわからない」「手順書通りに実行したが、どこで手順を間違えたかわからず環境セットアップがいつまでも終了しない」といった問題を解決できればなと思います。
手順書
成果物はGistで公開しています!いつでも更新できて、履歴も残るので良いですよね!
さくらVPS設定手順書その1:Debian 9をインストールしてからsudo、root、SSHを設定するまで.md
目的別、次に学んだら面白そうなこと
- データベースの勉強がしたい
- PostgreSQLのインストール
- 静的Webサイトを公開したい
- Nginx
- Webサイトを作りたい
- HTML/CSS -> Nginx
あとがき
前回のブログ投稿から少し日付が空いてしまいました。 記事の内容や手順書はほとんど完成していたのですが、どこまで品質をあげたら出そうか考えたら、まだまだだな・・・と悩んで出すのが遅れました。 結果として品質はあまり向上しませんでしたが、それも1つの結果として受け止めて今後に繋げていきたいなと思っています。
逆引きターミナル(Terminal)コマンド一覧 ※Macユーザー向け
まえがき
今回はWebデザイナーの為の「本当は怖くない」“黒い画面”入門シリーズ一覧 - FJORDで勉強した内容をまとめます。
はじめに
「パソコンの黒い画面
といえば、コマンド
を入力することでパソコンが処理をしてくれる様子」を思い浮かべると思います。
ですが、「実際何を行なっているか理解できているか?」という話になってくると、
「よくわからない」となってしまう人が大半なのではないでしょうか?
結論から言ってしまえば、できることはコマンドによる操作
になります。
操作できる対象は、コマンドによってまちまちです。
今回はその中でも入門者向けに知っておくと便利なコマンドを一覧化して紹介したいと思います。
対象読者
記載しない内容
- コマンドの使い方
- 理由: Webデザイナーの為の「本当は怖くない」“黒い画面”入門シリーズ一覧 - FJORDに記載があるため
※DRY原則
- 理由: Webデザイナーの為の「本当は怖くない」“黒い画面”入門シリーズ一覧 - FJORDに記載があるため
- より高度な内容
- 理由: 本記事は入門向け記事のため
本文
できること一覧(目的別、コマンド逆引き辞典)
目的 | コマンド | URL |
---|---|---|
フォルダやファイルを表示したい | ls | link |
パスを知りたい | pwd | link |
文字を表示する | echo | link |
マニュアルを表示する | man | link |
ディレクトリの移動 | cd | link |
ネットからファイルをダウンロード | cURL | link |
ファイルを開く | open | link |
かな文字 の読み上げを行う |
SayKana | link |
ファイルの作成 | touch | link |
ディレクトリの作成 | mkdir | link |
ファイルのコピ | cp | link |
ファイルの移動 | mv | link |
ファイルの削除 | rm | link |
ファイル内容の表示 | cat | link |
ファイル・フォルダの権限変更 | chmod | link |
備考
目的別、次に学んだら面白いこと
- 「もっとコマンドについて理解を深めたい!」 - シェルスクリプトについて学習 - 「プログラムに興味ができた!プログラムついて勉強したい!」 - C言語、Java、Pythonなどの言語を興味のある分野に合わせて・・・ - 「ターミナルがどういう原理で動いてるのか知りたい!」 - "bash"で検索
あとがき
ブログはまだ書き始めたこともあり、正直慣れないな〜
というのが本音です。
はじめ想定していたより、書いてみたら内容としては薄くなってしまいますし、文章の体裁も少し硬いかなと(これはもともと私自身が人から言わがちな印象でもあるんですけど)
書き続けることが大事だと思うので、まずは描き続けて、一定期間(1ヶ月とか)続けられたら大きく改善していきたいと思います。
最後まで読んでいただきありがとうございます。