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

オブジェクト指向設計実践ガイドという本を読み始めた。オブジェクト指向設計を意識して責務を分けコードを書くことができるとか、拡張性を考えてコードを書くことができるとか、このあたりの知識が弱いと思っていて、この本を読んでそのあたりの知識をつけていけたらなと思う。

1章 オブジェクト指向設計

一通り読んだ感想として、「変更に強いことが大事」というのが、言い回しを変えて、繰り返し書かれているのが印象的だった。アプリケーションが変更されるのは、重力みたいなものなので、その変更コストをどう抑えるのかみたいなところを考えると、変更に強いことがすごく重要になるという話。以下、本で気になったところ箇所抜粋

  • 設計が解決する問題
    • 要件の変更はプログラミングにおける摩擦力と重力
    • 変更が容易なアプリケーションを書けるようにする
    • 「あとにでも」設計できるようにする。変更コストの削減
  • 原則
    • SOLIDというオブジェクト指向設計でもっともよく知られる5つの原則がある
      • 単一責任
      • オープン・クローズド
      • リスコフの置換
      • インターフェース分離
      • 依存性逆転
  • 設計パターン
    • いわゆるGang of Fourと呼ばれるもの
    • 「設計プロダクトの柔軟性、モジュール性、再利用性、理解のしやすさ」をより高めてくれる

2章 単一責任のクラスを設計する

一通り読んだ感想として、「単一責任にするのは、再利用しやすいため」ということがすごく伝わった。また、変更を歓迎するコードとして、良く知られてる方法の一つに、「データではなく、振る舞いに依存するようなコードを書く」というのもすごく勉強になった。インスタンス変数や構造が複雑な配列を直接参照してて、そのデータに変更が発生した場合、その変更に合わせて参照してたところを全部修正するのは、かなり手間が発生するので、直接データを見るんじゃなくて、それを包むメソッドを作って(メッセージを受け取ると、データにアクセスする振る舞いをするメソッドを作って)、アクセスした方が良い。あと、題材になってた、自転車のギアとギアインチの関係を理解するのが、ちょっと頭痛かった(ただの算数だけど、なんか頭に入ってこなかった。。。)以下、本で気になったところ箇所抜粋

f:id:shimabukuromeg:20190102164250j:plain

  • なぜ単一責任なのか
    • 再利用が容易になる
      • 2つ以上の責任を持つクラスは再利用が簡単ではない
  • クラスが単一の責任かどうか見極める方法
    • クラスのもつメソッドを質問に言い換えた時、意味をなす質問になっているかどうか
  • 変更を歓迎するコードを書く。データではなく、振る舞いに依存する(データに依存するのはよくない)
    • 良くない理由は、データが変わった時に、それを参照してる箇所を全て修正しなきゃいけないから
    • データではなく、振る舞いに依存するよう、特定のデータにアクセスするようなメソッドを作って、そのメソッド(振る舞い)を使ってアクセスする
    • 例えば、インスタンス変数に結びついているようなコードはよくなくて、インスタンス変数を隠蔽するよう、インスタンス変数へのアクセスできるメソッドで包む
    • 配列など、複雑なデータ構造への依存はさらによくない(データに依存するのはよくない)
      • 配列のデータ構造が変わると、それを参照してるコードを全て直さなきゃいけなくなる。なので、データ構造の隠蔽するようにする
        • 複雑な構造への直接の参照は混乱を招く問題があるので、意味と構造を分けれる
          • 意味と構造を分けるとは?
            • 意味(タイヤの直径を知りたい)と構造(配列を直接参照する複雑な構造)が一つのメソッドの中にあったところを、意味と構造を分け、diametersメソッドと構造を作るwheelfyメソッドを用意したってこと?
          • Structクラスを使って、構造を包み隠す。Structクラスは、明示的にクラスを書くことなく、いくつもの属性を1箇所に束ねるための便利な方法
  • Structサンプルコード

全体的な感想

