ここ2ヶ月の近況

f:id:shimabukuromeg:20190323100734j:plain

ふと、最近ブログ書いてないのに気づいたので、ここ2ヶ月のことを簡単に振り返ってみる

イベント

  • 2月

    • 前職クロージング
    • 新プロジェクトJoin
  • 3月

https://twitter.com/20092014/status/1101721652373544962

  • Laravel 勉強会でLTした

最近やってること

  • Laravel
  • プロトタイプ作り

技術

  • この2ヶ月で、どれぐらいのスキルが上がったか

    • 基本的にLaravelばかりやってる
    • 具体的に答えられないから、もう少し日々の取り組みを見直そう
      • やったこと・学んだこと・次やることみたいな振り返りを週単位でやろう..。振り返りブログとか書かないと、自分が何やったかすぐ忘れる...よくない
  • 足りないと思ってること

    • Laravelでいま足りないと思っているところここ
    • Laravel使ってるけど、モデル、ビュー、コントローラー、routing、フォームリクエスト(validate)の雛形を使ってそこに簡単なコード乗せっててるだけで、DIとファサードとか疎結合とか理解できていない。良いコードを読むのが一番勉強になりそうな気がするので、色々探して読んでみたい。読む->真似する->オリジナルを作る

最近考えること

  • 何か機能を作ったり実装するとき、まず考えるのが自分が過去やったコードの書き方をどう利用するかってところな気がしていて、そうすると良いコードを書くには、たくさんいいコードを読んで、書いて、自分が過去やった書き方のパターンをたくさん増やしていくのがいいかもしれない。今の自分に足りないのは、コードをたくさん読んでみることな気がする。

  • あんまりコードかけるようになってる実感がないんだけど、最近聞いて心に残ってる話で「コードをかけるようにはいつかなりますが、コードをかけるようになったときにコードをかけるだけじゃ生きていけない世の中になっていたら意味がないのです。だから、数手先の事を考えていきていく必要があるし、そもそも数手先を考えて実装を考える仕事です」というのがあって、コードかけることの価値が低くなった世界がきても生きていけるよう、そんな世界をもう少し想像できるようにしたいと思った。とはいえ、まずはコードかけるようなるよう頑張る

まとめ

  • ここ2ヶ月はいろいろ生活に変化が多い期間だった
  • 特にギークハウスに住み始めて、いろんな人と出会いがあって面白い
  • 改めてブログを書いていこう(週単位の振り返りとか、最近やってみた技術の話とか、読んだ本の感想とか)

今週の振り返り(1月第3週)

今週の振り返り。仕事、イベント、勉強したことなど

やったこと

  • 月曜日
    • いまやってるProject(laravel)のIssue消化(3h)
  • 火曜日
    • いまやってるProject(laravel)のIssue消化(5h)
  • 水曜日
    • イベント
  • 木曜日
  • 金曜日
    • いまやってるProject(laravel)のIssue消化(6h)
    • 県立図書館初めてきた
  • 土曜日
    • いまやってるProject(laravel)のIssue消化とその勉強(5h)
  • そのほか
    • python勉強始めた
    • azure勉強始めた

いまやってるProject(laravel)のIssue消化

取り組んでて考えたこととか、学んだこととか、振り返る。

  • 過去にやったことあるけど、すぐ忘れてる問題。これ前やったことあるけど、どうやってやるんだっけ?どういう仕組みになってるんだっけ?ってなることが多いと感じた。忘れないように定期的に復習しないいけないな…という気持ちになった
  • 例えば、次のようなことを忘れてた。

    • ポリシーの仕組み

      • laravelの認可の仕組み。どのファイルに定義するんだっけ?とか、この書き方あってるんだっけ?とかすごく記憶飛んでた。一度書いたパターンと全く同じ感じでかけるんだったら、似たように書けばいいんだけど、なんか少し違うみたいなとき、そもそもポリシーの仕組みってどうなってるんだっけ?みたいになったので、復習する。
      • ポリシーについて勉強した時の記事。復習する http://shimabukuromeg.hatenadiary.jp/entry/2018/12/02/145305
    • クエリビルダ 、Eloquent周りのメソッド

      • view側に渡す配列を考えるとき、配列の操作でクエリビルダ のメソッドとかEloquentのメソッドとかを使ってデータを取ってきて、配列を作るんだけど、このデータ取ってきたいとき、どのメソッド使えばよかったんだっけ?とか、もっと効率的にできるやつなかったけ?とかスムーズに出てこなかったので、復習する

      • https://blog.capilano-fw.com/?p=727

      • https://readouble.com/laravel/5.5/ja/collections.html
  • ログインするユーザーのタイプによって、ログイン後のリダイレクト先のトップページを変更するやり方を学んだ。

    • 最初、laravelの認証周りのコード(AuthenticatesUsersあたり)を追いかけてて、全然わからず、これどうやってやるんだろって、めちゃめちゃ悩んでたんけど、結果的には、トップコントローラーみたいなコントローラーを作って、ログイン後のリダイレクト先をそこにして、そこで、ログインしたユーザーのタイプによって、それぞれのトップページへリダイレクトするようにした。知ってしまえば、そんなに難しくないんだけど、自分の中だけでは、そういう発想が全く出てこなかったので、勉強になった。今回の例に限らず、こういう状況はよく出てきそう。いろんなProjectのコードをみたり、他の方のコードをみたりして、もっと学んでいきたい
  • 結局以下リンク辺りのコードはあまり知らなくてもできたんだけど、ちゃんと理解できるようにしたい。認証周りのコードむずい

