やったこと・書いたもの{2017}

2017年に投げたPRとか(ここやqiita以外で)書いたブログのまとめ

12月

cakephp/cakephp

cakephp関連プラグイン

会社のブログ

10月

9月

6月


番外

ベタープログラマ

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

読みました。こういう系は「本棚においておいて、時折読み返すべき」な感じ。会社の人に「(こういうの)好きそう」と言われて気になっていたので、昨日本屋に行く用事があったのでついでに買ってみて読んだ。

ここ1年、特に夏以降は自身や周囲に対して随分と散々に思う面も多かった年だったので、第Ⅳ-Ⅴ部は読んでて辛い面もあった。理想だよね、そうありたいよなぁ・・ていう。
また後になって(レベルが上って)読んだら違う感想を抱くだろうけど、今の時点で琴線に触れた箇所などを書き出してみようかな

1章 コードを気にかける / 2章 見かけのよい状態を維持する

(p2) 優れたコードは匠の職人が注意深く作り出します。だらしないプログラマが軽率に作るものではありませんし、自称コーディング導師が神秘的に作るものでもありません。

弛みなき努力が〜・・

(p11) 散文を書くようにコードを書いてください。 章、段落、文に分解し、同じようなものをまとめます。異なるものは分離してください。

.

(p11) 最も重要な情報を最後ではなく最初に書きます。APIが実用的順序で読めるようにしてください。クラス定義の先頭に読者が気にするものを書いてください。すなわちわ、すべてのpublilの情報はprivateの情報の前に書きます。オブジェクトの生成は、オブジェクトの使用の前に書きます。

自分は結構「空白行」とか「宣言位置」とか気になる方なので、ただこれは「自転車置き場の議論」に陥るだろうから熱心に説いたり律したりするものでもないだろうっていう部分でもあるので、自分が新たにコードを書いている時以外は(たまに指摘したり手を出したりする事くらいはあっても)スルーor我慢する部分。
なので、こういう「言ってくれる」人がいるの嬉しいし、「散文を書くように」は普段から思っている感覚。

(p20) たるんだロジックは、たるんだ心の現れです。あるいは、少なくともロジック構造の理解が貧弱であることの表れです。

良いコードは「筋肉質な」「緊密度の高い」みたいな感覚があって、書く/読むときは、それこそ(余白も含め)1行ごとに意味や存在理由を持つようなコーディングを意識してるのだけど、「たるんだ心の現れ」ってまでバッサリ行くとw

6章 航路を航行する / 10章 バグ狩り / 11章 テストの時代

(p60) f:id:o0h:20171230231040p:plain

関連性とかがしっかりしていれば、「どこから読んで」「なにがあるか」がわかりやすいって意味で地図!

(P83) コンピュータが理解できるコードは誰でも書けます。人が理解できるコードを書くのが優れたプログラマです

.

(p100) ひどいテストはお荷物になります。つまり、資産ではなく負債です。

.

(p102) SUTの内部の実装詳細に関する知識、すなわち「ホワイトボックス」の知識に依存しているテスト(これは、テストを変更せずに実装の変更ができないことを意味します。)

.

(p102) f:id:o0h:20171230234732p:plain ここのテストでは慣習的に、何らかの準備を行い、それから操作を行い、そして最後に結果を検証します。これは アレンジ・アクト・アサートパターン として広く知られています。

テストコードの「見た目」について触れているセクション。この本の言い方でいうと「言い方」なんだけど、写真の通りで。なるほど「パラグラフ」が美しく分かれているなー。

(p106) モックマニアとはひどいテストコードにある別の臭いであり、SUTの構造が正しくないことを示しています。

12章 複雑さに対処する

(p115) 表面的には単純なモデルに見えます。一つの親オブジェクトが「システム」を表しており、子オブジェクトの全てを作成しています。(中略)既知のアンチパターンである「分散した自己」だと私に説明してくれました。

循環的なグラフをなくす、というのが大事。そこからさらに、参照(主従)の関係を一方方向的にする〜て感じかな?

14章 ソフトウェア開発とは / 16章 単純に保つ / 18章 変わらないものはない

(p141) ミケランジェロのように、あなたは問題空間の複雑さを減らして、目指す美しいコードが現れるまで複雑さを取り除いていますか。

(作る〜ってより)「取り除く」作業なんだ、っていうのはたまに思う

