patorashのブログ

方向性はまだない

「現場で役立つシステム設計の原則」読書会 vol.4

第4回の感想です。前回はこちら。

patorash.hatenablog.com

記事の投稿日付は連続になってますが、読書会自体は週に1度の開催です。

会社のテックブログのレポートはこちら。

tech.rhizome-e.com

4章 ドメインモデルの考え方で設計する

  • 要件定義のタイミングで色々と質問をしてドメインモデルを設計する上でのヒントを聞き出すことが大事だなと思った。
  • ドメインモデルの作り方。やはり全体と部分を行ったり来たりしながら徐々に洗練させていくものだよなぁと改めて思った。設計通りにはうまくいかないことが多い。業務フローをまとめて、そこから俯瞰して何が重要そうかを見つけていく。
  • ドメインモデルは独立した部品でなければならない。部品同士を組み合わせていくのはいい。
  • 業務の関心事は、ヒト/モノ/コトで整理できるとあった。これは楽々ERDレッスンに書いてあったことに通じるなと思った。楽々ERDレッスンではリソースとイベントとなっていたが、まずイベントを洗い出せという話だったかと思う。この本でも、コトを整理の軸とする、とまとめに書いてある。ついついヒト/モノのリソースだけに注目してDB設計しがちなので、そこは気を付けるポイントとなるだろうなと思った。
  • 業務ロジックにもパターンがある。パターンを認識しておくと、応用が効く。たしかに、大体がこの4パターンかなと思う。
  • 業務を表現するのがドメインモデルなので、名前がより具体的になっていく。そのため、どこに何が定義されているのかを探しやすい。抽象度を高めることが汎用的なプログラミングには大事だけれど、ドメインモデルについては全くの逆。暗黙知を明らかにしていくという役割を担っているということか。暗黙知の言葉が、クラス名やメソッド名になっていくとわかりやすいコードになりそう。
  • 開発者が業務の用語を正しく理解して使うことが重要。そうすれば、ドメインモデルが作りやすくなる。
  • 関係をわかりやすく図で表現してあると全体を俯瞰しやすい。UMLで表現できるものばかり。
  • その業務分野について興味をもって学ぶというのが大事。プログラムだけ上手くなろうとしても片手落ちで、我々は業務知識を学ばなければならない。会計ソフトを作っている会社のエンジニアが簿記の資格をとったりする話もある。自分の場合は、弊社の社長や営業さん達がお客さんとの会話で得られたものを定例会の時に教えてくれたりしたので、それがよかった。客先にいって質問する機会も何度かあったが、その時にも、どういうところを重視しているのか?などを質問できて学べることがあった。会話能力が基本スキル、というのはそうだろうなと思う。
  • ある意味、ズケズケと聞いて認識を合わせていくようにしないと、全然違った時のリカバリが難しい。プログラムだけならまだしも、信用が落ちる可能性もある。なんで聞かなかったの?とか、なんで確認しなかったの?とか。
  • ドメインモデルの設計とは、より良い回答を探し続けること。改善し続けること。
  • やはり終わりはない。常にリファクタリングし続けていく必要がある。プログラムもだけれど、自分自身も学び続けなければならないんだなぁと改めて思った。

雑感

ドメイン知識を付けながら、プログラム能力も上げていかなければならないので、テクニックだけに絞って勉強しててもいかんよねという話をしたり、コミュニケーション能力大事だよねっていう話をしたりしてました。 現在の開発メンバーは、わりかし大人しい人が多く、あまり質問しなかったりするので、会話を引き出すためのキッカケを作る練習とかはしたほうがいいんじゃないか?って話したかなと思います。

例えば、感想のところに書いた「営業さん達がお客さんとの会話で得られたものを定例会の時に教えてくれた」という話1つとっても、営業さん達が能動的に開発チームにフィードバックをくれるわけではありません。もう議題がないかなというあたりで「そういえばこの前、操作説明会をされてたと思うんですが、お客さんの反応ってどうでした?」とか、「この前追加した機能について、お客さんから何か反応ありましたか?」とか、聞いてみるわけです。そうすると、「あー、あれは喜ばれてましたよ」と言ってもらえたりするので。

ネガティブフィードバックはこちらから言わなくても言ってもらえるんですが、ポジティブフィードバックはなかなか聞けなかったりするので、こちらから聞いていく姿勢も大事です。