laraweb.net

qiita.com

イベント

沖縄のスタートアップ企業で働くエンジニアのリアルというイベントに参加した。県内のスタートアップ企業で働いてるエンジニアさんの話が聞けてすごく勉強になった。懇親会で参加されたかたといろいろお知り合いになれたりとか、高校時代の同級生がめちゃめちゃ活躍されてるのを知ったりとか、すごく面白いイベントで参加できてよかった。ここで登壇されてたエンジニアさんたちと同じ土俵で話ができるレベルになるよう頑張りたい。

togetter.com

arakaji.hatenablog.com

次週やりたいこと

  • いまやってるProjectで、自分が担当してないIssueのコードを読んでいろいろ勉強、キャッチアップする
  • azureとpythonコツコツ勉強する
  • このブログで復習するって書いたやつをコツコツ復習する

Azureのサービスを色々知りたくなったので触ってみた話

Azureのすごく基本的なサービス(リソースグループ作って、ネットワーク作って、仮想マシン建てて....とか)は、よく使うけど、そのほかのサービスについては、あまり触ったことがなかったので、気になったサービスをいろいろ触ってみた。

Microsoft 公式の無料の学習コンテンツ集を見つけたのでそれを参考にした。(このコンテンツ集めちゃめちゃわかりやすかった)

docs.microsoft.com

やったこと

サーバーレスとサービス間の接続についての2コースをやってみた。

サーバーレス アプリケーションの作成

Azure Functionを使ってみたかったので、とりあえずこのコースをやってみた。トリガーの種類や、バインディングというものの概念を把握できたのがよかった。(バインディングとは、特定の接続ロジックをコーディングしなくても、データリソースに接続できる仕組み)あと、Azure Functionまわりの他の登場人物たちもいろいろ知れて勉強になった。

docs.microsoft.com

サービスの接続

クラウドサービスを使う際に面白いところは、簡単にいろんなサービスを連携できたりするところとかだと思ってるので、このコースをやってみた。Azure Queue Storage、Azure Event Hubsあたりの勉強になった。イベントとかメッセージについての概念やイベント配信システムというものについてもあまりよくわかってなかったので、すごく勉強になった。サンプルコードがC#だったのは、めちゃむずかった

docs.microsoft.com

学んだこと

  • 実際のAzureのコンパネから操作してハンズオン形式で学ぶということで、操作感が掴めたこと

    • サービスごとに、どこに何があるのかって、慣れないと操作しづらいと感じることが多いので、ぽちぽち手を動かしながら操作感を掴めたのはよかったと思う
  • サービスを使う背景

    • どこコースを選択しても、このサービスを使う背景が細かく設定されていて、何のためにこのサービスを使うのかを把握できてよかった。例えば、ソーシャル ネットワーク サイトを運営してる人だったり、美容院の顧客のスケジュール管理を作ってる人だったり、エスカレーターの温度監視してる人だったりの立場に立ってハンズオンを進めるみたいな感じだったので、何のためにそのサービスを使うのかがイメージできて、勉強になった。

次やること

他のコースもやりたい。きになるやつ
  • SQL Server触ったことないので気になる

docs.microsoft.com

  • BIツール気になる

docs.microsoft.com

  • リソース管理は基本的なところだけど、ちゃんと体系的に勉強したことなかったので、気になる

docs.microsoft.com

この学習コースで学んだサービスを組み合わせて実際に使ってみる
  • パッといいアイディアが出てこないので模索中。この学習コース使っただけだと、サービス使いこなせるようにはならないと思うので、もう少し触っていきたい。ネットにあるやってみた記事を参考にやってみるとか、考えてみる。

感想

  • コンテンツ集、わかりやすいし面白いので他のコースもやっていきたい

  • 時間かかりすぎな感じもあるので、テンポよく進められるよう頑張る(コース毎に学習目安時間が提示されてる)

  • まだ簡単な操作感と概要みたいなのを把握できただけなので、実践していけるようコースを応用した何かを作ってみるとかしてみる

めっちゃ時間かかってたIssueが終わったので振り返り

めっちゃ時間かかってたIssueがやっと終わった。

思ったより、時間かかったので、なんでこんなに時間かかったのかを振り返る。

振り返り