いろいろ勉強になるし面白い。ただ、なかなか読むのが遅い。あと実践でもちゃんと使えるようになることを意識して読み進めたい。

2019年抱負

今年の年末にちゃんと答え合わせできるよう、簡単にだけど今年の目標を書いた。この一年は、もっとWebのスキルをつける年にしたい。2800hぐらい時間積みたいと思ってる。

  • 1700時間ぐらいは、お仕事の時間でいろいろ学べるように頑張る
  • 1100時間は、足りないスキル、気になるスキルキャッチアップする時間にする

今年1年でWebアプリケーションエンジニアとちゃんと名乗れるようになるのが目標

  • まだまだ初心者感が抜けてないと思ってるので、今年1年で脱初心者、中級者になれるようにする
  • rails,laravelのフレームワークをちゃんと使いこなせるようになりたい
  • ちゃんとっていうとあれだけど、アプリケーションを作る際に考慮すべきことを知っていて、それについて議論できて、決まったことをコードで表現できるようになる
  • そのための具体的なTODOは、都度考えながら、仕事で学んだり、本読んで学んだり、軌道修正しながら進めて行きたい

とりあえず今年インプットしておきたいと思ってるリスト

基礎力足りないと思ってて、ちゃんと読み切りたいと思ってる本のインプットと、手を動かして作りたいと思ってることリスト。仕事で使うスキルを中心にいい感じでキャッチアップできたらいいなあと思ってる。本読む、手を動かす、その結果をブログに書く、みたいなサイクルをたくさんしたいと思う。時間割は適当(本については1章3hとかの計算)

  • rubyオブジェクト指向本(30h)
  • laravel本(50h)
  • laravelオープンソースプロジェクトを読む(40h)
  • laravelで自作アプリ(50h)
  • 現場ruby本(30h)
  • javascript本格入門本(50h)
  • churakariリリースする(150h)
  • isucon周りの勉強(200h)
  • 実践コンテナ本読む(30h)
  • hello,world gem

資格

体系的に理解していけるように資格も取れたらいいなあと思ってる

kakakakakku.hatenablog.com

kiryuanzu.hatenablog.com

アウトプット

  • ブログ

    • とりあえず、クオリティ低くても、たくさん書くことと、誰かが読んでることを意識して丁寧に書くようにする(脱メモ)
  • LT

    • チャンスを見つけて挑戦したい(人前で話すの苦手なので、頑張っていきたい)

まとめ

今年も頑張っていきたい。よろしくお願いします!

2018年振り返り

今年の振り返りを簡単に書いた

今年やったこと

  • 時系列に並べてみた
    • 1月 プログラミングスクール
      • html css js php web基礎全般(100h)
    • 2月プログラミングスクール
      • html css js php web基礎全般(100h)
    • 3月 ruby/rails(100h)
      • progate ruby
      • ドットインストール(sinatra,active record)
    • 4月 ruby/rails(100h)
    • 5月 ruby/rails(100h)
      • rails tutorial 1周目
    • 6月 ruby/rails(100h)
      • rails tutorial 2周目
    • 7月 ruby/rails
      • churacari
        • さぼさん、仲嶺さんと一緒にやり始めた趣味プロジェクト
        • 来年はchurakariリリースしたい
    • 8月 ruby/rails
      • churacari
    • 9月 laravel 実務経験
    • 10月 laravel
      • laravelお勉強で個人アプリ作る
    • 11月 laravel 実務経験
    • 12月 laravel 実務経験

