のんラボ

リリース内容を小さくしたらいろんなメリットがあった話

2020/07/26 2020/07/29

リリース内容を小さくしたらいろんなメリットがあった話 こんにちは。Nonです。今回はリリースする内容を小さくしたら色々なメリットがあった話をしようと思います。 とは言っても、すでにdevsOpsやマイクロサービスが浸透してきているので、リリース内容が小さい方が良いというのは知っているかもしれません。 ここでは、やっぱりやってよかったよねという話にしていきたいと思っています。 1. リリースを小さくしたらバグが減った リリースを小さくするということは実装する機能の数が減るということです。ということは、制限時間内に(納期までに)開発者が向けるべき関心事が減るということですね。 正直、この内容をシェアしたくてこの記事を書いたまであります。 リリースが小さくなったので、リリースまでの納期は短くなります。しかし、自分が注力すべき内容が小さいので、その全てに全力を注ぐ事ができます。そのおかげで、明らかに今までのコードより品質が高くなりました。QAチームからのフィードバックも減り、実装コストだけではなくて全体のコストも減りました。 やはりバグ原因での手戻りが少ないとストレスも減って進捗がいい方向に向いていくことを実感することができました。 2. リリースを小さくしたらマネジメントしやすくなった 1と同様に、関心事が減るので、把握すべき進捗の内容が減りました。おかげで今までおざなりになっていたプロジェクトの進捗の把握もかなりしっかりできて、ほぼ計画どおりのプロセスを踏むことができました。 (この案件では私が実装兼PMみたいな感じ) こうなると、マネジメントする側にもかなりのメリットがアルのではないでしょうか?進捗管理という事務作業が一気に減ることになりますんので、本来PMがすべき真の意味のプロジェクトマネジメントを遂行することができます。 追記するとPMはプロジェクトの進捗管理をするだけの役職ではないと個人的に思っています。 このことに関しては賛否あるかもしれません。 私もPMについてしっかりと勉強できているわけではないので、おかしな点があるかもしれません。簡単に書くとPMは POから欲しいと言われた機能を吟味し、取捨選択する 機能についてメンバーに割り当てる 機能から更に分割されるであろうタスクはメンバーが決めるもの 機能について終了日のあたりをつけ、QAとの連携をとる リリースにあたって他のプロダクトとの影響について調査する この辺ではないかと思っています。 何やら一般的にはスケジュールばかりに目が行っていますが、どう考えてもそれは副産物で、メンバーとの折衝、他のチームとの折衝こそがPMの本来の仕事のはずです。(だからコミュ力が求められるのだと思います。) 上述した内容を遂行した結果、たまたま進捗管理をしていたというだけだと思います。 逆に言えば、他の影響範囲との摩擦がなければリリース日なんて「完成した日」になると思ってます。 3. リリースを小さくしたらスピードが上がった(たくさんのピリオドを打てる) マラソンを走るスタイルで、ダラダラと開発をしていたのが、パッと開発してストップ、パッと開発してストップ、の連続になりました。メリハリが効いてピリオドも明確に打てる。何かあったときのトラブルにも強い印象になりました。 ピリオドを打てるというのはとても大きくて、終わったら前回の反省をすることができます。対して、長ーいスパンで開発すると、その途中で反省会をしてもあまり意味がないように思えます(経験)。 長ーいこと開発を続けるよりも、キチンとピリオドを打って、終わったよということを表明できるのはメンタル的にも優しい気がしました。 最後に リリース内容が大砲の弾のように大きくて必死こいて弾を運んで、外したらOUT。みたいなのより、リリース内容は小さくして気軽にパパパパっと打てるサブマシンガン的な手法の方が手軽でいいです。 小さい分、何回も繰り返してリリースすればいいですし。 この取り組みは今後も続けていきたいです。 今回は私の主観が多めでした。 次回は何書こうかまだ決めてないです。でも記事にはします。 その時はよしなに。 .

車輪の再発明は悪なのか?

2020/07/24 2020/07/24

プログラマが知るべき97のこと こんにちは。Nonです。本日はプログラマが知るべき97のことを読んでいてこれ「いいな」と思った箇所について書いてみようと思います。 こちらの書籍はとても有名なので、既読の方もいらっしゃるかもしれません。 そういう方は復習というか、内容を思い出したり、私の意見と違うところや共感できるところを探していただければ幸いです。 プログラミング業界では車輪の再発明は悪と見られがち? 一度作成されたコードを再作成することはしばしば嫌がられる傾向にあるのがプログラミング業界です。例えば、Bootstrapを導入しているプロダクトでモーダルを表示する処理を自作する意味はあまりないでしょう。 もしあるとすれば、 Bootstrap依存(jQuery依存)をしたくない すでにある機能のテストを再度したくない などでしょうか? もちろん、その中にはDry原則もあるでしょうが、Dry原則とはそもそも Don't Repeat Yourself なので、自分自身のコードの中で同じような処理を作成することはアンチパターンだよってことを示していると思います。 あとはOSSにあるツールなどを知っているパターンでしょうか。 OSSに実装したい機能とほぼ同じものがある場合、そちらを利用したほうが遥かに効率がいいからです。 では車輪の再発明にメリットがあるときはどのようなとき? しかし、実は私は車輪発明は大好きです。何故かというと車輪の再発明はとても勉強になるからです。 車輪の再発明で得られるものは多いです。 たとえば、モーダルを表示するために必要な技術は何か?表示するときにアニメーションを入れるにはどうすれば良いのか?このようなことを勉強するにはうってつけです。 更にその機能の構造や動きを理解することで、その機能を利用するときに気をつけるべきことやどのように利用すれば気持ちよく動作するかがわかります。 独自フレームワークは嫌われやすい 似たような話に独自フレームワークがあります。 今大抵のプログラミング言語にはフレームワークがあります。 黎明期の頃はフレームワークが充実していなかったので独自フレームワークを作成することがはやっていましたが、今では特殊な案件以外ではありえません。 しかし、独自フレームワークを作った人はフレームワークの構造を理解しています。 例えばWEB用のフレームワークを作成した人はリクエストとレスポンスを捌く部分についてよく知っているので、どう捌けば良いのか、どのように作れば良いのかを(作ったことがない人より)知っていることでしょう。 もしかしたら、独自フレームワークを作ったことがある人こそ、人気のフレームワークの便利さを一番理解しているのかもしれません。 最後に 実際のプロジェクトで何も考えずにパッケージが導入されていることはよくありますし、用途が重複したパッケージが導入されているものも見たことがあります。 これは、パッケージの特性を理解しないまま「ただできるから」、それだけの理由で導入したのでしょう。 そういうことが無いように、すでにできている車輪を使うだけでなく、その構造と使用方法を理解した上で使えるようになりたいですね。そしてそのためには車輪を自分でも作れる必要があるのではないでしょうか? ここまで書いておいてなんですが、私個人の意見です。 次回もプログラマが知るべき97のことを読んで記事にしようかなと思っています。 その時はよしなに。 .