「要件定義に関しては、どういうふうに要件を聞き出していけばいいんでしょうか?」という相談があったので、チェックシートを作っておくといいんじゃないか?という話をしたり。お客さんにチェックシートを記入してもらうわけではなく、こちらが質問したかどうかのチェックシートとして活用すると、抜け漏れを防げるんじゃないかな?会話の糸口にもなるんじゃないかな?と。

日々勉強して、リファクタリングを繰り返しながら正解に近づけていくのが王道だなと、改めて思いました。

楽々ERDレッスンについて触れましたが、こちらも感想は記事にしてあるので、そちらもどうぞ。

patorash.hatenablog.com

「現場で役立つシステム設計の原則」読書会 vol.3

第3回の感想です。前回はこちら。

patorash.hatenablog.com

会社のブログのレポートはこちら。

tech.rhizome-e.com

3章 業務ロジックをわかりやすく整理する

私が書いていた箇条書きのメモ。

  • データクラスと機能クラスの話。真っ先に思い浮かんだのは、Fat Controllerである。モデルに機能を書かないでコントローラーのアクションに処理をまとめてしまうせいで、再利用できないようになってしまうやつ。やはり悪手として紹介されていた。どこに業務ロジックが定義してあるかがわかりにくくなる。
  • そして、共通化の手法として、汎用クラスの話があった。UtilsやCommonだが、これらもよくないとは直感的に思っていたが、やはりそうだった。同じような処理がたくさんできて、使い分けがわからなくなるというのは、ちょうど前回の読書会の感想で参加者メンバーの1人が言っていた話と同じだなと思った。
  • 前にいた会社(12年以上前)だと、メンバー全員がオブジェクト指向を全然理解してなかったので共通化処理を継承元のクラスにガンガン追加していくというやり方を取っていたことを思い出す。当時はテストを書く習慣もなかったので、今考えると相当恐ろしい。
  • Railsのモデルはデータと業務を寄せていくところなので、まさにここに書いてあることに合致する。しかし、現状のプロジェクトだと値オブジェクトを使ってないから、まだまだ半分正解っていうところだろうか。
  • メソッドは必ずインスタンス変数を使うっていうのはよい指針だと思う。
  • クラスが肥大化したら分けるというのも、値オブジェクトを導入するいいタイミングっていうことなのだろう。共通で使えるパーツが増えていくと、再利用性が増すのでとてもよい。
  • パッケージにまとめる話。クラスを宣言するときにpublicって付けなかったらパッケージ内のみのスコープのクラスになるという話だったかと思う。他のところで通用しない、プロジェクト単位では再利用できない業務ロジックをそのパッケージ内に収めるという意味ではよさそう。これはたぶんRubyではできない気がする。パッケージはないけれど、それと似たようなことができるのが、モジュールで名前空間を作ることなので、そこは積極的に利用していきたいところだが、コードがかなり冗長になるので、やりすぎには気をつけたい…。Javaだと、importでパッケージを指定するので、あまり冗長にならない。
  • 3層とドメインモデルの話があったが、この3層をきれいに分けるパターンへのアンチテーゼみたいなのがRailsで、Railsだとデータソース層とドメインモデルが一体化したのがモデルになっている。そのおかげで高速に開発できる反面、複数のドメインモデルを使ってデータソースに保存する場合に、どこのモデルにロジックを書くべきかに困る。そして、どれかのモデルに書いてしまうと、そのモデル同士が密結合になってしまう。そこそこ大きなRailsアプリになってくるとぶつかってしまう壁みたいなものだ。この本を読んでいるとRailsの良いところと悪いところが同時に見えてきて面白い。

雑感

大体のメンバーが、Fat Controllerの話に似ているのでビジネスロジックはModelに持っていくやつ、という感じのことを言っていたように思います。そこら辺は同じチームの後輩氏には最初のほうで叩き込んであるので、普段からちゃんとできているなぁと思います。他のチームも多分そのあたりは大丈夫なはず…。

しかしまぁ、ドメインオブジェクトを意識したコードにはまだできていないので、まだまだ半分正解っていうところです。