今年振り返り

  • railsチュートリアル2週目終わったぐらいから時間計測しなくなったけど多分1000hは学習時間積めた
  • railsチュートリアルと実践的な開発の間にはかなり高い壁があると感じた
  • 今年やったことを時系列並べてみると、頑張ったなあという気持ちと、もっとできたんじゃないかなあという気持ちがあって、もっとできてんじゃないかと思うところとしては、あまりアウトプットできてないところ

    • もっとアウトプットする
      • アウトプットがあるほどインプットできる
      • 一応ブログ書いてるけど、メモ感が強いので、もう少し丁寧に、誰かの参考になるように書く
      • LTとかもっとできるようにする
      • 作ってみた、やってみたの量をもっと増やす
      • コード書いてる時間が単純に少ない問題もある
  • 10月以降はプロジェクトに参加させてもらってめちゃめちゃ勉強になった

    • レビューしてもらえること
      • 個人で学習してるだけだと、それが正しいか判断できないからレビューしてもらえるってことは一番勉強なる
    • チームメンバー間のやりとりをみれる
      • コミュニケーションから学ぶこと多くて、いろいろ教えていただいたり、チームメンバー間のやりとりの内容の意味わからない場合、それが自分に足りてないことで、自分がわかってないことが浮き彫りになるので、良い
    • 実際に動いてるコードを読める
      • 個人学習とか趣味レベルだと仕事で使われてるアプリがどんな感じなのかあまりイメージできなかったけど、実際のコードを見れるってのは勉強になった。最初見たとき、めちゃめちゃクラスがあって、これが実務経験か!!!って気持ちになった
    • 初歩的なところでこけてる
      • めちゃめちゃ初歩的なところでこけるとか度々あって、実務経験積みつつも、基礎力を並行して向上させて行かなきゃいけんなあと感じた
    • 設計むずい
      • コード書き始める前に、まずどういうものを作るのかっていうissueを作ったりするのが、難しいと感じた。どういうポイントを考慮しないといけないのかみたいなところがまだつかめていないと思う
  • もっと言語化
    • ここまで振り返っていて、勉強になったとか、うまくできてない、とかの振り返りがあるけど、それをもう少しちゃんと言語化して、振り返れるようになった方がいいと思ったので、曖昧な言葉で流されないように気をつける
      • 何が勉強になったのか
      • 何ができていないのか
      • そのために何をするのか

まとめ

  • 今年は、アプリケーションを書けるエンジニアになるべくスタートラインに立てるよう、頑張った一年だった。ただ、まだまだ力不足なので来年は今年の三倍頑張りたいと思う。もっとコード書く。
  • あと、プログラミングの勉強を本格的に初めて、同じような目標に向かって頑張ってる仲間もたくさんできたのがよかった。切磋琢磨していけるよう頑張る

条件式を書くときは、明示的にわかりやすくするよう心がける。()をつける

条件式を書くときに、条件が長くなっちゃうと、それがぱっと見どういう条件なのかわからなくなるので、カッコとかつけて、読みやすくするのを心がける。

() を付ける

以下、内容は適当だけど、()で囲んだほうが見やすい。

$user->post_id == $post->id && $user->isPost() || $user->isTask();
($user->post_id == $post->id && $user->isPost()) || $user->isTask();

初歩的過ぎるとこだけど、コードレビューしてもらって、気づけたことで今後気をつける。明示的にわかりやすいを意識して書けるようにしていきたい。() 付けるのは初歩的すぎなので他にも意識する(いろんな人のコード読みつつ、実務経験を積みつつ勉強する!)

演算子の優先度

あと、演算子の使い方で、優先順位があるのちゃんと把握してなかったので気をつける。(or より andのほうが優先度高い!)

演算子の優先順位

http://php.net/manual/ja/language.operators.precedence.php

Laravelの認可処理

最近、Laravelの認可処理を実装する際に学んだことを書きます。

やりたいこと

  • ユーザーの役割に応じて、アクセス制御できるようにしたい。例えば、Adminユーザーだったら編集/削除/登録の操作できるけど、それ以外のユーザーの場合は、参照する権限しかない、みたいなことをできるようにしたい。

  • 認可処理で設けた利用制限について、どの処理に対して、どういう認可の処理が適用されてるかを php artisan route:list の実行結果で、すぐわかるようにしたい(なのでミドルウェアによる認可が必要。コントローラーの各アクションに定義すると、どの処理にどの認可処理が適用されてるか、route:list とかでぱっと見わからない)

  • ただ、Laravel 5.1を使っていて、ミドルウェアで認可できるようにしたいんだけ、5.1では対応してないようだったので、can ミドルウェアを laravel 5.1で使えるようにしたい

