2023年に書いたコード

「2023年のふりかえり」ではPythonやJavaScriptのコーディングの話ばかり出てくるけど、これって今年全体から見ると1割以下だなぁと思ったのでGitHubのメトリクスを見ながら振り返ることにした

laiso.hatenablog.com

言語ごとのコミット数

vn7n24fzkq/github-profile-summary-cardsというのが生成してくれたグラフ

profile-summary-card-output

Python はデータ分析サーバーをFastAPIで書いてるのでその分と、Swiftは記憶にない

他の大部分はLaravel を使った複数のプロジェクトになる

PHPの話

PHPの仕事が欲しいわけではないのであんまりPHP書ける人ブランディングをしてこなかったけど9割はPHPやテンプレートHTMLを粛々と書いてると思う

レガシー管理画面アーキテクチャなのでReactやVueどころかjQueryでフロントエンドの処理書くこともない

ただLaravelやPHPに存在する機能を積極的に使おうとはしていて常にlatestなバージョンに追従している

PHP8はmatch構文が他言語みたいに書けて面白くて、enumも外部ライブラリなしで導入できる

Type declarationsはボーイスカウトルールで立ち入った区画を整備して帰っていく方針で付けてる

型の不一致はテスト時にTypeError吐いてくれることもあれば、PHPStormがコーディング時に教えてくれる時もある

Laravelの話

Laravelの諸機能は自作のオニオンアーキテクチャみたいなものを定義しなくてもある程度レールに乗っていくだけでバリデーションと権限管理をコントローラーから分離してくれたり、Active RecordでDBとモデルを分離したり、DIコンテナで実行時に実装を差し替えられたり、などの知られたデザインパターンを適用していってくれて、僕のような片手間PHPerに都合がいい

お気に入りはEventsのオブザーバーパタンで、1対多関係の非同期処理への派生が作りやすい

laravel.com

処理を追うのに知識がいるトレードオフがあるけど全部手続き処理を書くより単純になるなら使う、ぐらいのバランスで採用してる

Laravelの標準機能ならなんでも良いのかといえば、そういうわけでもなくEloquentのAPI Resource(Railsのjbuilderみたいなやつ)などは ネストの奥の方で愚直にJSONシリアライズループしてN+1な手続きを発生させて遅くなっていることがプロファイラみてると発見できるので普通の手で書いたforループで置き換えたりしてる

開発手法の話

普段の機能実装のフローとしてはいきなりDB設計とかテストコードとかを書き始めるわけなくて、最初は単一ファイルにトランザクションスクリプト(ビジネスロジックをベタ書きしたもの)を書きはじめる

Railsだとrails runnerがあるけどLaravelだとないので、make:commandで適当なエントリーポイントを作って、そこに機能開発に必要な画面の裏側の処理だけ先に作る

この時点ではテストファーストもしてないしUIの実装も全く手をつけていない

コーディングで設計の作業をしているイメージ

以前はテストケース内でこれをやっていたが設計が定まらないとテストコードの設計も決まらないのでこうなった

全体の手順としてはビジネスロジック→DB設計→モデル→ビュー→コントローラーの順

  1. Commandで実行可能なトランザクションスクリプトを作成
    1. これによってデバッガを使いながらコーディングができる。Webアプリケーションの中に書き始めると手動操作が発生してしまうがスクリプトではじめるとショートカットキーで実行できるのでイテレーションサイクルが早められる
  2. DBに変更が必要ならこの時点でmigrationを追加
    1. (1)でユースケースを先に書いてるのでスキーマをそれにあわせて発行したいSQL文からtableをつくる
  3. DB入出力を完成させる。これでDB設計→モデルまで一旦終ったことになる
  4. このデータをモデルとして、(1)で書いたコードをコントローラーに持ってきて、画面に表示するビューのUI部分を作る
    1. 場合によってはこの段階でプロトタイプにしてUXレビューにまわす(抽象的な仕様だと手戻りがだいたい発生する)
    2. ビューを定義した時点で新たな事実が分かって前提が変わるので(2)をやりなおしたりする。マージ後に手戻りさせるとマイグレーションが2つになってしまうけどこの段階ならまとめられる
  5. 次にビュー→コントローラーのフェーズに移る。(1)で書いたコードをパラメータと関数に分離してパラメータはリクエストから入力+バリデーションするように変更
  6. 抽出した関数を任意のモデルに移動。複数のモデル(≠DB table)を横断する処理はChatGPTに名前を考えてもらって単一責務な専用のクラスにする
    1. 自分で命名するとHogeModelServiceみたいな名前になりがち
  7. (6)の自動テストを書く
  8. テストで実装の差し替えが必要になったらinterface定義してDIで差し替える