最近、自分の書くコードはこの本の影響を受けていて、コトを意識したドメインオブジェクトを作る等して、コントローラーから更に処理を剥がしてドメインオブジェクトもしくはサービスオブジェクトにして関心を分離し、テストしやすいように変えています。コントローラーはそれを呼び出すだけ(新しく作ったところだけですが)。

ここまでテストしてあると、わざわざシステムテストで確認する必要も感じなくなりました(JSが絡むフロントエンド側のテストは別だけれど)。System Spec(いわゆるブラウザテスト)は止めて、APIのテストと同じくRequest Specで済ませました(権限チェック等によるリダイレクトのテスト等はしておきたかったので)。

CommonとかUtilsとかを作るのは、ドメインオブジェクトを作ることから逃げているなぁと考えるようになったので、どこかのタイミングでリファクタリングで撲滅させておきたいと思います。

「現場で役立つシステム設計の原則」読書会 vol.2

間が空いてしまいましたが、第2回目の感想とかです。

前回はこちら。 patorash.hatenablog.com

会社のブログのレポートはこちら。 tech.rhizome-e.com

2章 場合分けのロジックを整理する

感想は箇条書きでメモってました。

  • 区分や種別が条件分岐を生む。区分がロジックを複雑にする。
  • それに対処するために、elseをなくして早期リターンを行うとコードが簡潔になる。これは今もよくやっている。
  • if文の条件をメソッドにして名前を与えると、条件が分かりやすくなる。これもよくやっている。
  • if文同士の関係を疎結合にするというのは、バグが起きにくいし、コードも見やすく、理解しやすくなる。
  • Javaのインターフェースを使っての実装例として分かりやすくてよかった。
  • Rubyだとインターフェースに該当するものがないので、無理やりModuleで作るしかない。呼び出したら例外を発生させるメソッドを定義するとか。
  • Javaの列挙型(enum)は使ったことがないんだけれど、列挙型もクラスとして扱えるというのは知らなかった。
  • 値オブジェクトの次は、区分オブジェクト。業務ロジックとしての区分は頻繁に出てくる。
  • 権限だったり、顧客区分だったり。ここを設計で綺麗にできると、迷いが生じにくそう。
  • 状態遷移のルールを区分オブジェクトにしてしまうという発想はなかった。これもまた条件分岐でやっていたと思うのだが、これならば一目瞭然でわかりやすい。Rubyならば、Setを使って実装するとよさそう。

雑感

よくやっている手法が出てきたので、まぁその辺りはできるようになってるな、うんうんと思いながら読み進めました。早期returnするとコードの階層が浅くなるのでいいですよね。if文の条件も、割と頻繁に出てくる可能性があるので、再利用性が高まるし、なにより条件に名前を付けられるのがわかりやすくなって良いっすね。

インターフェースを使うことで、区分に型を強制できるので、表現力があっていいなと思いました。そして、列挙型を使うことで更に簡潔に…。Rubyには現時点では列挙型がないので羨ましい。これはどうやればRubyで表現できるのか?という話し合いをしたりしました。

状態の遷移先を事前にHashMapに定義しておくのも、なるほどなぁと思いました。こうやってif文を減らしていくのか…。

読めば読むほど、リファクタリングがしたくなる本ですね!しかしなんか読書会の場ではリファクタリングに対して後ろ向きな意見がちらほら出て、やや残念な感じでした。リファクタリングしたらテストし直さないといけなくなるから…と。え、テストがあるからリファクタリングできるんじゃないの?って話したんですが、手動テストし直さないといけなくなるんで、というので、なんかルールが間違ってるんじゃない?ということは言いましたが、他のチームのことなのでこれ以上はとやかくは言えず。日々、リファクタリングに取り組んでほしい!

「現場で役立つシステム設計の原則」読書会 vol.1

最近、社内勉強会で、「現場で役立つシステム設計の原則」読書会をやってます。そして、今年に入ってから会社でテックブログが始まりました。こちらもよろしくおねがいします。

tech.rhizome-e.com

そちらのブログのほうでも、読書会レポートを参加者で交代で書いてます。

しかし、まぁ自分で思ったことはこっちのブログでも書いとこうかなぁと思うので、こっちでも書いときます。

本はこちらです。

1章 小さくまとめて分かりやすくする