やったこと

  • Laravelで用意されてる認可処理、ポリシーを使った
  • Laravel 5.1でcanミドルウェアを使えるようする。Laravel 5.3以降で、Laravelが標準で用意しているcanミドルウェアのファイル(Illuminate/Auth/Middleware/Authorize.php)を5.1環境に配置して使えるようにする
  • ルートパラメーターからミドルウェアインスタンスを渡せるようにした(モデル結合ルート)。それを元にポリシーの認可の条件を書けるようにした

Laravelで用意されてる認可処理、ポリシーを使った

Laravelでは、認可処理が2種類用意されてて、詳細はドキュメント。 https://readouble.com/laravel/5.7/ja/authorization.html

  • 1つの認可処理に名前をつけて利用の可否を決定づけるゲート(Gate)

  • 複数の認可処理を記述できるポリシー(Policy)

これ、どういう状況でゲート使って、どういう状況でポリシー使った方が良いか、ちょっとよくわからなかったんだけど、使い分けとして、特定のリソースの操作に対して、認可する場合はポリシーを使って、グローバルで認可の制限をつけたい場合は、ゲートを使うのが良さそう。今回の場合でいうと、特定のリソースに対しての編集/削除/登録の認可になるので、ポリシーを使って書いた。Gateを使って良くなそうな例として、Gateで認可の条件を書いていくとすると、AuthServiceProviderのbootメソッドに、大量に処理を書いていく可能性があり、パッとみて、どういう制御がかかっているかわかりずらくないっていく懸念がありそう。特定のリソースに対する制御の場合は、ポリシーを使って書いていった方がわかりやすくて良さそう。以下、ポリシーを使う場合のざっくりした流れ。詳しいところはドキュメントに載ってる。

(1) xxxリソースに対応したポリシーを作成する

$ php artisan make:policy xxxxPolicy

(2) ポリシーを登録する。AuthServiceProvider の$policies に作成したポリシークラスと対応するEloquentモデルを記述する

(3) 作成したポリシーに認可する条件を記述する

(4) 作成したポリシーを適用したいアクションやミドルウェアに追加する

これで、ポリシーに記述した条件を満たしていないと、アクセスできない/できる みたいなことができる。この後、ブラウザからアクセスしてみて、403とかになれば良さそう。あと、ポリシーとは関係ないけど、ゲートを定義する際の名前の付け方について、

Gateは"誰が"、"何を", "どう", "できる/出来ない" を扱うもので、"誰が"はログインユーザーが第一引数から渡されることで自明なので "何を", "どう" が大切。なので名前の規則としてV-O (SVO) の形にしましょう。

っていうのがあって、名前のつけ方とかも重要なので気をつける。例えば、Adminユーザーだったら投稿できる。みたいなことを考えてみると、(canのFacadeを利用して書いてみることを考えると)、Admin can update Post になるのでupdate-post って感じで、Gate::defineに定義する。

Laravel 5.1でcanミドルウェアを使えるようにする

やったことは、laravel 5.7の Illuminate/Auth/Middleware/Authorize.php を、そのまま5.1のlaravelで独自ミドルウェアとして定義した。

(1)5.7環境で、Kernel.phpの$routeMiddlewareで定義されてる canミドルウェアで定義されてるAuthorizeクラスを確認

(2)それを、Authorizeを、5.1環境で独自ミドルウェアとして定義する

これで、routingにcanミドルウェアを使えるようになった。

ちょっと話が逸れるかもだけど、この作業してるときちょっと悩んだことについて書くと、Authorizeクラスを持ってくるとき、最初5.3から持ってきていて、それだとうまくいかなかった。それで色々やってて、5.7から持ってくるとうまくいった。これは、5.3から5.7の間でコードが変わってたからなんだけど、どう変わってたかというと、