(p154) 単純な設計、使うのが容易、誤用を防ぐ、大きさが重要、短いコードパス、安定性、単純なコード行、単純に保ち愚かにならない、想定は単純さを減少させる、早まった最適化を避ける、十分に単純、単純な結論

これはそういうセンテンスがあったわけではないけど、この章の見出し群が良かった!

(p155) 単純な設計の確かなしるしは、大量の書き直しをせずに機能を追加したり拡張したりできることです。

時折「こうなることが丸で予め分かっていたかのような、すげーシンプルに使い倒せる、まさに!というコードだ」て感じさせる場面がある。こういう時はニヤニヤするなーって

(p156) コードが単純に見えるかどうかは、個人的な好みと慣れによる部分が多いです。人によっては、ある種のレイアウトのイデオムがコードを明瞭にするのに役立つと考えています。また、逆に邪魔であると考えている人もいます。

「見慣れ」の問題は本当にある、そういう意味で「いかに普段から同じコードを一緒に読んでいるか」というのはチーム力になる気がするな。もちろん「良いコード」の方が良いので、そうかフレームワークのコードリーディングとかを共同でやるのはいいのかもねー

(p165) かつては疑わしかった設計が、突然申し分のないものと見なされ、変更できないものになります。

古いコードを神格化してはならない!大胆な改修は必要・・・正義ではないけど、ただビビっちゃいけないと思うし禁忌でもないし、素直に(今のレベルで)コードやシステムに対して疑問の眼差しを向け続けるのは必要。と思う

(p169) 私達は、変更を推奨するコードを目指して努力しています。それは、形状と意図を表しているコードであり、単純さ、明解さ、首尾一貫していることを介して修正を推奨しているコードです。副作用を持つコードは、変更に対してもろいので避けます。二つのことを行なっている関数を目にしたら、二つの部分に分けてください。暗黙の事柄を明らかにしてください。頑固な結合と不必要な煩雑さん避けてください。

24章 学びを愛して生きる / 26章 チャレンジを楽しむ / 27章 停滞を避ける

(p233) 「単純に説明できないのであれば、それはきちんとは理解していない」 (中略) その話題について聞いたことがあるかもしれませんが、あなたの知識の限界がどこまでかは分かっていないのです。教えることは、その境界を押し広げます。

.

(p246) あなたが向上しているのがはっきりと自分で分かるようにしてください。達成したことを知るためにソースコントロールシステムのログをレビューしてください。

.

(p246) 車輪を再発明する心配をしないでください。すでに過去に行われたことを書いてください。 (中略) (あなたの実装を実際に使うことに関しては注意してください)

.

(p249) しかし、安全地帯は有害な場所です。そこは、罠です。安全な生活とは、学ぶことも、進歩することも、さらによくなることもないということです。安全地帯は、停滞する場所です。あなたは、すぐに新たな若い開発者に取って代えられます。安全地帯は老廃するための高速道路です。

36章 遠慮なく話す / 37章 多くのマニフェスト

(>p326) コードは書かれるよりも、人によって読まれることが多いことを忘れないでください。したがって、コードは書くことではなく、読むことに対して最適化されるべきです。

.

(p336)f:id:o0h:20171230235858p:plain

ここの結論は、ジョークです。 と、わざわざ脚注で書いてある。

しかし何かの議論をしている時の自分を振り返ると、なかなかこの「結論」から遠くない振る舞いをしてしまってはいないか・・と、バツが悪い!!俯瞰せねば、達観せねばということになる。 特に刺さるのは「特定の状況に個別に合わせるよりも、固定された不変な考えがあることを信じます。」てやつだなぁ。プラクティス大事、原理は大事なんだけど「賢く」やらないと。バランス。取り組んでいるのはあくまで現在進行形の・・・

(>p337) マニフェストが良い情報を含んでいて、教養としてではなく、会話の火つけとして使われる時には役立ちます。

この前のページに「マニフェストは、原則の大まかな概要に過ぎず、「一つの正しい道」ではありません。」と書いてある。 しっかり自分の中に「原則」を持つことが大事、それでいて固執し過ぎず柔軟にいることも大事・・て感じかなぁ 古びないようにすること


総じて

これ分からないときにいくら読んでも、理解できないんだろうな。もっというと、今「わかった」って思っても後から読み直して「わかっていなかったな」って体験がすごくありそう。
書いて有ることは違和感なかったから、読んでて痛かった部分を中心に思い出すようにしたいのう