ユビキタス言語を重視する

2020/07/13 2020/07/13

プログラマが知るべき97のこと こんにちは。Nonです。本日はプログラマが知るべき97のことを読んでいてこれ「いいな」と思った箇所について書いてみようと思います。 こちらの書籍はとても有名なので、既読の方もいらっしゃるかもしれません。 そういう方は復習というか、内容を思い出したり、私の意見と違うところや共感できるところを探していただければ幸いです。 ドメインの言葉を使ったコード 突然ですが、DDDではユビキタス言語という業務上の言語を反映することが大事だよ。ということが言われています。 ユビキタス言語ってなに? ユビキタス言語というのは、プログラミング設計をする上で、開発者だけでなくその他のステークホルダーとの共有言語のことを指します。 例えば、荷物の運送管理システムを使用する時、開発者はよくユーザーという言葉を利用しますが、ステークホルダーは運転手という言葉を利用するとき、やはりシステムでも運転手という言葉を利用する方がいいでしょう。 そして、開発者が運転手という言葉を利用するというのはコードにも反映するということになります。 例えばユーザーが荷物を運ぶ処理を持っていたとすると、 <?php class Driver { /** * @var int */ private $id; /** * @var string */ private $name; public function __construct(int $id, string $name) { $this->id = $id; $this->name = $name; } /** * @param Luggage $luggage * @return void */ public function transferLuggage(Luggage $luggage) { // 荷物を運ぶ処理 } } となります。クラス名はUserではなくDriverとなりますね。 ではログイン処理ではどうなるでしょうか。 境界付けられたコンテキストの観点からみると、ログイン処理は業務知識とはまた違うドメインになりますので、この場合はDriver->login()ではなく、User->login()の方がいいでしょう。 このように、業務知識内の言葉を利用することで、プログラムコードと実際にミーティングなどで利用される言葉の乖離を防ぐことで、ユースケースの齟齬、つまりユーザーとの誤解を避けるために作成され、使用する言葉のことを指します。 プログラムコードに仕様を書き込むとは? こちらもしばしば見かける内容です。 仕様書を作成しないという意味ではありませんが、できるだけプログラムコードに仕様を反映するということは結構前から言われていたように思います。 キーワードは私の知る限り3点。 ビジネスロジック 抽象クラス ユビキタス言語 でしょうか。 ビジネスロジックで仕様をコードに表す ビジネスロジックで仕様をコードに表すとは何か?2020年に突入した今なら、すでにご存知の方もたくさんいらっしゃるでしょう。 私はこれまで色々なプロジェクトを経験してきましたが、とにかく、コントローラーだけで実装を終了していたり、プログラムコードの示す目的がコードに反映されていないコードをたくさん見ました。 だから、「コードの仕様を先輩に聞いたり」、「なぜ、このコードが必要なのかを議論する」必要があったのです。 試しに例を作成してみました。 class TransactionController { public function store(Request $request) { // バリデーション処理など $user = Auth::user(); Transaction::create([ 'user_id' => $user->id(), 'product_name' => $request->get('name'), 'product_price' => $request->get('price'), ]); // 処理 } } これが示す仕様、ユースケースをこのコードから読み取れるでしょうか?簡単な例なので、もしやわかる方もいらっしゃるかもしれません。しかし、なんとなくTransaction、取引を作成する処理だとわかるくらいでしょうか? このコードは改善が必要に思います。 class TransactionController { /** * @var BuyProductInterface */ private $useCase; public function __construct(BuyProductInterface $useCase) { $this->useCase = $useCase; } public function create(Request $request) { $this->useCase->process(); } } class BuyProduct { /** * @var CustomerService */ private $customerService; public function __construct(CustomerService $customerService) { $this->customerService = $customerService; } public function process() { // $customer, $productの定義 $this->customerService->buy($customer, $product); } } class CustomerService { /** * @var TransactionRepositoryInterface */ private $transaction; public function __construct(TransactionRepositoryInterface $transaction) { $this->transaction = $transaction; } /** * @param Product $luggage * @return void */ public function buy(Customer $customer, Product $product) { // 商品を購入する処理 } } ここまで書けば先程より伝わるでしょうか? このプロジェクトの示す取引を作成するというのはお客様が商品を購入することを示していたのです。 このようにビジネスロジックそのものをコントローラーに直接記述してはいけません。とても無機質なコードになり、コードを業務に置き換える作業がとても大変で開発者にとってストレスがかかります。 このような現象をプログラムコードを業務へ翻訳するとか言ったりしますね。 その翻訳作業を無くすために、翻訳してある状態でコードにしておくことが重要です。業務に関する知識をビジネスロジックとして別に切り出し、そこでは業務に関する言葉などを利用することで、コードに仕様を表す事ができます。 抽象クラス 以前、ドメイン駆動設計の読書会についての記事で、「抽象に依存せよ」といった旨について記事にしたことがありますが、抽象クラスの役割は依存関係の解消だけではありません。仕様をコードに表すという観点からも有用です。 もしかしたら誤解を生んでしまうかもしれませんが、抽象クラスはそのオブジェクト(つまり業務での登場人物)のできることリストと言い換えることも出来ます。 1番はじめに使用した運転手の例で作成してみましょう。 interface Driver { public function transferLuggage(Luggage $luggage): void; public function startRest(DateTimeInterface $from): void; public function endRest(DateTimeInterface $to): void; public function moveBase(Base $base): self; } (実際の業務を無視して、)とにかく運転手ができそうなことをリストにしてみました。 運転手ができそうなことがこの抽象クラスからわかるかと思います。 開発者はこのクラスから、「このドメイン内の運転手はこのようなことができるのか」と大まかな仕様を理解することができるはずです。また、今後のミーティングなどで運転手にできることが増えたなら、この抽象クラスに処理を追加すればいいこともわかります。 入力値と出力値もわかるので、コーディングレベルでも伝えられることは多そうです。 ユビキタス言語 最後にユビキタス言語でコードに仕様を表してみましょう。 実はここまでのサンプルコードで出てきているのですが、プログラム処理的な言葉を排除し、業務的な言葉でコードを書くことを示します。(大体) class CustomerService { // 省略 /** * @param Product $luggage * @return void */ public function createTransaction(Customer $customer, Product $product) { // 取引を作成する処理 } } このようなコードだとcreateTransactionがどのような業務フローを示すのかがよくわかりません。 コードの内容をそのまま受け取るとお客様が取引を作成する? うーんちょっとわかりません。 class CustomerService { // 省略 /** * @param Product $luggage * @return void */ public function buy(Customer $customer, Product $product) { // 取引を作成する処理 } } このようにすればわかりますね。関数名がbuyですし、Product型の変数を渡していることから商品を購入する処理ということは想像できそうです。 このように変数名 / 関数名を少し業務に寄せるだけでも全然違います。 とても簡単に見えますが、結構難しいです。プログラミングをしているときは頭がプログラムの味方をしてしまうのです。 もう少し極端にしてみる 商品登録をする処理を作成してみましょう。 class Staff { public function createProduct(Product $product) { // 商品登録処理 } } あっているようにも見えます。createはデータストアにデータを登録する処理として名付けられることもしばしばあります。 でもこれで満足してはいけません。本来ならこうなるはずです。 class Staff { public function registerProduct(Product $product) { // 商品登録処理 } } 登録なのですからregisterですよね。 商品更新ならどうでしょうか?updateProductが正解っぽいです。でもミーティングでは商品編集という言葉で進んでいました。ではeditProductが正解でしょう。 いやいや、ウチのミーティングでは商品保存で統一されているんだよ。 ならば、saveProductでUPSERT的な処理を記述するべきでしょう。 このように細かいところまで使用する言葉に気をつける必要があります。 こうすることでコードに仕様を表すことができるのです。 最後に コードに仕様を書くことの大切さはプログラマが知るべき97のことでも書かれていましたね。 ここまでするの面倒だからしないという方もいるかも知れませんが、どうせコメントに仕様書くならコードに書きませんか? 次回もプログラマが知るべき97のことを読んで記事にしようかなと思っています。 その時はよしなに。 .

ボーイスカウト・ルールを現実的に実現するためには?

2020/07/06 2020/07/06

プログラマが知るべき97のこと こんにちは。のんです。 本日はプログラマが知るべき97のことを読んでいてこれ「いいな」と思った箇所について書いてみようと思います。 こちらの書籍はとても有名なので、既読の方もいらっしゃるかもしれません。 そういう方は復習というか、内容を思い出したり、私の意見と違うところや共感できるところを探していただければ幸いです。 ボーイスカウト・ルールってなに? プログラマが知るべき97のことにはこう書いています。 ボーイスカウトには大切なルールがあります。それは、「来た時よりも美しく」です。たとえ自分が来た時にキャンプ場が汚くなっていたとしても、そしてたとえ汚したのが自分でなかったとしても、綺麗にしてからその場を去る、というルールです。 最近、私の町ではボーイスカウトの姿を見なくなってしまいました。私が子供の頃は友達がボーイスカウトしていたこともあって結構身近な存在だったのですが、現在はどうなんでしょうか? しかし、これまでの人生このような光景は見たことあるかもしれません。ボーイスカウトに限らず、小学校で美化活動として昼過ぎくらいに町内清掃している姿くらいは見かけているはずです。 「この考えをプログラミングにも取り入れようよ」という考えがボーイスカウト・ルールです。 結構簡単そうじゃない?いえいえ、かなり難しいはずです。 コードに散々しているゴミコードをただ修正変更するのは結構簡単と思えるかもしれませんが、私は難しいと感じます。その理由を1つずつ挙げると、 バグ修正は気軽にできない すでに正常動作しているコードを修正することへの心理的ハードルが高い 納期に追われているなど、時間的余裕が無い コミットをきれいに保ちたい。(ブランチ作成や切り替え作業が面倒くさい) すぐに思いつくのは以上のような理由でしょうか?他にも色々あるかもしれませんが、多分共感していただけると思います。 バグ修正は気軽にできない バグ修正は気軽にできません。影響範囲の調査や、バグを修正したことによるデグレーションを考慮しなければならなくて、とても工数がかかります。ゴミ拾いと同じ感覚で修正していたらいつの間にかscrap & buildしていたとかなりかねません。(時間的余裕と、影響範囲潰しができればとてもGJ👍ですが!!) すでに動作しているコードを修正することへの心理的ハードルが高い 四則演算の効率化や簡単化など、ちょっとした処理の修正に対して変更を行うことを想定しましょう。すでに正常に動作しているコードを修正すると考えるだけで不安になります。心の中で、(うーん……次のマイナーバージョンでするか)みたいになるのは火を見るより明らかです。 納期に追われているなど、時間的余裕が無い。 これは簡単ですね。そもそもその程度の修正をする時間すら存在しない時です。 コミットをきれいに保ちたい 一般的にGitを用いて開発をする場合、ブランチは機能単位に切られ、マージできるレベルでコミットされるはずです。あるAという機能を作成しているときに、ボーイスカウト・ルールに則って修正を行うと、A機能のためのブランチにBの修正が混じることになります。これを嫌がる人や、是としないチームはたくさんあるはず(というか、そういうルールが推奨されているはず)です。 そういうルールがある中でボーイスカウト・ルールを適用しようと思うと、(Aという機能を作るという別の仕事をしているにも関わらず、)ブランチを新しく作成したり、マネージャーへ連絡したりしなければなりません。 それが面倒臭いという人は必ずいるはずです。(私もそうでした。) こういった「課題をクリアする」というより、ボーイスカウト・ルールを適用しやすい環境を作る方がとても簡単です。上記の課題を例にボーイスカウト・ルールを適用しやすい環境を考えてみました。 (adsbygoogle = window.adsbygoogle || []).push({}); ボーイスカウト・ルールのハードルを下げる 見かけたバグはすぐ直す。このルールをそう受け取る方もいるかも知れませんし、そう思っていない方も、義務感から修正への執念を持っているかもしれません。私の知り合いには、あまりにひどいコードに遭遇し、もはやこの考えが強迫観念となっている方がいました。 もっと気軽に考えましょう。以下のポイントを押さえ、継続すればうまくいくはずです。 変数名や関数名本当に軽微なポイントにのみ注目する ノルマなどは当然設けない 修正というより整頓と考える(後述) 関連して、一気に修正 / 整頓しない 修正というより整頓と考える 例えば、引き継いだプロジェクトで下記のようなコードに出会ったとしましょう。自分はある程度経験を積んで、よくわからない処理を調査していました。数十分ほどかけて、そのロジックを解き明かしたとしましょう。 <?php class DustSample { /** * @var string */ private $dust; /** * @param string $dust */ public function __construct(string $dust) { $this->dust = $dust; } public function unknown() { // 難解なコードで自分が頑張って読み解いた重要な処理 } } この時、unknowメソッドをボーイスカウト・ルールに則り修正するのではなく、コメントを書くなどして、わかりやすくしたり、一部privateメソッドなどで切り分けられそうなものを切っておきましょう。だから修正より整頓と考えるわけです。 <?php class DustSample { /** * @var string */ private $dust; /** * @param string $dust */ public function __construct(string $dust) { $this->dust = $dust; } /** * 〇〇を✕✕して△する処理 */ public function unknown() { // 難解なコードで自分が頑張って読み解いた重要な処理 } /** * 〇〇を✕✕する処理 */ private function unknown_parts() { // 難解なコードの一部、でも、処理を切り分けることでどんな処理をするのかが少しわかりやすくなっている } } 少しはハードルが下がるはずです。少なくともコメントの追加で動作が変わるというのは早々ないでしょう。 これまでの慣習をできるだけ無視し、オブジェクト単位で、特に依存を無くす実装にする PHPだとよくあるのは、全部Controllerに書かれていて、しかもそれが他の処理に密結合を起こしている場合です。 そうなってくると、ボーイスカウト・ルールどころではありません。 ちょっとした改修タスクを作成し、その部分だけでもオブジェクト化しておきましょう。 クリーンアーキテクチャに基づいたDDDがオススメではありますが、そうでなくても、振る舞いを閉じ込めたEntityのみを採用するだけにとどめたり、ValueObjectだけでも採用したりすることで、ボーイスカウト・ルールをしやすいコードへと変身させるのです! わかりやすい、あるいは依存していないコードに対してはとても修正をかけやすいです。心理的ハードルが下がるはずです。Interfaceで抽象クラスを作成したり、ControllerではなくActionでリクエストを捌いてみたり、とにかく小さく処理を作成するように心がけると、みんなは自然とゴミを拾ってくれます。 ここでも大事なのはストレスのかからないレベルで導入することです。隅っこの方のディレクトリにModels/Entityとディレクトリを切り、その中に必要な振る舞いと値を入れるだけとかでもいいです👍 テストコードを整備する ここまでで気づいている方は多いでしょう。 テストコード、これがあればストレスとはおさらばですね👍 なんちゃってリファクタリングではなく、本格的なリファクタリングができるようになります。 https://www.amazon.co.jp/Java言語で学ぶリファクタリング入門-結城-浩/dp/4797337990 その時はこちらの書籍を読むといいかもしれません。 TDD(テスト駆動開発)と勘違いする方がいますがここでは関係ありません。 リファクタリングについては、また違う記事でしましょう。 やはり一番の処方箋は開発者の心理的ハードル下げることでしょうか。 修正してくれたことを褒めたり、感謝する文化を作ったり その修正を勤務評価にフィードバックしたり ポジティブな理由ですすめることができたら間違い探しをしているみたいに楽しいかもしれません ボーイスカウト・ルールを適用するにあたっての注意点 一応デメリットとしてあげられるのは、計画的 / 継続的にやりましょうとういことです。 計画的に進めなければ、プロジェクトの方針と食い違う可能性が出てきます。継続的に進めなければ、中途半端になってしまいます。 見かけたら100%の修正をする必要はありませんが、その分続けなければならないことは感覚的にわかりますね。 最後に ボーイスカウト・ルール。この考えとても好きです。年末に大掃除するとき、慌てない家庭はこのルールをキチンと守っているのでしょう。あるいは夏休み宿題で苦労することはないでしょう。 継続的インテグレーションが完全に普及した今、コードを作成したらそれで終わりという文化もなくなりました。 コードのメンテナンスをしっかりすることで、バグの早期発見や仕様の理解もできるでしょう。 私も完全に出来ているわけではないので、今後も頑張りたいです。 プログラマが知るべき97のことについての記事はまた書くかもしれません。 そのときはよしなに。 .

Z250で三方五湖レインボーラインへツーリング!

2020/06/25 2020/06/25

Z250で三方五湖レインボーラインへツーリング! こんにちは。Nonです。 今回は技術記事ではなくバイク記事です。 三方五湖レインボーラインへ行って来たよ 前日が雨でツーリング行けるかどうか不安でしたが、無事いい天気で当日を迎えることができました☀️ 行きは大津周辺で集合。琵琶湖の西側、367号線を北上するルートで向かいました。 この道路もめちゃめちゃいいですね👍 10時から大津を出発して、12時に到着。2時間くらいで行けるものなんですね。 実はレインボーラインへ行くの2回目なんですが、そのときは舞鶴若狭道で向かったものですから、少し遠回りだったんですよ。 レインボーラインの入り口でパシャリ レインボーラインの道中でパシャリ レインボーラインで昼飯食って13時くらいから帰路に着きました。 レインボーライン降りて少し北の216号線走る 北の方には良いワインディングがあるものの、道路の状態と、視界が悪くて少し怖かったかも。。 北の最頂には特に何もありませんでした。でも港はキレイでしたね。 162号線で帰る 162号線いいですよ👍 あの辺で走ってる黒いZ250は僕かもしれません🏍 最後に コロナ禍でなかなかツーリング行けなかったので、久々のツーリングでした。 一番いい時期を奪われてほんまに。。。 やっぱりツーリングはいいものですね。 ちょいちょいですが、こういったバイク記事を投稿しています。よかったらこちらも見てみてください。 Z250で伊勢志摩ツーリング!! | のんラボ Z250で伊勢志摩ツーリングに行ってきました!!こんにちは。Nonです。今回は久々にツーリングの記事を更新します🏍正確には上図のマップどおりではありませんが、スケールはコレより大きい範囲回ってきました... Z250で初!キャンプツーリング! | のんラボ 洞川キャンプ場へツーリングしてきましたこんにちは。Nonです。今回は久々に技術とは全く関係ない記事を投稿します。週1ペースで技術系の記事を投稿していますが、月1でこういうのもいいと思っています。毎回技... Z250での冒険日記 | のんラボ 定期的にこんな感じの記事も追加して行くと思う。4月27日〜29日 西日本一周ツーリングこれはお友達と弾丸ツーリングに行きましたZXR1200のパワーを見せつけられましたね。鳥取砂丘写真は撮影してないけ... また記事書きます!動画もアップロードできるようにこのブログもバージョンアップしようかな。 最後に!バイクはいいぞ!! .

フロントに処理を書くとき、フレームワーク内で処理は書かない方がいい気がする

2020/06/17 2020/06/17

フロントに処理を書くとき、フレームワーク内で処理は書かない方がいい気がする こんにちはNonです。 今回はこれまでと変わってフロントに着目したいと思います。 前提 (laravel-mixでの)Vue フレームワーク内で処理を書くとこうなる export default { name: 'ApplicationComponent', data() { return { food: { name: '', price: 0, num: 0, }, drink: { name: '', price: 0, num: 0, }, sum: { price: 0, num: 0, }, tax: 0.08, }; }, created() { this.food.name = 'おにぎり'; this.food.price = 100; this.food.num = 3; this.drink.name = 'お茶'; this.drink.price = 150; this.drink.num = 1; }, computed: { sum() { return { price: this.calcTax(this.food.price, this.food.num) + this.calcTax(this.drink.price * this.drink.num), num: this.food.num + this.drink.num, }; } }, methods: { calcTax(price, num) { return price * (1 + this.tax) * num; }, } }; コンポーネント単位でこのような処理を書くと、違うコンポーネントのロジックを書くときに、計算方法を間違えそうになるかもしれません。 そこで、計算処理、つまりビジネスロジックを持つモデルを外部のjsで持つことでロジックの重複を防ぎます。 フレームワーク内はレンダリングに注力し、処理は他のパッケージで持つ フレームワーク内はレンダリング、つまり値の監視や、コンポーネントの管理などはフレームワーク(ここではVue)で行い、フロントで行うべき処理であるビジネスロジックはモデルとして外部に持つようにします。すると下記のようになります。 export default { name: 'ApplicationComponent', data() { return { food: { name: '', price: 0, num: 0, }, drink: { name: '', price: 0, num: 0, }, sum: { price: 0, num: 0, }, tax: 0.08, }; }, created() { this.food.name = 'おにぎり'; this.food.price = 100; this.food.num = 3; this.drink.name = 'お茶'; this.drink.price = 150; this.drink.num = 1; }, computed: { sum() { const productCollection = new ProductCollection([ new Product(this.food.name, this.food.price, this.food.num), new Product(this.drink.name, this.drink.price, this.drink.num), ]); return { price: productCollection.sumPrice(), num: productCollection.sumNum(), }; } } }; export class ProductCollection { constructor(items = []) { this.items = items; } sumPrice() { return this.items.reduce((previous, current) => { return previous.sumPrice() + current.sumPrice(); }); } sumNum() { return this.items.reduce((previous, current) => { return previous.num + current.num; }); } } export class Product { static get TAX() { return 0.08; } constructor(name, price, num) { this.name = name; this.price = price; this.num = num; } calcTax() { return this.price * (1 + this.TAX); } sumPrice() { return this.calcTax() * this.num; } } このように、商品のビジネスロジックをクラスの中に封じ込め、更にフレームワーク依存しない箇所に集めることで、使い回すことを可能にしています。 さらに、フレームワーク依存しないので、他のフレームワークに移行するときにも重宝します。 Vueの場合、mixinに書けばいいじゃん? もちろん、Vueに依存することを前提にしている場合はそれでもいいですが、HelperやUtilのような役回りが多いmixinにビジネスロジックを書くのはいかがなものでしょうか? 〇〇mixinが多くなってしまうのが、目に見えます。 クラス(オブジェクト)のパワーを借りることができる。 例えば、バリデーターを自作したとして、このようなクラス作成します。 export class StringValidator { constructor(value) { this.value = value; this.result = []; this.messages = []; } max(length) { this.result.push(this.value.length > length); this.messages.push(length + '文字以下で入力してください。'); return this; } min(length) { this.result = this.value.length < length; this.messages.push(length + '文字以上で入力してください。'); return this; } number() { this.result = Number.isInteger(this.value); this.messages.push('半角数字のみで入力してください。'); return this; } invalid() { return this.result.filter((item) => { return item === true; }).length > 0; } } このようにすれば、jQueryだろうがReactだろうが使用できるようになるでしょう。 今回の場合はVueで書いてみます。 export default { name: 'ApplicationComponent', data() { return { name: '', errors: [], }; }, methods: { submit() { const validator = new StringValidator(this.name); const invalid = validator .max(10) .min(1) .invalid(); if (invalid) { this.errors = validator.messages; return false; } // 処理 } } }; これならバリデーションの内容を外部に任せることができます。 もちろん、入力中のバリデーションやVueで行いたい基本的なバリデーションをmixinなどに書いてリアルタイムにエラーを出力することなどもできますので、そちらはVue側に記述して、ビジネスロジックに関するバリデーションは外部に持つというのが、いい気がします。 最後に 今回はフロントにロジックを記載するときについて書いてみました。 PHPでWebアプリを作成するときは少し前まではフロントを書くときjQueryを採用することが多かったです。 こうなるとどうしてもロジックをスクリプトにチョチョイと書いてしまう実装は多いのではないでしょうか? フロント言語がしっかりとしてきた今、フロントのコードもしっかりと設計していきたいものです。 今は社内でスクラムの勉強会をしているので、その記事も書くかもしれません。 そのときはよしなに。 .

社内でドメイン駆動設計入門の読書会 #15

2020/06/08 2020/06/08

社内でドメイン駆動設計入門の読書会 #15 こんにちは。Nonです。 今回も会社で読書会をしている話をしようと思います。 内容は控えめに、ディスカッションの内容重視で書いていきたいと思います。 より具体的なコードや内容がみたい!という方は購入しましょう! 前回:会社でドメイン駆動設計入門の読書会 #14 読んでいる本 読んでいる本はこちらのドメイン駆動設計です。 ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 以前の記事でも言っていたように、業務でDDDを利用して開発することが多くなったのですが、DDDに精通している人が少ないという問題がありました。 そこで、その精通している人が読書会をしようかと誘ってくださいまして、是非にと参加させていただきました。 進行方法 読書会の進行方法は 今回読書の対象にする章を決める。 10〜20分間その章を読む 読み終わってしまった人は、もう一周読み直すか、次の章に進んでもらう その後40分間で、その章に対する疑問や考え方をディスカッションする 1〜3を毎週定期的に行う という進行方向となっています。 社内で読書会をするのはこれが初めてなので、進行方法はもっといいのあったら教えて下さい。 今回読んだ内容 ドメイン駆動設計のとびらを開こう 軽量DDDに陥らないために ドメインエキスパートとモデリングする 本当に解決すべきものを見つけよう ドメインとコードを結びつけるモデル ユビキタス言語 深い洞察を得るために ユビキタス言語がコードの表現として使われる 境界づけられたコンテキスト コンテキストマップ テストがチームの架け橋に ボトムアップドメイン駆動設計 まとめ ディスカッション ディスカッションではコードの話のほうが多かった でも、ドメイン駆動はドメインに注目して開発していく設計なので、コードは実はあまり関係ないのかもしれません。もちろん、コードが二の次というわけではなく、コードはドメインを反映させるためのふさわしい構造になっていないといけません。 ユビキタス言語 この記事を読んでいる皆さんにはすでに周知のとおりですが、変数名は重要です。 変数名はその処理を追うための手かがりになるからです。 ドメイン駆動設計でもこの点に触れていて、create, make, registerや、update, saveなど、普段何気なく使っている変数名や関数名について触れています。 ドメインで頻出する単語はそのドメインにとって重要なので、それもコードに反映しなければなりません。 例えば、あるドメインで、ユーザー登録ではなくエージェント登録という内容であれば、userではなくagentという名前になりますし、ユーザー更新ではなくユーザー保存と慣ればsaveUserとなります。 この微妙な命名でコードとドメインが乖離してしまう原因になってしまうのです。 境界づけられたコンテキスト これはまだ完全に理解できていないので、今後の課題とします。 最後に 実は結構前に、ドメイン駆動設計の全ての章を読み終えて、業務のコードに実装まで始めていました。実際にコードにするとなると非常に難しく、軽量DDDになってしまっている感が否めません。今後も精進していきたいです。 常時、自社プロダクトにコミットしているので、自分の作成したプロダクトくらい自分の支配下においていきたいものです。ということはドメインに一番詳しいのは、自分たちということになります。 そういう意味でも、ドメイン駆動設計を用いて、自分たちが実現したいことをコードで表すことは義務であるのかなと思います。 読書会は引き続き進めているので、機会があればまた連載記事として、掲載していこうと思います。 その時はよしなに。 .

社内でドメイン駆動設計入門の読書会 #14

2020/06/01 2020/06/01

社内でドメイン駆動設計入門の読書会 #14 こんにちは。Nonです。 今回も会社で読書会をしている話をしようと思います。 内容は控えめに、ディスカッションの内容重視で書いていきたいと思います。 より具体的なコードや内容がみたい!という方は購入しましょう! 前回:会社でドメイン駆動設計入門の読書会 #13 読んでいる本 読んでいる本はこちらのドメイン駆動設計です。 ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 以前の記事でも言っていたように、業務でDDDを利用して開発することが多くなったのですが、DDDに精通している人が少ないという問題がありました。 そこで、その精通している人が読書会をしようかと誘ってくださいまして、是非にと参加させていただきました。 進行方法 読書会の進行方法は 今回読書の対象にする章を決める。 10〜20分間その章を読む 読み終わってしまった人は、もう一周読み直すか、次の章に進んでもらう その後40分間で、その章に対する疑問や考え方をディスカッションする 1〜3を毎週定期的に行う という進行方向となっています。 社内で読書会をするのはこれが初めてなので、進行方法はもっといいのあったら教えて下さい。 今回読んだ内容 アーキテクチャ アーキテクチャの役目 アンチパターン:利口なUI ドメイン駆動設計がアーキテクチャに求めること アーキテクチャの解説 レイヤードアーキテクチャとは ヘキサゴナルアーキテクチャとは クリーンアーキテクチャとは まとめ ディスカッション 今回はアーキテクチャについて これまでのドメインオブジェクトをどうやって実装していくか、それにあったアーキテクチャを紹介してくれている章でした。 抽象に依存せよ これまでの章で何度も登場してきたのが、この文言です。 抽象に依存しておけば、実装クラスの内容をある程度縛ることができますし、抽象クラスを見るだけどんな内容が実装されるべきなのかわかります。 クリーンアーキテクチャ The Clean Code Blogより抜粋 https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 徹底的に依存を嫌うので、値を返さない用な処理が多いです。 前回試しにかいたコードを見てみましょう。 class CreateCircle { private $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function process(CreateCircleInputPort $inputPort, CreateCircleOutputPort $outputPort) { $circleName = new CircleName($inputPort->circleName()); $circle = $this->userService->createCircle($circleName); $outputPort->output($circle); } } interface CreateCircleInputPort { public function circleName(): string; } interface CreateCircleOutputPort { public function output(Circle $circle): void; } このprocess関数は何も返却されていません。 Actionからこのアプリケーションサービスを呼び出すイメージなので、アクションには何も帰らないことになります。 こうすることで、Actionはこのアプリケーションサービスに依存しないようにできています。 ではActionは何をレスポンスとして返せばいいのかというと、上図にあるようにUse Case Output Portに返したいものを注入しておきます。 class CreateCircleAction extends Controller { private $useCase; public function __construct(CreateCircle $useCase) { $this->useCase = $useCase; } public function __invoke(Request $request) { $response = new CreateCircleResponse(); $this->useCase->process($request, $response); return response()->json($response); } } returnするのは同一のドメイン内だけで行うことのようです。 アーキテクチャの勉強にもなった 正直この読書会をするまでは、MVCすら危うい感じでしたが、このように具体的に書いてくれる本があったので、設計にも少しは明るく慣れたと思います。 抽象に依存せよ。(interfaceを利用せよ) ドメイン内以外でreturnするな(オブジェクトを渡して、結果はそこに注入せよ) 強いてあげるなら、フレームワークに依存するな。 これくらいを守れればコードの可読性と保守性は飛躍的に向上すると思います。 最後に どうやって設計すれば。。。という壁にぶち当たっていたので、今回の章(今回の読書会)でこの壁は壊せたと思います。 このアーキテクチャはドメイン駆動だけでなく他のモデルにも通じますし、PHPだけじゃなくてjavascriptにも通用しますので、フロントのコードも多少はきれいになると思います。 次回はドメイン駆動設計のとびらを開こうです。 また記事にしますので、その時はよしなに。 .

社内でドメイン駆動設計入門の読書会 #13

2020/05/25 2020/05/25

社内でドメイン駆動設計入門の読書会 #13 こんにちは。Nonです。 今回も会社で読書会をしている話をしようと思います。 内容は控えめに、ディスカッションの内容重視で書いていきたいと思います。 より具体的なコードや内容がみたい!という方は購入しましょう! 前回:会社でドメイン駆動設計入門の読書会 #12 読んでいる本 読んでいる本はこちらのドメイン駆動設計です。 ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 以前の記事でも言っていたように、業務でDDDを利用して開発することが多くなったのですが、DDDに精通している人が少ないという問題がありました。 そこで、その精通している人が読書会をしようかと誘ってくださいまして、是非にと参加させていただきました。 進行方法 読書会の進行方法は 今回読書の対象にする章を決める。 10〜20分間その章を読む 読み終わってしまった人は、もう一周読み直すか、次の章に進んでもらう その後40分間で、その章に対する疑問や考え方をディスカッションする 1〜3を毎週定期的に行う という進行方向となっています。 社内で読書会をするのはこれが初めてなので、進行方法はもっといいのあったら教えて下さい。 今回読んだ内容 複雑な条件を表現する「仕様」 仕様とは 複雑な評価処理を確認する 「仕様」による解決 リポジトリの仕様を避ける 仕様とリポジトリを組み合わせる お勧めサークルに見る複雑な検索処理 仕様による解決法 仕様とリポジトリが織りなすパフォーマンス問題 複雑なクエリは「リードモデル」で まとめ ディスカッション 今回は評価と参照 今までのドメインは「ユーザーを作成する」とか、「サークルにメンバーを追加する」など、追加、更新、削除。つまりライフサイクル周りに注目するユースケースばかりでしたが、今回はサークル一覧をどう見せるか、どのようにサークル検索するか、に注目していた章でした。 正直な話、プログラミングにおいて「参照」が一番書かれる頻度が高いと(個人的に)思っているので、気になる章ではありました。 ディスカッションにおける最終的な結論 参照はドメイン駆動で設計しなくてよくね? 参照はデータ参照といっても過言では無いくらいです。 多少の加工はありますが、それは果たしてドメインと言えるのかも甚だ疑問です。 例えば登録されている商品の値段を税抜価格から、税込価格へ変換する処理は知識とは呼べそうですが、Entityに書くほどでしょうか? また、1000円以上の商品を赤文字で表示するという画面側の要望があるときにその振る舞いをEntityに書くべきなのでしょうか? これに対する結論が「リードモデル」だそうです。 登録 / 更新 / 削除用のドメインオブジェクトとは別に参照用のドメインオブジェクトを作成する言えばいいでしょうか? 少し誤解(語弊)があるかもしれませんが、そのように私は受け取りました。 参照は性能にも密接に関わる 登録件数1億件のデータにアクセスするとき、単純なクエリで一発で取れるなら、プログラムで処理して、時間をかけるより、SQL一発で簡単にとってそのままレスポンスとして返したほうがユーザーのためになるという意見も今回のディスカッションの中で出たくらいです。 CQRSという考えもあるらしいので、全てにおいてドメイン駆動設計で実装する必要はなさそう。というのが、今回の章で言いたい部分の一つだったのかもしれません。 参照を別の設計で駆動させるときのディレクトリ構造 src┓ ┣User┓ ┃ ┣CreateUser┓ ┃ ┣User ┃ ┣UserName ┃ ┣GetUser┓ ┃ ┣全く別の設計手法で書かれたコード ... となりそうです。 少なくとも、私はそのように書いています。 Entityでgetterはできるだけ書きたくない これが、一貫してこの本に書かれているのですが、この理論で行くと参照系とは相性の悪い(?)手法なのかもしれません。 CQRSについては別でまた記事にしたい CQRSについては勉強不足なので、また別の機会に。 最後に 実はドメイン駆動設計で組むぞ!って始めたプロジェクトで一番はじめに組んだコードが参照系でした。 かなり苦労したので、別の手法でコーディングするのは納得できています。 CQRSとまでは行きませんが、単純なSELECT処理をして、フロントが欲しい物を多少加工して返しています。これのせいでコードが汚くなるということも無いですし(参照系ですので)、問題ないと思います。 次回はアーキテクチャです。 また記事にしますので、その時はよしなに。 .

社内でドメイン駆動設計入門の読書会 #12

2020/05/18 2020/05/18

社内でドメイン駆動設計入門の読書会 #12 こんにちは。Nonです。 今回も会社で読書会をしている話をしようと思います。 内容は控えめに、ディスカッションの内容重視で書いていきたいと思います。 より具体的なコードや内容がみたい!という方は購入しましょう! 前回:会社でドメイン駆動設計入門の読書会 #11 読んでいる本 読んでいる本はこちらのドメイン駆動設計です。 ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 以前の記事でも言っていたように、業務でDDDを利用して開発することが多くなったのですが、DDDに精通している人が少ないという問題がありました。 そこで、その精通している人が読書会をしようかと誘ってくださいまして、是非にと参加させていただきました。 進行方法 読書会の進行方法は 今回読書の対象にする章を決める。 10〜20分間その章を読む 読み終わってしまった人は、もう一周読み直すか、次の章に進んでもらう その後40分間で、その章に対する疑問や考え方をディスカッションする 1〜3を毎週定期的に行う という進行方向となっています。 社内で読書会をするのはこれが初めてなので、進行方法はもっといいのあったら教えて下さい。 今回読んだ内容 ドメインのルールを守る「集約」 集約とは 集約の基本的構造 オブジェクトの操作に関する基本的な原則 内部データを隠蔽するために 集約をどう区切るか IDによるコンポジション 集約の大きさと操作の単位 言葉との齟齬を消す まとめ ディスカッション 今回はより現実的な話 今までに挙がった例はどれも単体での動作のみに注目してきましたが、現実のドメインは様々なEntityが複雑に関連しています。 そうなるとEntityは肥大化していきますし、振る舞いも相当なものになるでしょう。 そういうときに、どのようにまとめるべきなのか。ということを話題にしていました。 正直まだよくわからない。 最初から申し訳ないですが、集約難しいです。 現実の関心事を論理的に切り分けるのは一苦労です。 なので、この本にかかれている内容を一部抜粋して、私の考えを記していきたいと思います。 ユーザーとサークルの関係 ユーザーはサービスを利用するにあたって、必須な情報でしょう。 ログインするため アプリを利用するため ログを残すため 色々なことにユーザー情報が利用されることでしょう。 対して、サークルも同様です。 アプリをより楽しく利用するため サークル内でやり取りすることがアプリの真髄 など、サークル作ることは必須ではありませんが、サークル作らないことはこのアプリにとって利用していないのとほとんど変わらない場合を考えます。 するとユーザー⇔サークルは密接関係を持つことがわかります。 サークルとユーザーのドメインは? ユーザー作成にサークルが関係無いことはわかります。 サークル作成にはユーザーが必須に感じますね。 class UserService { private $circleFactory; public function __construct(CircleFactoryInterface $circleFactory) { $this->circleFactory = $circleFactory; } public function createCircle(CircleName $circleName): Circle { return $this->circleFactory->create($circleName); } } class Circle { private $id; private $circleName; private $members; public function __construct(int $id, CircleName $circleName, MemberCollection $members) { $this->id = $id; $this->circleName = $circleName; $this->members = $members; } // ...(略) } class CircleName { private $circleName; public function __construct(string $circleName) { if (mb_strlen($circleName) > 50) { throw new OverflowException('サークル名は50文字以内です。'); } $this->circleName = $circleName; } public function __toString(): string { return (string)$this->circleName; } } class MemberCollection { private $members; public function __construct(array $members = []) { foreach ($members as $member) { if ($member instanceof User) { throw new RuntimeException('Member is must be User type.'); } } $this->members = $members; } public function toArray(): array { $result = []; foreach ($this->members as $member) { $result[] = [ 'id' => $member->id(), 'name' => $member->name(), ]; } return $result; } } のような感じでしょうか。ユーザーサービスはサークルEntityを作成するふるまいを持ちます。 このとき、注目すべきEntityがユーザーEntityとサークルEntityで2つ出てきます。 ユーザーEntityはユーザーの名前を変更する振る舞いを持ちますが、今回の注目ごとはサークルの作成です。果たしてこの振る舞いがこのユースケースと関係あるでしょうか? このふるまいがあるせいで、関心事が散漫とならないでしょうか? また、このコードを是とすると、changeName以外のふるまいがユーザーEntiryに集中することになるので、サークル作成ドメインに違う関心事が書かれたコードがどんどんと追加されることになっていまいます。 ドメインごとにUserEntityを作成するべき? もしかしたら境界づけられたコンテキストの方の分野かもしれませんが、ドメインごとにEntityを分ける戦略が考えられます。 src┓ ┣User┓ ┃ ┣CreateUser ┃ ┣User ┃ ┣UserName ... ┣Circle┓ ┃ ┣CreateCircle ┃ ┣Circle ┃ ┣CircleName ┃ ┣User ┃ ┣UserService ... ┣Domain ... うーん。でもCircleに関心事があるドメインにUserServiceがあるのが少し違和感。本では容赦なく使用していましたが、Circleを作成するにはUserにも関心が向くという知識がドメインに与えられるのでいいことなのかもしれない? EntityはEntityを持つことがある? class MemberCollection { private $members; public function __construct(array $members = []) { foreach ($members as $member) { if ($member instanceof User) { throw new RuntimeException('Member is must be User type.'); } } $this->members = $members; } public function toArray(): array { $result = []; foreach ($this->members as $member) { $result[] = [ 'id' => $member->id(), 'name' => $member->name(), ]; } return $result; } } に書いたように、CircleはMemberとしてUserを持ちます。 if ($member instanceof User) { throw new RuntimeException('Member is must be User type.'); } の部分。 なので、CreateCircleというドメインにEntityが2つあるのは是とするのが、普通の考えなのかもしれません。 Circleに所属するのはUserなので、Userの知識を持つUserをCircleが持つというのは自然な考えだと思います。 この辺はもっとドメイン駆動設計に慣れたらまとめ直したい。 正直、腑に落ちていない点が少しあります。この状態でかくあるべきというのは危険ですので、これ以上の展開は避けておきますね。 最後に ちょっと難しい話でした。それぞれのEntity同士の関係になると一気に難しくなった気がします。ここを理解(納得)できないと、実装も揺らぎそうで怖いです。 次回は複雑な嬢他県を表現する「仕様」です。 また記事にしますので、その時はよしなに。 .