感想は箇条書きでメモってました。

  • メソッドへの切り出し、クラスでの切り出しは既によくやっている
  • 切り出すことでテスト可能になり、安心して使うことができる
  • テスト可能になるとリファクタリングが可能になる
  • 値オブジェクトについては、聞いたことはあったが、あまり活用したことがなかった。
  • こんなに小さなクラスでも定義しまうのかという驚きがあった。よく十徳ナイフのようなごちゃごちゃしたクラスを作ってしまうことがあったが、それくらいなら小さいクラスを作ったほうがマシかなと思った。小さいクラスを作ることに罪悪感というか、なんとなくダメみたいな気持ちになってたが、それが払拭された。
  • 型を付けることで、間違いが起きにくくなる。型を活用する安心感をまだあんまり感じたことがなくて、むしろ野暮ったいくらいに思っていたけれど、最近になってようやく理解できるようになってきた。
  • バリューオブジェクトを意識するだけでも、再利用可能なドメインモデルを沢山作ることができて、1つの会社でやっていると、同じようなドメインモデルを活用することが多いから、仕事が捗りそうだなと感じた。
  • ここにきてようやく初めてオブジェクト指向とはなんぞやを理解したように思えた。

雑感

1章を読んだだけで、かなり目から鱗が落ちたような感じでした。俺は全然オブジェクト指向をちゃんと理解できてなかったなと痛感しました。

1章を読んだ後に、試しにJavaScriptをTypeScriptに変えてみようかなと思い、 1つのファイルを修正してみたのですが、型を意識することと、値オブジェクトを意識するようにしたら、「読むだけで意味のわかるコード」になったなと思いました。 もちろん、今までも意味がわかるようにメソッドに切り出して処理に意味のある名前を付けていたのだけれど、中で扱っている値はいわゆるプリミティブな値のままだったので、わちゃわちゃやってるなぁという感じでした。

確実にプログラマとしての腕が上がったな、という気持ちになれたので、この後の章を読んでいくのが楽しみになりました。

読者ハ読ムナ(笑)を読んだ

後輩くんと週に一度、週報を作るときにミーティングしているんだけれど、その時に読んでますって言われた本で、どんな本か聞いたら面白そうだったので私も電子書籍で買ってみた。

あらすじは、「うしおととら」や「からくりサーカス」などで有名な藤田和日郎さんと、その編集担当だった武者さんが、架空の新人アシスタントにアドバイスしていきながら漫画家としてデビューするまで色々とアドバイスをするという話です。

うしおととらにしても、からくりサーカスにしても、大学の近くの漫画食堂で読破したんですが(20年前近くじゃねーの…)、どっちもあんまり内容覚えてない…けれど、からくりサーカスはめっちゃ面白かったという記憶だけある。持っていない漫画のストーリーすぐ忘れてしまう。

話が脱線してしまったんですが、めっちゃ為になりました。

序盤の話

序盤は、まずアシスタントとして藤田さんのスタジオに入ることになるので、そこでルールを教わります。それが「無口禁止」。理由は色々と語られていますが、

  • あなたは新人だからどういう人かわからない
  • あなたも周囲の人のことがわからない
  • コミュニケーションを取って、お互いにどういう人かわかりあいましょう
  • 信頼貯金を作りましょう。話さないと貯まりません
  • 新人は信頼貯金がゼロなので、しっかりわかってもらえるように動きましょう
  • いいヤツじゃないと信頼貯金は貯まらないよ
  • 他人に興味を持ちましょう!

という感じだったと思います。

その話の後くらいに、今度は「映画を一緒に見る」というのがありました。映画を見た後、その映画の評価を点数付きで発表して、その理由をちゃんと言葉にする、というものでした。これも後々の話で出てくる理由も含めて書くと、

  • その人の着眼点がわかるようになる
  • どういうジャンルが好きとかの傾向がわかるようになる
  • ふんわりした理由はダメ。なぜ好きか、嫌いか、ちゃんと理由を考えろ。
  • これは、自分の漫画を客観視するための訓練でもある
  • 漫画のネタのヒントや気付きを貰えることもある
  • 「あの映画の爆発のシーンみたいな感じで描いて」で伝わるようになる

みたいな感じだったかな。