ペットプロジェクト

という単語があるらしい。

https://en.wiktionary.org/wiki/pet_project

A project, activity or goal pursued as a personal favorite, rather than because it is generally accepted as necessary or important.

英和辞典系のサイトを見ると、「長年あたためて来た計画」って出てくるけど。 「必要だから」系のものではなく、「ただ己の好きな!!」みたいなニュアンスが強い感じかな。それが僕には楽しかったから!

読んでいる本に何度も出てきて知ったのだけど、印象的な言葉で気に入ったな。

Advent Calendar 0217

12月ぜんっぜん書いてないな!!って思ったので、

f:id:o0h:20171224192312p:plain

その反証と言うか言い訳と言うか・・・で、諸所に書いたものをまとめとして残しておく!!というもの。
今月はAdvent Calendarにも参加していたので、このブログで書くような雑な話ってより「他人が読むかもしれない」フォーカスで書いたのが4本。疲れた・・・w
もう12月25日を過ぎたので、それらを連ねてみる

qiita.com

qiita.com

BigQueryのやつは、書いていて本当に疲れた・・・しかしながら自分としても割と直近で使っていたHotな知識だったし、そこら辺を改めて丁寧に理解できたなっていう点では甲斐はあった

composer installは早くならないけど意外とそこまで困らないのかもなって思った話

続き的なもの。 この前、「うまくhackしたらインストール早くなるの?」という話を書いて見た。

魅力あるし、単純に勉強としてcomposerの挙動を知るぞ!!は面白そうなのだけど、「現実問題としてほしいかい?」がある。
あー、まぁ、ほしいけど、「何も知らないところからcomposerのプラグインを書く(大変そう)」事のコストと、「今直面している問題の所在と大きさは?」のバランス。

で、結論として、「意外と困ってないかもな」となった。

この辺りは、職場での開発・デプロイフローがどうなっているか?という話次第だった。*1

  • dockerで、vendor含めてprojectのソースコードをホストから共有する形で食わせながら、処理はコンテナ側でやる
  • デプロイは、travis-ci上でビルドして配布

という現状。

で、「遅くて困る」かどうかは

  • composerはなぜ遅いのか、何をクリアすれば遅さが気にならなくなるのか
  • composerの遅さが気にならなくなるのはどんな場面か
  • 開発時、デプロイ時に問題となるか(回避できるか)

という複合だと思う

なんで遅いの

については、色々ありそうだ・・ ただ今回の話は、「各パッケージを並列DLできたら解消し得る問題」に絞りたい。
そうなると、「DLの遅さ」だ。*2

で、これに関しては標準のキャッシュを活かせればほぼ解決する。・・全てではないが、まぁかなり嬉しいレベルで軽減する。

いつ問題になるの

  1. 新規にinstallするとき
  2. .lockを利用してinstallするとき
  3. requireするとき
  4. updateするとき

が、「何かパッケージを落としてくるとき」なので、影響を受ける。
余談だが、ただし2に関しては「依存状態の解消を行う」ような処理は完了している!という状況といって差し支えないと思う。そのため、コンフリクトする可能性を前提として排除できるからパラで落として来て問題なくない?というのが前に書いた内容だった。

開発時やデプロイ時に問題となるか

「遅さやばい」となのはキャッシュがきかない時で、「日常的に行う」のは2になると思う。
もっというと、ローカルでの開発において(ブランチの切り替えやdocker imageのビルドに比べたら)composer installなんて「やらないで済むならやらないで済ませたい(必然性が低い)」ものではないか。

なので、「問題となるか否か」は「キャッシュがきけば問題ない」から「キャッシュが効く場面を最大化できれば実質解決する」はず。

デプロイについて

travis-ci上でdocker imageをビルドしているという話をしました。
で、ci上にキャッシュを残す機能がある。.travis.ymlに caches/directoriesを指定してあげると、そのディレクトリがピルドプロセスをまたいで共有されるようになるので、$COMPOSER_HOME/cache を対象にしてあげれば良い。そうすることで、「いちいちpackagis→githubからダウンロードしてこないで済む」ことになる。もちろんvendorディレクトリごとキャッシュしたりもできるし。

これを利用して、CMD等でコンテナに作用するのではなく、ビルド時にcomposer installをするよな形にして、「installは1回だけに、しかもその1回を高速で完了させる」という要望は叶えられる