時間かかったと思われる要因、適当にあげてみる

  • 欲しい配列の構造を作るのがむずかった(配列操作力弱すぎ)

    • まず欲しいデータの構造を決めるのがむずい
    • 決めたとして、どうやって引っ張ってくるかが考えるのがむずい
    • やってる途中で、この要素いらないんじゃない?この要素必要なんじゃない?ってのが出てきて、むずい
    • 引っ張ってくるデータの関連性とか考慮しないといけなくなると難しくなる印象
  • データを引っ張ってくるときに、クエリビルダ を使えばいいのか、Eloquentを使えばいいのか迷った

  • どちらを使うにせよ、使い方をちゃんとわかっておらず、ドキュメントみながらで、時間かかった

    • ちゃんとわかっていないって言ってるのは、準備されてるメソッドの使い方とか、このメソッドを使うときの引数やreturnがどんな感じになってるのか、etc....
    • なので、ドキュメント見ればいいだけなんだけど、なんというかドキュメントを読み解くのに時間がかかったってのと、ドキュメントに書いてるサンプルコードを自分が書いてるコードに合わせて書くってのに時間がかかった
    • あと、そもそも、どういうのが準備されてるのかを探すとことか時間がかかった
  • SQL弱い

    • joinとかinnerjoinとか複数のテーブルの操作系
  • 過去やったことあるやつもすぐ忘れて同じこと調べすぎ問題

  • 既存コードの意図を読み取るのに時間がかかった(そもそものコード読む力弱い)

  • JSのコード読む力弱すぎた(そんなに難しいコードじゃないかもだけど、今回はJSのコードも変更に含んでて、わからなすぎて時間かかった)

改善

上記、振り返りを改善するために、ざっくり考えたこと

  • 欲しい配列の構造を作るのがむずかった(配列操作力弱すぎ)の改善

    • APIとか触るようになると、もっと理解力深まるかも。
    • 難しいと思ったコードと似てるコードをもっと読む(今作ってるアプリの違う機能のとこで、似たようなとこありそうだから読んでみるとか。慣れる)
    • 難しいと思ったコードの状況と似ているコードが必要になるシュツエーションを想像する。そして書いてみる
  • データを引っ張ってくるときに、クエリビルダ を使えばいいのか、Eloquentを使えばいいのか迷った。の改善

    • 使い分けの目安を持つ
      • Eloquentを使うときは、対象とのテーブル(モデル)が1つの場合とか、関連するデータを富豪的に取ってきたい時とか。Eloquent使う場面の方が多そう
      • クエリビルダ を使うときは、複数のテーブルからデータを取ってこないといけない、ちょっと複雑なSQLを使ってデータを取ってきたい時とか
  • どちらを使うにせよ、使い方をちゃんとわかっておらず、ドキュメントみながらで時間かかった。の改善

  • SQL弱い。の改善

    • 都度理解していくようにする
    • Laravelドキュメントのクエリービルダーのとこ中心に復習
    • 時間見つけて、SQLの本読んでみる
  • 過去やったことあるやつもすぐ忘れて同じこと調べすぎ問題。の改善

  • 既存コードの意図を読み取るのに時間がかかった(そもそものコード読む力弱い)の改善。

    • 単純に読む量少ない問題あると思うので、時間積む
    • ただ、闇雲に読むってのも微妙かもなので、効率的に読むポイントとかあれば抑えたい(模索中)
  • JSのコード読む力弱すぎた(そんなに難しいコードじゃないかもだけど、JSのコードも変更に含んでて、わからなすぎて時間かかった)の改善。

    • 改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用までって本を買ったので、基礎から勉強する

感想

ちょっとづつ進歩してる感じもあるけど、もっとサクサクコードかけるようになりたい。頑張ろ。

オブジェクト指向設計実践ガイド5章を読んだ感想

この章は、ダックタイピングの話。これまでの章もそうだったけど、いかに抽象化して、再利用可能にして、変更コストを下げるかというのがたくさん述べられてた。やはりそれだけ重要ってことですね。ダックタイピングは、動的型付け言語の抽象化を促してくれるやり方の一つで、ダックタイピングを使って抽象化しましょうという感じの内容。めちゃめちゃ勉強になった。ここまで読み進めて、抽象化、再利用、インターフェース、変更コストなど、オブジェクト指向設計で重要と思われるキーワードを何度も目にして思ったことなんだけど、この概念たちは、プログラミングの世界に限らず、世の中一般的なことで考えても、当てはまる気がした。仕事とか、日常生活の中で起こる何かしらの具体的な行動、成功体験を、自分なりに解釈して、抽象度をあげて整理して、それをまた別の行動にも応用、再利用するみたいなことは、割と一般的に考えてる人は多いと思う。プログラミングの世界でも、具体的なコードがいくつかあって、それらの共通する部分を切り出して、抽象的に考えて、コードに落とし込むことによって、応用の効く、再利用可能なコードが出来あがるんじゃないかなと思ったりした。

イントロ

  • 次の2つの考えを組み合わせるのが強力な設計テクニック
    • メッセージ中心の設計
    • 厳密に定義されたパブリックインターフェースの構築
  • これはダックタイピングとして知られてるテクニック。この章では、ダックタイピングについて勉強する