なんかこのあたりの話を読んでいたら、「めちゃめちゃチームビルディングやん」と思って読んでました。特に映画を一緒に見るの件(くだり)は、私が読書会やっているときの狙いと結構似ていたので、違う業界でも似たような手法があるんやなぁと興味深く読みました。

ネームへのダメ出し

新人漫画家なので、連載を狙うべく、アシスタントをしながらネーム(話の下書き)を描いて、編集の武者さんのところに持ち込んでいくわけですが、そこで色々とダメ出しされます。そして、ダメ出しされた内容を元に藤田さんが「武者さんはこう言いたかったんじゃない?」とか「自分のときはこうだった」というアドバイスをくれます。とはいえ、そのネームに対しても藤田さんからのダメ出しもあります。

これも完全にコードレビューと被ってて面白かったんですが、この新人漫画家は武者さんダメ出しされて傷つくんですが、コードレビューでもコードのダメ出しをしているのに人格攻撃をされたと受け取ってしまうことがありますよね。

このあたりについて、藤田さんが「ネームに対する思い入れが強いから傷つく。自分に対するダメ出しだと思ってしまう。でも、ネームに対して言ってるだけよ。もっと良くなってほしいから言ってるの。自分たちが映画を見た後に点数つけてるのと一緒」というふうに言ってます。いやもうホントにその通り…。まぁ必要以上に汚い言葉を使ってレビューする人もいることはあるので、なんとも言えないんですが、それはまぁその人の問題ってことにして…。

他人の批評は素直に受け取りなさいってことと、批評でわからないところがあったら質問しまくれって書いてあって、「素直さは大事よ…」と頷いてました。レビューで人のコードを読むこともあるでしょうし、どういうコードが世間一般で良いコードと言われているかを探求することで、自分のコードを客観的に見られる視点を身に着けないと、レビュー受ける度にグサグサ傷ついてしまう。とはいえ、傷つきたくないからと殻に閉じこもられてしまうと非常にやりづらい。漫画の業界でも、ダメ出しが嫌になって辞めちゃったり、同人誌を描く方に行ったりという話がありました。(※別に同人誌を批判していたわけではないです)

その他のところ

それからもネームや絵にダメ出しされ続けて、言われた通り修正してもまたダメ出しされて…という感じで、なかなか心にくるものがあります。 途中では、同期の漫画家が連載をスタートさせたりしていて、焦りを感じているときもありました。流行のジャンルの漫画を描かないとダメなんじゃないか?とか、知り合いの出版社なら漫画描けるよって誘われたりとか。 しかしまぁそれも本質的なところの「キミは何が描きたいの?どこ(の出版社)で描きたいの?」っていうところに帰結していきます。

何を軸にしてエンジニアとしてやっていくか、という話とか流行の技術に振り回されたりするような話と似ているなぁと思いながら読んでました。そして、「外ではなく内を見つめろ」っていうアドバイスがズーンと突き刺さりますね。自分の価値観・情熱をしっかり持つこと。内省についてまで書かれていて、なんてすごい本だ!と思いました。

どんな業種の新人でも結構当てはまるのでは?

まぁ私はIT業界なもんですから、そういう視点でわりかし藤田先生に感情移入しながら読んでました。 プロを志すのであれば、楽しく面白く心構えを学べる良書だと思いました!

藤田さんや武者さんが話しかけるような形式の本なので、スルスル読めますし、単純に漫画家がデビューするまでの世界の話としての読み物としても面白いですよ!

Hash#digの逆を行うHash#buryを定義するgem buryを作った

先日、新しくgemを作ってリリースしました。

リポジトリはここ。

github.com

Hash#digの逆とは?

Hash#digは、引数に渡されたkeyの配列でHashを掘っていくメソッドです。

hash = { a: { b: { c: 1 } } }
hash.dig(:a, :b, :c) # => 1

今回作ったやつは、それの逆を行います。引数で渡されたkeyの配列のところに値を埋め込みます。

require 'bury'

hash = {}
hash.bury([:a, :b, :c], 1) # => { a: { b: { c: 1 } } }

なお、digは「掘る」という意味なので、埋めるという意味のburyと名付けました。

途中のkeyが重複しても考慮される

途中のkeyが重複したらそれを検知してマージしてます。

require 'bury'

hash = { a: { b: { d: 2 } } }
hash.bury([:a, :b, :c], 1) # => { a: { b: { c: 1, d: 2 } } }