上記は新機能開発というか更地に機能を建てる時の手順なんですけど、機能改修の時も4-5あたりから合流して同じフローに乗せてる

テストの話

テストコードの方針についてもボーイスカウトルールで積み重ねていっているんだけど、とくに重視しているのはバグの再現コードをテストにしてリグレッションテストを入れるという作業

バグを修正しないといけないという状況は=ユーザーにとって重要なコードということがはっきりしているので、テストで保護する価値も高いと考えている

ユニットテストはコードの分離さえ積み重ねていけば前進できるけど、E2Eな統合テストはコンテキストが多用でテストケース1つの価値が低くなることもあるので、無理せずそういうテストの保守はせず消して手動テストケースのスプレッドシートに移してる

スプレッドシート上で言語化できるってことは自動化できるやろと当初は思っていたんですけど、そううまくはいかなかった

ということは私達は言語化していないことを暗黙的に検証してることが多いので、運用しながら監視などのアプローチをそろそろ加えるべきなのかもしれない

Codecovで計測してる数値以下のように増加が見込めたが「内部品質向上のためにN%達成」という目標は立てずに「前期N%増減→それによって何か影響あったかなかったか」という指標として見てる

codecov

ただこれらの開発方針はソロ開発している都合で好きなようにやっている反面があり、分業してたりチーム開発でナレッジを運用しつつだったりすると事情が変わってくるのかもしれない

たとえば世の中によく広まっているEntityとRepositoryを作ってビジネスの語彙で内部DSLでユースケースを記述して—— っていう戦略を最初は真似してやってみていた

この戦略はファイルが増えるぶん複数人で作業しても衝突しない反面、EntityがDBのtableの定義に寄せられて開発ラインごとに新規tableを定義してファイル分割するようなドメインモデル貧血症問題を起こしがちだった

それを自分たちの環境で何が必要なのかを自己認識していった結果できたのが上記の1.〜のフローになってる

エンジニア10倍いたらそんな過程踏まずに一気にリノベしてマイクロサービス化していたかもしれない

GitHub上での活動

以下はtarao/oss-contributionsが生成してくれた集計結果*1

「LMQL v0.0.6.1で日本語が通るようになった」 の時のプルリクエストがあるだけで、とくに目立った活動はしていないことが分かった

zenn.dev

Contributors1
Repositories2
Commits31
PRs 3
Reviews
Issues 1
1 commit 2 PRs
eth-sri/lmql
★2,868
1 commit 1 PR
Pull requests
jzillmann/pdf-to-markdown
★884
1 PR
Pull requests

ついでに2021-2022年の集計するのも忘れてたので出してみた

2021年はVercelやAWS Amplifyを使ったアーキテクチャの研究をしていったっぽいが、2022年は記憶にも記録にも残ってない

2021年

Contributors1
Repositories3
Commits17
PRs 3
Reviews
Issues 1
1 commit 3 PRs 1 issue
vercel/vercel
★11,669
1 PR
Pull requests
serverless-nextjs/serverless-next.js
★4,321
1 commit 1 PR 1 issue
Pull requests
Issues
serverless/blog
★182
1 PR
Pull requests

2022年

Contributors
Repositories
Commits51
PRs 1
Reviews
Issues 3

*1:tarao/oss-contributions: 個人/組織のOSS貢献を可視化する https://tarao.hatenablog.com/entry/2021/06/14/160248