5.1 ダックタイピングを理解する

  • プログラミング言語での「型」は、変数の中身の分類を示す
  • オブジェクトは、ただ一つのインターフェースだけに応答するってわけじゃない
    • Rubyのオブジェクトは、テーマにそってマスクを変える仮面武道会の参加者みたいな感じ(型を明示的に示さない言語仕様)
  • アプリケーションによっては、特定の1つのクラスに関連しないパブリックインターフェースをいくつも定義することもある
    • 4章では、クラス「内」のインターフェースに注目した話たっだけど、ここではそれ以外のインターフェースの話。
    • ポイントは、オブジェクトが何で「ある」かではなく、何を「する」か。
    • あらゆるオブジェクトが他のオブジェクトを常に信頼して、それでいてどんな種類のオブジェクトになれる場合、設計の可能性は無限大になる。めちゃめちゃ柔軟な設計を作れる
  • 柔軟性を賢く利用する方法
    • クラスをまたいだ型を認識すること
      • クラスをまたいだ型というのは、ダックタイプのパブリックインターフェースのこと
    • クラス内で作るパブリックインターフェースの型パターンと同じくらい入念に作る(第4章でのパターンの話)
  • ダックタイプとは
    • オブジェクトのクラスが何であろうとそのメソッドが呼び出せれば良しとするプログラミングスタイルのことをダックタイピングという
    • ダックタイプを説明する最善の方法は、ダックタイプを使わないとどうなるかを検討してみると良い
    • この本の言い回しだと、ダックタイプは、「クラスをまたいだ型、インターフェース」を表してるっぽい
  • ダックを見逃してるパターン1(以下、サンプルコードとシーケンス図)
    • 4章の図4.6に近い例

  • ダックを見逃してるパターン2(以下、サンプルコードとシーケンス図)
    • 要件が変わって旅行の準備がさらに複雑になった場合を想定したもの
    • このサンプルコードは、自身を出口のない苦境に陥れるプロセスの最初の一歩。重要なメッセージを見つけられなかったときに書いてしまうようなコードで、依存満載。よくない。
    • このようなコードを書いちゃう原因は、prepareがMechanicインスタンスを想定しているという考えからこうなちゃってる。(心の奥底では、引数はMechanicであると思っちゃってる)
    • caseとかで、引数となるインスタンスのパターンを切り替えるようにしてるけど、これだと依存が爆発的に増える書き方
    • シーケンス図をみても、複雑な感じになってる

  • ダックを見つける
    • ダックを見つけられず依存満載のコードから、依存を取り除く鍵となるのは、「Tripのprepareメソッドは単一の目的を果たすためにあるので、その引数も単一の目的を共に達成するために渡されてくるということを認識すること」です
    • 共通の目的を考えると、prepareメソッドが何を必要とするかという話になって、それは「旅の準備をすること」だと言える。
    • 次の図は、ダックを生み出した場合を表した図
      • これまは、prepaeメソッドは、引数のクラス別で処理方法を変えてたけど、ここでは、prepare_tripに応答できる複数のPreparerインスタンスが引数にくることを想定するようになった

  • 上記の図を表したサンプルコード
  • ダックタイピングの影響
    • もともとprepareメソッドは具象クラスに依存してた。変更後は、ダックタイプに依存するようになった
    • 最初のコードはの具象性は、コードを理解しやすいが、拡張に危険が伴う
    • ダックタイプ化されたコードは、抽象的で理解力が求められるけど、拡張が容易になった
    • 具象化と抽象化のコストの緊張は、オブジェクト指向設計で基本的なこと
  • ポリモーフィズム
    • 多様性、多相性
    • 同じメッセージに応答できる能力のこと
    • メッセージの送り手は、受けてのクラスを気にする必要が無く、受け手は、それぞれが独自化した振る舞いを提供する

5.2 ダックを信頼するコードをかく

  • ダックタイプの実装自体は、比較的簡単
  • ダックタイプが必要であるかを見つけることと、そのインターフェースを抽象化するのがむずい
  • 隠れたダックを認識する。次のものはダックで置き換えれる
    • クラスで分岐するcase文
    • kind_of?とis_a?
    • responds_to?
  • もっとも簡単なダックタイプは、単純にパブリックインターフェースの取り決めとしてだけ存在してるもの(この章でダックタイプ化したサンプルコードもこの類に入る)
    • いくつか、異なるクラス(Mechanic,Driver,TripCoordinator)にprepare_tripを実装することで、異なるクラスたちをPreparerとして抽象的にフル回せるようにした
  • ダック間でコードを共有する
    • この章でのPreparerダックたち(Mechanic,Driver,TripCoordinator)は、それぞれが各クラスで独自の振る舞いを用意してる。実装は共有していない
    • ダックタイピに慣れてくると、ダックタイプを実装するクラスは振る舞いも幾らか共有する必要があることに気づく。
      • このあたりは7章で説明する(コードを共有するダックタイプ)
  • 賢くダックを選ぶ
    • kind_of?やis_a?、responds_to?を使われてても、あえてダックにしないほうが良い場合もある
    • 例えば、HashやIntegerのような、Rubyのコア機能へ依存してるとかだと、コアクラス自体が安定してるものと考えて良いので、あえてダックにしなくてもいいという感じ

5.3 ダックタイピングへの恐れを克服する

  • 静的型付け言語と動的型付け言語の比較
  • 静的型付け言語は、それぞれの変数の型とメソッドのパラメーターを明示的に宣言する
  • 動的型付け言語だと、この要求を省く
  • 静的型付け支持者があげる静的型付けのメリット
    • コンパイラコンパイル時にかたのエラーを発見してくれる
    • 可視化された型情報は、文書の役割も果たしてくれる
    • コンパイルされたコードは最適化され、高速に動作する
  • 動的型付け支持者があげる動的型付けのメリット
  • ダックタイピングは、動的型付けの上に成り立つ