5.6まではcan middlewareでユーザーがログインしているかをチェックしていた。 $this->auth->authenticate() . 5.6? 5.7? でcan middlewareはguestも受け付けるようになったのでログインしているかどうかはチェックしなくなったらしい。なのでcanでログインしてるかしていないかはチェックしないと思って使えば良いので5.7のコードで問題なさそう

めちゃめちゃ勉強になった。あと、githubの使い方で、ブランチ間の差分を見る方法もを知らなかったので、勉強になった。

Authorize.php 5.3と5.7の差分

github.com

Authorize.phphistory https://github.com/laravel/framework/commits/5.7/src/Illuminate/Auth/Middleware/Authorize.php

ルートパラメーターからミドルウェアインスタンスを渡せるようにした(モデル結合ルート)

ここまでやって、canミドルウェアを使えるようになったし、ポリシーも登録できたんだけど、特定のリソースにアクセスする際の認可をポリシーで、うまく書けていなかった。(例えば、自分が投稿したリソースだったら、アクセスできる。他の人はNG。みたいな認可の処理を書きたい)もう少しいうと、ルートパラメーターのidを元にしたリソースのインスタンスを、ポリシーで定義してる認可の条件で使えるようにしたいけど、どうやってやればいいかわからなかった。結果的には、ドキュメントのLaravel 5.1 HTTPルーティングのモデル結合ルートに書いてあることを定義すると、うまく渡せるようになった。(RouteServiceProvider::bootにモデル結合を定義する)

ドキュメント https://readouble.com/laravel/5.1/ja/routing.html#implicit-binding

これでうまくいったんだけど、ここまでくるのにいろいろと悩んでて、その辺りを書くと、canミドルウェアを使って、routingにポリシーを定義する方法がわからず、めちゃめちゃ悩んだ。今振り返ると、ドキュメントにちゃんと書いてあるんだけど、正しく読めていなかった。その際にやったこととしては、Authorize.phpの処理をxdebugでとめまくって、コードの深いところまで、追いまくって、どこの条件でおかしくなってるのか調べたりした。結果的には、やはりドキュメントに書いてある通りに定義されてなかった(引数の指定の仕方がおかしいなど)のが原因だったことがわかったんだけど、定義元ジャンプしまくって、コードを深く追いまくったおかげで、実際どういう処理が書かれてるのかを知れたので、すごく勉強になったと思う。(追ってる間のコード、ちゃんと読めてないのもあるかと思うので、もう少し読み解けるようなりたい。最後のあたりで make ってやつが出てきたりしたけど、よくわかってなくて、その辺り気になってる)

f:id:shimabukuromeg:20181202143121p:plain

まとめ、次やること

  • ポリシーとゲートに違いとか、Laravelで認可の処理書くの、基本的なとこだけど少し詳しくなれたと思う。
  • コードを追っていくやつ、もう少しやってみる。個人的に、ファサードとかDIとかサービスコンテナとかいまいちよくわかってなくて、コード追うやつやりながら、ドキュメントとか読んだりすると理解できそうな気がしてる。あんまりよくわかってないけど。

Laravel学習方法

最近laravel勉強してて、学習するのに重要だなあと思ったポイント備忘録。

  • xdebug
  • Laravelのソースコードを追う
  • Laravelの公式ドキュメント読む
  • PHPのドキュメント読む
  • Laravel本読む
  • 他のlaravelプロジェクトのソースを読む

qiita.com

特にxdebugで処理を止めながら、コードを深いところまで読んでみるってのが重要な気がしてて、そのあとにドキュメントを見ると、ドキュメントがかなり読みやすい感じがありました。それに加えて、Laravel本を参考に色々手を動かしてみるとか、ほかのLaravelプロジェクトを読むとかまで手を伸ばせたら良さそう。