localでの開発時

これも「毎回クリーンインストールはしないよね・・・」という話は大きい。
基本的な戦略は同じで、「キャッシュを使いまわせるようにする」なのだが、imageに含めるよりかはマウントする形でホストからコンテナに渡す方が自然な感じがする。まぁ共有すゆのは「キャッシュじゃなくてvendor自体」になると思うので、composer.lockからのinstallをかけところで所有済みパッケージとのdiffがない!となり、そもそもキャッシュを参照しにいかないで済む場面が大半な気はする。

ということで

自分の今触れている状況においては、composer install自体はそんなに問題になっていなさそうだなーというかんそ

*1:個人では今は複雑なアプリケーション書いていないので!

*2:そういう意味だと、「ルートパッケージの並行DLは許容しない」「各パッケージごとに、依存パッケージはパラレルで落としてくる」みたいな制御が出来たら効果高いのでは・・

composer installをめっちゃ早くできるのかな?

という話を、社内でしておりました。
「そういえばprestissimoって本体に取り込まれる?とかって話なかったっけ」てな話題となり、PR見てみたら「難がありそ」と。

それが I think that it’s difficult to support conflict, suggest, provide and replace dependencies.かな?と思った。。

なるほどな〜たしかにな〜難しそう〜〜と思いつつ、それにしたって「composer isntallがめっちゃ早くなるよ」は魅力。

逆に言うと、「インストールの時だけならパラレルでDLしても大丈夫じゃない?」って言う気もしたのでした。
composerでパッケージの取り込みを行うのは、主に

  1. install
  2. require
  3. update

であって、このうち「1」については「依存パッケージの衝突が起きていないか」というチェックは、すでに終わっているフェーズにあるのでは? と。 (雑な見方の気もする・・・

あまりcomposerの内部処理を追ったことがないのだけど、「installのときだけこのプラグインを有効にする!」ということができれば、もしかしたら大丈夫だったりするのかなー。

どっかで実験してみよ

Configure::readOrFail()っていうのがあって便利だからみんなで使おう

CakePHPorFailシリーズ

Configure に、定数ぽい値を持たせていたりしている。

※ イミュータブルじゃなくなるし、constとしたほうが良いのでない?という観点はあります。
※ 「いや、stageによって異なる値を上書きしたりしたいじゃん!」という声もありますが、それはdotenvや環境変数でどうにかなりそうな問題
※ まぁ色々あって、Configure::write() に寄せているよ!というお話をスタート地点とさせていただきます。

直接 ::write()メソッドを用いて書き込む〜というよりかは、 config/app.php のような「設定ファイル」を介在させて食わせて、という風な。

「絶対に設定しないと行けない」という制約

例えば、cakephp/appを見てみると、 App.encodingenv('APP_ENCODING', 'UTF-8') と書かれていたりするじゃないですか。 みたいな感じで、

  1. 環境変数として値を用意して
  2. Configureに食わせる

という利用シーンはあると思います*1
その中には、「どの環境においても、絶対に設定されていなければ困る」というものもあると思うのです。

Configure::read() とすると、「キーが存在しなかった場合はnull」を返します。
場合によっては、「nullのまま進んでは困る」と。
このときに役立つのがConfigure::readOrFail() です。 Class Cake\Core\Configure | CakePHP 3.5

keyが未設定、もしくはされているがnullいなっている 場合に、RuntimeExceptionを投げるようになります。
read()になっている箇所を置き換えるだけで、「ちょっと事故った、しかし事故が大きくなりすぎる前に気付く」ことがしやすくなります。

まだまだあるぞ! orFail()シリーズで堅牢なプログラミング

良きようにfail fastになるな、という利点です。 Configure::read() 以外にも、 orFail()なメソッドはちょこちょこあります。

f:id:o0h:20171124221702p:plain

  • SELECTを試みたレコードが1件もなかった場合に例外を投げる Query::firstOrFail()
  • saveを試みて(validation error/ domain rule violationで)保存ができなかった場合に例外を投げる Table::saveOrFail()
  • deleteを試みて、(entityにPKがない / entityが「isNew()」である / domain rule violationで)削除ができなかった場合に例外を投げる Table::deleteOrFail()

こういった顔ぶれです。 便利ですね😁

*1:最も、「読み出せなかったときのために初期値を用意して扱う」というのが良いのかもしれませんが・・