ダックタイピングまとめ

  • メッセージこそ、オブジェクト指向アプリケーションの中心にあるもの
  • メッセージはパブリックインターフェースを介して、オブジェクト間で交換される
  • ダックタイピングは、これらのパブリックインターフェースを特定のクラスから切り離し、何であるかではなく、何をするかによって定義される。仮想の型を作る
  • ダックタイピングは、根底にある抽象を表し、柔軟性を高めてくれる

全体的な感想

  • この章の説明を読むとダックタイプについてわかった気になるけど、実際のコードをかくときとかでこの考えを利用できるかは、また別の話のように思えるので、実務レベルで使えるようになるため、この考えが含まれてるコードをたくさん読む、そしてたくさん手を動かす、ってことを進めていきたい

  • ここまで読むのに時間かかり過ぎだー

オブジェクト指向設計実践ガイド4章を読んだ感想

4章読み終えた。この章は「柔軟なインターフェースを作る」話。今回もかなり読み応えがあって、特に 4.3のパブリックインターフェースを見つける、のところはすごく勉強になった。また読み返したい。特に勉強になったところは、オブジェクト指向を考えるとき、オブジェクト同士が、どうメッセージのやりとりするかを考えると、より柔軟なアプリケーショを書けけるようになると述べられてた部分で、これができるようになると、設計者のキャリアとしても転機が起きてることがいえるらしく、すごく重要な考えなんだと思った。

内容的には、この本で挙げられてる例を踏まえると、一応わかった気にはなるのだけど、実際にこのメッセージ的な設計の考えを、今やってる開発(Laravel)とかで当てはめようとすると、いまいちピンとこなかった。いまいちピンとこなかったところとしては、この本でオブジェクトのメッセージについて説明している例(Tripクラスが、自転車の準備状態のチェックを、Mechanicクラスにメッセージを送って確認するっていう例)を、コントローラやモデル、サービスクラスなどで、どんな感じで当てはめたらいいのかわからず、難しいというような感じ。そもそも、どういうクラスが必要で、各クラスたちにどういう責任を持たせておくべきか、みたいなとこから考え切れてないので、そういうとこも原因の一つだと思うけど、それでもむずそう。頑張って理解していけるようにする。

あと、メッセージに基づく設計の方が、柔軟性があるアプリになる理由を少し考えてみた。オブジェクト同士のメッセージって、依存関係が発生するような場所になりやすそうな感じなので、そこを中心にするってことは、依存関係の管理とかをより中心的に見れるようになり、それでより柔軟性のあるアプリになる感じなのかなと思ったりした。概念はわかったので、あとは実践していけるようにする。実践していくにあたり、オブジェクト間のメッセージを見つけることもすごく重要で、シーケンス図を使って探すのがめちゃめちゃ良さそう。なので、シーケンス図もっと使っていけるようにする。設計初心者がたどる「オブジェクト」指向なコードの動きを表した図が紹介されてて、そこでの設計初心者の状態を早く抜けれるよう頑張りたい

以外、本読んで、気になったところや重要そうだと思ったところ抜粋

4.1 インターフェースを理解する

  • 丸は、オブジェクトを表してる
  • 上記図の左側のやつは、いろんなものを明らかにしすぎてて、いろんなとこにアクセスできてる。上記図の右側のやつは、制約をつけてるので、特定のとこにしかアクセスできないようになってる
  • 左側のやつは、もはや再利用不可能。依存性注入や、単一責任などをちゃんと設計できててても、このような状態になる可能性があって、大事なポイントとしては、クラスが何を「する」かではなく、何を「明らかにする」かを設計しないといけない
  • 設計で考慮したいこと(明らかにしたいこと)

    • オブジェクトが何を知っているのか(責務)
    • オブジェクトが誰を知っているのか(依存関係)
    • オブジェク同士がどうやって会話するのか(メッセージをやりとりするのか)
      • オブジェクトの会話は、オブジェクトの「インターフェース」を介して行われる
  • オブジェクトにアクセスする際に必要なのがインターフェース。インターフェースの概念は色々あるけど、この章では、クラス「内」にあるインターフェースの話

    • クラス内にあるインターフェース
      • クラスは、メソッドを実装し、そのうちいくつかは他のオブジェクトから使われることが意図されている。
      • それらのメソッドがそのクラスのパブリックインターフェースを構成する
    • クラス内にあるインターフェース、以外にもインターフェースの概念はいくつかあって、例えば、複数クラスにまたがって、どの単一のクラスからも独立してるもの、があげられたりする
      • これは5章のダックタイピングでコストを削減するのところで話す