なんで作ったの?

Hashを動的に作りたかったのだけれど、Hashの深いネスト構造を作るのが大変だったので、作った次第です。今やっている作業を楽にするために作った完全に俺得なメソッドですが、もしかしたらこういう再帰的にHashをマージしたい需要はあるかもなぁと思ってgemにしました。

テストはminitestで書いてます。minitestは早くて簡単。

実装ポイント

Hashクラスへのメソッド追加のため、bury以外のメソッドを生やしたくなかったので、再帰的な処理をlambdaにしてメソッド内に閉じ込めました。

bury/bury.rb at 467750a62bc55959b03ad9ab680c109313105a11 · patorash/bury · GitHub

既に改善点が…

会社のTeamsで、こんなのを作ったと書いていたら、mergeメソッドにブロックを渡すとkeyが重複している際の処理が書けますよと教えてもらったので、それを使ってリファクタリングしたい所存。知らんかった…。めちゃ再帰でゴリ押ししてしまった。

docs.ruby-lang.org

しかし、公開するとフィードバックがあるのでありがたい😀

追記

リファクタリングを行い、かなりシンプルなコードになりました。これだけでよかったんか…😇

https://github.com/patorash/bury/blob/v2.0.0/lib/bury.rb

あと、元々のメソッドが破壊的メソッドなのに!マークのないメソッドだったので、非破壊的メソッドと破壊的メソッドを分けて定義しました。これで更に使いやすくなるはず。

2022年の目標

年末年始に読んだ本

年末年始に本を読んでいて、大変面白かったのと参考になった。

最高の体調

たいていのことは20時間で習得できる

科学的に正しい英語勉強法

結構これらの内容がリンクしていて、目標を考えるのによかった。

「最高の体調」で学んだこと

  • パレオ式生活がいい
  • 現代文明から離れる時間を作る
  • 一度にたくさんのことをやらない

「たいていのことは20時間で習得できる」で学んだこと

  • たいていのことは20時間で習得できる
  • しかし、同時に色々手を出していると習得できない。習得するまでは1つに絞れ。
  • 習得したら、次のものに移れ。
  • 学習と練習は違う。
  • 学習だけでは上手になれない。
  • 練習だけではなかなか上手になれない。
  • 練習して、さらに学習すると、上達しやすい。

「科学的に正しい英語勉強法」で学んだこと

  • もっといいものがあると思って他の教材に目移りするから習得できない
  • 英語勉強法というよりは、全ての勉強法について言えることだった
  • インプットはほどほどに、アウトプットを増やせ
  • 苦しんで思い出そうとする努力をしてから答えを見ろ

今年の目標

あれこれ沢山考えるとその数だけ思考にリソースを奪われてしまうので、とりあえず3つに絞る。

  1. 英語をマスターする
  2. Go言語をマスターする
  3. デジタルミニマリストになる

Go言語以外はもう取り組んでいる。とりあえず英語は単語を知らなさすぎるので、勉強中。単語集とか見ている。あと、久々にエンジリッシュに取り組んでいる。継続してマスターしていきたい。英語の問題集も家にあるので、そのあたりをやっていく。単語と文法と熟語をある程度インプットしたら、問題集をガリガリやっていくことにする。

マスターって言っても、どうしたらマスターしたと言えるのか?っていうのを定義しないといけないので、雑にTOEIC600点くらいに設定しておこうか…。TOEIC受けたことがないので、勉強をある程度したら、今年中に1度は受けてみようかなと思う。

デジタルミニマリストの内容と最高の体調の内容は繋がるところがある。

patorash.hatenablog.com

SNSを見る時間が減るといろいろとできる時間が増えたので家事が捗ったんだが、これを勉強の時間に使っていきたい。スマホには、雨音のBGMを流す役割を与えてしまえば、なんとなくスマホが気になりにくくなった。スマホを近くに置かなかったら、SNSの利用時間が激減するので、あとは運動・勉強・家事に時間を割り振っていく。まぁ本を読むのはタブレットになるので、デジタルを手放すのは難しいが、ChromebookからSNSアプリを削除しておけばよさそう。

世の中の流れに疎くなりそうではあるけれど、別にいいかなぁという気持ちになっている。できることを増やすことにフォーカスする。