4.2 インターフェースを定義する

  • インターフェースとは、オブジェクトにアクセスするための入り口
  • レストランで例えると、メニューはパブリックなインターフェースと書いてあるのがわかりやすかった(お客さんは、選んだメニューがどうやって作られるかは知らなくていい)
  • パブリックインターフェースを作るメソッドによって、クラスが外の世界に顔をだす
  • パブリックインターフェースの特性
    • クラスの主要な責任を明らかにする
    • 外部から実行されることが想定される
    • 気まぐれに変更されない
    • 他者がそこに依存しても安全
    • テストで完全に文書化されてる
  • プライベートインターフェースの特性
    • 実装の詳細に関わる
    • 他のオブジェクトから送られてくることは想定されていない
    • どんな理由でも変更されえる
    • 他者がそこに依存するのは危険
    • テストでは言及されないこともある

4.3 パブリックインターフェースを見つける

  • パブリックインターフェースを見つけて定義する
    • クラスの主要な責任を見つけて定義する
    • パブリックインターフェースの設計が良いと、変更に対するコストが下がる
      • なぜ?
  • アプリケーションを新規で作成するときに、いい感じのインターフェースを発見する方法
    • ツールを使う
      • シーケンス図
      • ユースケース(要件)を満足させるために、必要なオブジェクトとメッセージの両方を検討する際、まずコードを書かなくても良い
    • ドメインオブジェクト
      • アプリケーションの性質から、なんとなくどんなクラスが必要なのか検討をつくものがある
      • それはデータと振る舞いの両方を兼ね揃えた名詞だったりする。これをドメインオブジェクトという
      • ドメインオブジェクトは、最終的にデータベースに表されるものだといえる
      • ドメインオブジェクトは簡単に見つけられるけど、設計するときに中心になるものではない。注意を向けるべきなのは、オブジェクト間で交わされるメッセージ
        • なぜ?
  • シーケンス図
    • シーケンス図を使うことで、オブジェクト間がどんなメッセージを交わすかわかりやすくなる
    • ユースケースでの名詞は、オブジェクトになる
    • ユースケースでのアクションは、メッセージになる
    • オブジェクトは、パブリックインターフェースを介してのみ、お互いに交信すべきなので、シーケンス図を書くことで、パブリックインターフェースを明らかにできる
    • シーケンス図を書くことによって、議論が逆転する
      • クラスに基づく設計からメッセージに基づく設計へ
      • 「このクラスが必要なのは、知ってるけど、これは何をすべきなんだろう」から「このメッセージを送る必要があるけど、誰が応答すべきなんだろう」へ
  • 適切に定義されたパブリックインターフェースをもつ再利用可能なクラスを作るポイント
    • 「送り手の望みを頼むメッセージ」と「受け手にどのように振る舞うかを伝えるメッセージ」の違いを考える
    • メッセージをやりとりする際の「何を」対「どのように」の重要性
      • オブジェクト間でメッセージのやりとりをするとき、「どのように」の部分まで、振る舞いを知っている必要はなくて、「何を」の部分だけにできると、依存関係が小さくなっていよい。オブジェクト同士は、お互いをあまり知りすぎないほうが、コードのメンテナス性や柔軟性が向上する
  • 図4.5から4.7は、設計初心者がたどる「オブジェクト」指向なコードの動き
  • 図4.5では、TripはMechanicに「私は自分が何を望んでいるかを知っているし、あなたがそれをどのようにやるかも知ってるよ」と伝える

  • 図4.6では、TripはMechanicに「私は自分が何を望んでいるかを知っていて、なあなたが何をするかも知っているよ」

  • 図4.7では、TripはMechanicに「私は自分が何を望んでいるかを知っているし、あなたがあなたの担当部分をやってくれると信じているよ」

  • まだ、定義されていないオブジェクトが必要である認識を得るための方法

    • シーケンス図を使う
    • Consumerから発信されるメッセージ(適切な旅行を見つけるためのメッセージ)、を受け取るオブジェクトが定義されていない
      • 適切な旅行を見つける責任を持ったオブジェクト
      • 適切な旅行を見つける振る舞いをするオブジェクト

4.4 一番良い面(インターフェース)を表に出すコードを書く

  • 明示的なインターフェースを作る。パブリックインターフェースに含まれるメソッドは、次のようなものであるべき
    • 明示的にパブリックインターフェースだと特定できる
    • 「どのように」よりも「何を」になっている
    • 名前は、考えられる限り、変わり得ないものである
    • オプション引数として、ハッシュをとる

4.5 デメテルの法則

  • デメテルの法則とは
    • オブジェクトを疎結合にするためのコーディング規則の集まり
    • 列車事故を除去する方法で、委譲を使う方法がある
      • 列車事故は、異なる型のオブジェクトを複数繋げて、メッセージを送ること
      • 委譲とは、他のオブジェクトにメッセージを渡すこと
      • 委譲を実現する方法はいろいろあって、forwardable.rbとか使ったりする
      • これらは、それぞれオブジェクトが自身に送られたメッセージを自動的に捉え、どこか他のところへ送り直すのを簡単にするために存在してる
    • 参考
    • 委譲サンプルコード
  • デメテルの法則は、委譲をたくさん使っていこう、という話ではなくて、長いメソッドチェーンで繋がってて、欲しい振る舞いがかなり遠くにいるのがよくないって話
  • なので、もっと近くでメッセージをやりとりできるよう、新しくオブジェクトを作る
  • デメテルの法則違反(メソッドチェーンで連なった列車事故)は、パブリックインターフェースが足りてなくて、発生するので新しくパブリックインターフェすを作る際のヒントにできる

全体的な感想

  • むずいけど、少しづつわかってきた感もあるので、引き続き頑張る
  • この考え方を元に、実際にコードをかけることが重要なので、取り入れていけるよう頑張る

オブジェクト指向設計実践ガイド3章を読んだ感想

3章は依存関係を管理する話。サンプルコードを使って、オブジェクト指向設計の依存関係について説明されてて、わかりやすかった。最近は Laravelを勉強してることが多くて、その中で依存性の注入(DI)の概念とかがよく出てくるんだけど、いまいちよくわからんなーとか思ってたところを、この章の説明を読んで、理解が深まった気がする。一通り読んだ印象としては、コードの中で依存してる箇所を、どんどん取り除いていって、依存部分を別のところ定義し直して、極力依存してる箇所を減らそうよ、みたいな記述が多くあったのが特に印象に残った。それは、そうすることで再利用可能なコードになるし、複雑さが減る。依存してる部分に変更があった場合に、変更箇所が少なくて済む、などメリットがある。なんども出てきてるけど、アプリケーションを書く上で重要なのは、柔軟性のある、変更に強いコードを書くことなんだなあと思いました。以下、この章で気になったところや重要そうだと思ったところ抜粋

  • 3.1 依存関係を理解する
  • 3.2 疎結合なコードを書く
  • 3.3 依存方向の管理

3.1 依存関係を理解する

  • 依存関係があるコード例(悪い例)
  • 上記の依存関係があるコード例では、Wheelの変更によって、Gearへの変更が強制される部分が少なくても4つある(どこでしょうか?)
  • 正解は次の4つ。一定の依存関係がクラス間に築かれるのはしょうがないけど、この4つは不要な依存関係で、コードをより複雑化してしまう。
    • 他のクラスの名前
      • gear_inches メソッドの Wheel.new(rim,tire) の部分で、Gearクラスが、Wheelクラスの存在を知ってる
    • self以外のどこかに送るメッセージの名前
      • gear_inches メソッドの Wheel.new(rim,tire).diameter の部分で、Gearクラスは、Wheel クラスがdiameterというメッセージに応答することを知ってる
    • メッセージが要求する引数
      • メッセージを送る際に(gear_inches メソッドの Wheel.new(rim,tire).diameter の部分)で、Wheel.newの引数にrimとtireが必要なことを知ってる
    • そららの引数の順番
      • Wheel.new(rim,tire) の引数の順番が知られてる
  • 設計課題は「依存関係を管理して、それぞれのクラスが持つ依存を最低限にすること」です。
  • クラスが知るべきことは、自身の責任を果たすために必要十分でよい。知りすぎるのは良くない
  • 以下の図は、悪いコード例を表した図になっていて、GearがWheelを知れば知るほど、この2つのクラスの結合はより密になる。そして、あたかも1つのエンティティのように振る舞うことになってしまう
    • Wheelに変更を加えると、Gearも変更しなきゃいけなかったり
    • Gearを再利用したいだけなのに、Wheelもついて来ちゃう

  • 依存関係に関連した一般的な問題というものがある。大別して次の2つ
    • 破壊的な類の依存関係が生じる場合
      • 『「何かを知るオブジェクト」を知るオブジェクト』を知るオブジェクトがある場合
      • デメテルの法則違反
      • いくつものメソッドチェーンを繋いで、遠くのオブジェクトの振る舞い実行すること
      • 途中のオブジェクトに変更が入る可能性を考慮すべき
    • コードに対するテストの依存関係
      • テストを書き始めたプログラマーはコードと過度に結合したテストを書きがち
        • コードをリファクタリングするたびにテストが壊れる
          • テストの設計は、9章で検討する

3.2 疎結合なコードを書く

  • 依存オブジェクトの注入
    • 他のクラスに、クラス名そのもので参照してるところは、結合を生み出す主要な場所になる
      • サンプルコードだと、gear_inchesメソッドで、Wheelクラスを参照してる
      • この書き方だと、gear_inchesメソッドは、Wheelインスタンスのギアインチしか計算しないことになって、例えばの他にギアインチを測りたくても測れない(Wheelへの参照がハードコードされてるので)
      • 本来であれば、gear_inchesメソッドは、diameterに応答できるオブジェクト(直径を測ってるくれるメソッドをもつオブジェクト)があれば良い(Wheel.new(rim,tire) じゃなくても良い)
      • Gearクラスが、他のオブジェクトについて、知りすぎてると、再利用しづらくなる
      • そのため、このWheelと結合してる部分をやめて、初期化(initialize)の時に、diameterに応答できるオブジェクトを要求するように変更したら良さそう
    • 修正したサンプルコード
      • この変更をすることによってGearクラスのgear_inchesメソッドは、wheelがWheelクラスのインスタンスであるかを知ってる必要がなくて、単純にdiameterに応答するオブジェクトであるかを気にするだけでよくなった
      • 変更前は、Wheel.new(rim,tire).diameter となっていて、Wheelクラスのインスタンスであることを気にしないといけなかった
      • このような変更後のコードのことを、依存オブジェクトの注入という
  • すでにアプリケーションとして動いているコードは、いろいろと制約すでに存在している可能性があって、依存オブジェクトを注入するように変更できない場合もある。そういう場合は、クラス内で隔離するようにする。
    • gear_inchesメソッド内でWheelインスタンスが作成されてたのを、initializeメソッドで作るようにする。こうすると、gear_inchesメソッドは綺麗になって、依存はinitializeメソッドで公開される
    • wheelインスタンスを作るメソッドを別で用意する
  • メッセージに着目して考える場合
    • メッセージとは
      • とあるオブジェクト(レシーバ)のメソッドを使うことを、メッセージを送るって表現することがある
      • レシーバとメッセージという呼び方は、Smalltalkというオブジェクト指向言語でよく使われる呼び方
    • 外部メッセージを隔離して、selfにメッセージを送るようにする
      • 外部にメッセージを送ってるところを隔離する。隔離するっていうのは、専用のメソッド内にカプセル化するって意味
  • 引数の順番への依存を取り除く
    • initializeメソッドなど、初期化する時に指定されてる引数があって、順番も決まってて、という依存があるが、これらの「固定された順番の引数」への依存を簡単に回避する方法がある
      • initializeメソッドに引数をただ一つargsのみを取るようにする
      • 初期化の際の引数にargs(ハッシュ)が使われてるのって、引数の固定された順番への依存を解消するためだったのか。(railsとかで定義元ジャンプしていくと、引数にargsを指定されてるメソッドとかがたくさんあってよくわからんみたいな印象があったので、なるほどと思いました)
  • 引数の順番への依存を取り除いたサンプルコード
  • 明示的にデフォルト値を設定する
    • || メソッド(or演算子と同様の動作をする)を使う
      • || メソッドを使うと、引数に指定するargs(ハッシュ)の中で、true/falseを値にもつキーのデフォルト値がtrueの場合、明示的に値をfalseにすることができない問題がある
      • そのため、このような場合は、fetch メソッドを使うほうが良くて、fetch メソッドを使うと、フェッチしようとしてるキーの先がハッシュであることが期待されて、ハッシュのキーがない時だけ、デフォルト値を採用される。なので、|| メソッドと違って、意図的に値をfalseにできる
  • 複数のパラメーターを用いた初期化を隔離する
    • 変更が必要なメソッドを「自身で」修正できない場合に、依存関係を取り除くようにする方法についての話
    • 例えば、引数の順番の依存関係などが変更できない状況(外部のフレームワークの一部で、簡単に変更できない状況)の場合に、この依存関係を隔離する方法
    • その方法とは、外部のインターフェースを包み隠すメソッドを作る
    • 以下のサンプルコードでいうとGearWrapperモジュールの特異メソッドgearを定義して、そこでは、argsを引数に取れるようにする。そうすることで、引数の依存関係を隔離できる
    • 結果、GearWrapper.gear(:chainring => 52, :cog => 11, :wheel => Wheel.new(26, 1.5)).gear_inches の部分で、オプションハッシュを使って、Gearの新しいインスタンスを作れるようになった
  • 複数のパラメーターを用いた初期化を隔離するサンプルコード

3.3 依存方向の管理

  • 依存関係には常に方向がある
  • これまでの例は、GearがWheelやdiameterに依存していた
  • 逆に、WheelをGearやratioに依存させることもできる
  • 依存関係を逆転させたサンプルコード
  • 依存方向の選択
    • 依存の方向を考える時「自身より変更されないものに依存する」ようにした方が良い。具体的には以下の3つを考える
      • あるクラスは、他のクラスより要件が変わりやすい
        • 例えば、rubyの基本的なクラス(String,Arrayなど)が大きく変わることは少ない
      • 具象クラスは、抽象クラスよりも変わる可能性が高い
        • 依存オブジェクトの注入のところで説明した話
          • クラス内で、newしたインスタンスに依存するより、初期化時にインスタンスを必要とするように修正すると、より抽象的なものに依存するようになった
        • 静的型付言語は、インターフェースを宣言して、注入するインスタンスがそのインターフェースの一種だと、注入先のインスタンスに教える
        • rubyの場合、ダックタイプに依存していて、これは実は、さりげなくインターフェースを定義してる
        • インターフェースは、依存関係をより抽象的にするためのもの。
          • インターフェースとは、あるカテゴリーのものは、〇〇をもつ、という概念が抽象化されたもの
            • 今回のサンプルコードでいうと、wheelインスタンスは、diameterをもつ
      • 多くのところから依存されたクラスを変更すると、広範囲に影響が及ぶ

全体的な感想

  • なかなか理解が追いつかなくて、スラスラ読めてる感じじゃないけど、読み応えがあってすごく勉強になる章だった。
  • 概念的には理解できた感じあるけど、実践で具体的にコード書くとなると、まだ難しそう。ここで書いてることを意識しながら、実践でもこの考え方を使えるようにしていきたい
  • ここは依存性を注入してコード書こうとか、ここは依存性を逆転させた方が良さそうとかを考えて、コードを書ける日が来るのだろうかと思ってしまったりするけど、少しづつ成長していけるよう頑張る