DDD以外の設計手法についてご教示いただきたく、DDDの主張をある程度正確に理解した上でDDDをこき下ろしているイメージの強いくまぎさんに質問させていただきました。

最近はソフトウェアの設計について調べると、DDDについての記事ばかりで辟易する一方、私がエンジニアになった頃にDDDに勢いがあった影響もあって私自身DDD以外の良い設計とされているものを知らず、DDDに胡散臭さを感じつつもDDDの考え方にとらわれている、毒親の影響を受けた子供のような状態から抜け出せずにいます。

その最たる例がリポジトリパターンです。

よく依存性の逆転・DIと一緒に語られますが、くまぎさんがおっしゃる通り余計にインターフェースを切るのはイケてないと感じます。また、DI抜きにしても、リポトリパターン由来の様々な問題(N+1やバルクアップデート、管理画面用のメソッド生やしたくなる問題など)に対する解決策として提示されている手法をみて、自分で問題をでっち上げているように見えます。その一方で、ドメインのモデルを集約という単位で、リポジトリを介してDBに出し入れするのは便利そうに感じます。リポジトリパターンを使わずにドメインのモデルの入出力が書き散らされるとモデルにプロパティを追加するときなどにあちこち修正の必要が出て面倒です。

そもそもリポジトリパターンのようなDBとのやりとりをするところにドメイン知識を持ち込まないという考えに無理があるのでしょうか?別の方への回答に「DDDの人たちが言うようなドメインロジックを中心に据えてストレージをリポジトリやインフラ層に追い出したりするアイデアには反対です。疎結合を有難がる風潮が念仏のように唱えられがちですが、データはアプリケーションの本尊そのものであって、脇に置いたりあとから気軽に挿げ替えたりするものではありません。言い換えるとそこに疎結合を求めてはいけません。」と書いていましたが、くまぎさんがアプリケーションを書くときは、DBとドメインロジックをベッタリさせて書いていますか?ドメインロジックのテストを書くときはDBを立ち上げてデータを入れてテストしているのでしょうか?

くまぎさんが実践しているプラクティス等あればぜひご紹介いただきたいです。

そ、そんなにこき下ろしているでしょうか…?

プログラミングにおいて教条的に何らかの思想を上から振り下ろす事に対して違和感を持っているだけのつもりで、代わりに何らかの思想を振り回す事が良いとも思っていません。

クリーンアーキテクチャの書籍では「データベースなんかは玄関のドアノブのパーツぐらいの重要度しか無いのでいつでもドアノブを取り替えれるようにだけしておいて本題に集中しろ」みたいな事を書いていたので流石にそれは無茶というか巨大プロジェクトがエアプなのかって感じる事はありました。改めて主張を整理したいと思います。

まずDBとドメインロジックをベッタリさせて書いているか?という問いですがYESです。特にGoogleの場合は「SpannerからMySQLに移行しよう」みたいな話はまず出てこないですし、仮に移行するならそういう独立したプロジェクトとしてチームで取り組む規模の話になることでしょう。またユニットテストでも可能な限り本物に近い環境を使うように努力せよという指針も公開されています。

Increase Test Fidelity By Avoiding Mocks

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT e...

testing.googleblog.com

https://testing.googleblog.com/2024/02/increase-test-fidelity-by-avoiding-mocks.html

ドメインロジックがベッタリしていると困るケースとしては他にロジック自体の意味がわかりにくくなるというケースがあります。ただこちらは純粋にコードの抽象度の話であって、不慣れな人がコードを書いたら抽象度の高い業務ロジックとDB実装側の都合から来る個々のコードが入り乱れて読みにくくなるのは「DDDを適用しなかったせい」ではなくて「コードの再利用性が低いせい」です。

オブジェクト指向や他のパラダイムの事を神格化して聖典のように崇める人もいますが、一介のコード書きから見たらそれらすべて「コード整理術」の一部でしかありません。膨れ上がり続けるソースコードと向き合って増加し続ける複雑さをどう整頓するかがすべてです。整頓することの恩恵を部屋の掃除程度にしか思ってない人もいますが、コードが整理されるとバグ修正も機能追加も「ここのモジュールが本来ではこうするべきだったから」という形で責任が分割されるのでプログラミングの難度が大幅に下がるという効能があります。言い換えれば、将来のプログラミングの難度を下げる事ができるのが良い抽象化、そうでないならどんなプラクティスも自己満足です。究極的には例えば通販なら注文ロジックの最上位が「店舗.発注(注文票)」ぐらいになっていれば「これからはこういう条件の注文が来た時は却下したい」等と仕様追加があった時にどこに手を加えるべきか自明になって便利、ぐらいの簡単な話です。

ここにおいてすべての値を値オブジェクトにラッピングするのは例えるなら整頓用の箱を大量に用意する事で部屋が整頓できると信じるようなものであって有害ですらあります。

クリーンとかオニオンとかそれぞれの言葉でロジックを階層化することで複雑さを閉じ込めたと主張する人は多いです。中にはただ単に教典にある形に近くなった事を喜ぶ人もいるかも知れません。僕がプログラミング初心者に何度も強調して伝えているのは「再利用する予定のないロジックでも再利用性を重視したコードを書け」という指針です。レイヤーを分ける事自体は善にも悪にもなりますが、そのレイヤー分けの良し悪しを決めるのは「直交性」です。レイヤーごとに責務が明らかで凝集性が高いコードを…などと説明してもピンと来ない事が多いですが「仮にこの部分だけを別の目的で使いまわすならどんなインタフェースが露出していれば使いやすいか、を考える事が自ずと責務の分割と凝集性を高めてくれます(最後はセンスの問題になりますが…)。再利用性を優先することが直交性を高める為の近道である、というのはプログラミングを始めたばかりの自分にも繰り返し伝えたい直感に反する経験則です。

再利用性を優先した結果、リポジトリパターンと呼べる形にコードが落ち着く事自体はそんなにおかしな話ではありません。アプリロジックという究極的には再利用性皆無の極北からグラデーションのように段階を経てOSやDBのAPIという普遍性の塊までの間をどのように整理区分するかがプログラマに課せられた仕事であって、聖典を振り回すような場所ではないと僕は考えています。

アプリのコードの優れたアーキテクチャには究極的には未来予知が必要になります。例えば「将来的にここに仕様変更が来ると思うので拡張余地を残した」といったドメイン知識の注入が効くケースは大いにあります。ただしそれが当たったからといってそのプラクティスがどこでも通用する物であることは意味しません。重要なのは将来の変更に対して頑健であることで、将来の変更を助ける方法は小難しいテクニックを使う事とは限りません。特に最近始まったばかりのサービスというのはプロダクトマネージャにすらどこに何が起きるかわからないものですから、その内部は煮え滾る溶岩のように柔軟であるべきです。拡張性やエンバグのしにくさ(セキュアコーディングとか言いますよね)よりもコードの書き直しやすさと消しやすさに重点を置いています。拡張性ではない書き直しやすさというのは説明がしにくい指標ですが、およそ消しやすさとほぼ同義です。アプリ側の都合で数千行のコードがまるっと要らなくなることはザラに起きますが、本当にその数千行を消して良いかを判断するパッチを作るとしてその複雑さが低いほど消しやすいコードです。やたらとインタフェースを切って拡張余地を量産する場合、実際に不要だった拡張余地自体を消すのはどこから依存されているかわからなくて追加の数倍の神経を使うので、そうならないように自信を持って消し飛ばしていけるようなコードを心がけて書いています。ある程度サービスの概形が固まってきてから内部を冷え固まらせていく作業は新機能追加やデバッグのタイミングでコードの再利用と称してゴリッと書き換えて行けばよくて、人によってはこれをリファクタリングと呼ぶ人もいるでしょう。

長くなったのでまとめると

  • あらゆる教条主義は基本的に嫌いだけど最終的に似るのは別に良い

  • 凝集とか難しい言葉を使うより再利用性を意識する方が直交性に効く

  • 依存が少なくて消しやすいコードは正義、コードが若い時ほど消しやすさを優先

こんな感じになります。プログラマごとに違う考えがあると思うので他の意見も聞いてみたいですね。

9時間(8時間更新)
💌 スーパーレターへの回答方針

機密事項は一切答えません。


0 / 20000
¥0

利用規約プライバシーポリシーに同意の上ご利用ください

熊崎 宏樹さんの過去の回答
  • 消えません。

    産業革命の時ですら「蒸気機関で労働が消える」などと騒いでいたという話がありますが一向に労働はなくなっていません。汎用AIをうまく使える人にさらなる仕事が降り注ぐだけであって、飛脚100人分の労働がトラックの運転手一人で置き換わったみたいな話がそこかしこで起きるだけと見ています。

    23日
  • 趣味として何かを作ってるぶんには「影響力の大きいものを作った」という事を持ってして「あいつは技術力が高い」としています。

    ソフトウェアエンジニアの本職としては「あの人がいると仕事が進む」というのが技術力の高い人の肌感覚です。つまり仕様を手早く整理して人に伝え懸念点を素早く解決し、メンバーの疑問に答え役割分担を適切にこなしながらマネージャからの信頼も厚い、そういう人が強いです。

    23日
  • 「日本はいつでも自販機でミルクティーが買えるのが嬉しい」とインド系の人が言っていたのが意外でした。午後の紅茶が好きみたいです。

    23日
  • 再帰とか抽象構文木とかマクロですかね…。人によって「最低限」の基準が違うので論じにくい話です。

    この手のメタな知識はまさにLISPの世界で熱心に研究され続けて来たので「計算機プログラムの構造と解釈」通称SICPという本に集まっており、だからこそ熱心なプログラマはこの分厚い本を崇めたりLISP使いになったりします。昔はSICPがマサチューセッツ工科大学の教科書だったりしたのですが最近はPythonをやるようになったという噂もあって、それほどLISPが必須知識として見做されなくなってきた風潮を感じます。もちろん興味が有るのであれば是非邁進してください。

    1か月
  • テック企業で働く気ならスキルセットをテックに寄せる方が近道ですし、アメリカ系の企業なら社内の公用語は英語でしょうから英語を社内公用語に使っている会社なら英語の練習にもなっていいですね。

    英語が公用語かつテック系で日本にオフィスを置いている会社は都内にたくさんありますのでぜひ検索してみてください。

    2か月
  • そんなに高い志など無く、自分が好きな分野の中で社会から需要がある所を選んだ感じです。ただし、MLとかデータサイエンティストなどは数式とにらめっこする時間の方が長そうなので、数学力ではなくてCPUアーキテクチャとかそういう知識が活かせそうな分野を選びました。

    最近は「異世界転生するなら俺TUEEEできる所を狙いたい」というモチベーションぐらいで充分なんじゃないかと思っています。

    2か月
  • いつもXでmondの回答拝見して参考にさせて頂いたいます。 今回初質問になりますが、よろしくお願い致します。 相談内容は「どうすれば自分がわからない部分を言語化して自分で解決して理解できるようになるか」です。 自分は普段Webアプリケーション開発に従事しておりエンジニア歴は6年目になります。 簡単なCRUDのAPIを実装したり、フロントエンドで画面を構築はできるつもりです。 しかし、少しでも知識の深掘りが要求されると途端につまづいてしまいます。 例としてパフォーマンスの高いSQLを書けるようになるためRDBMSにおけるB-Tree Indexの仕組み(なぜインデックスを貼るとクエリ処理が早くなるのか)を勉強したものの、どんな入門書やネットの解説記事、各種RDBMSの公式リファレンスを読んでも理解出来ませんでした。 他にもRDBだけでなくアルゴリズムとデータ構造やネットワークなどあらゆる分野で少し難しいレベルが要求されると何が分からないのかが分からず八方塞がりになってしまいます。 そんな状態がここ2,3年続いており、自分のエンジニアとしての技術レベルが停滞しています。認めたくないものの自分のエンジニアとしては限界なのかもしれないと感じています。 もちろん、他の方が自分の何倍も技術に向き合われていて単に自分の努力不足であることは承知しております。 しかし、「何を勉強しても何を勉強しても何が分からないのかを言語化できず、自学自習のサイクルを回せない」のではエンジニアとして失格であると考えています。 しかしエンジニアであることを諦められないため、「どうすれば自分がわからない部分を言語化して自分で解決して理解できるようになるか」をアドバイス頂きたいです。 お手数おかけしますがお手数おかけしますが、ご回答頂けますと幸いです。

  • お世話になっております。コンピュータサイエンスについて質問があります。 現在 23 歳の高卒ソフトウェアエンジニアで CS を体系的に学びたく学士を取得しようと思っています。やる気があれば修士以降もやりたいです。 単純にコンピュータやコードを書くのが好きでもっと詳しくなりたかったり、自分に出来ることを増やしたりビッグテックで働いてみたいなど理由は色々あります。 選択肢は2つ考えていて、働きながら海外の大学のオンライン講義を受けるか、国内の大学で学ぶため受験からやり直すかです。 単純に比較をするのは難しく懸念点も様々ですが、気にしているのは卒業後の年齢で入社しようとしても足切りされるのではないかという点を心配しています。高度な仕事をやりたくて勉強したのに土俵に立つことすら出来なくなってしまったら少し悲しいです。社会人大学生としてやっていく方がリスクが少ないのは分かっているのですが、まだ決め切れておらず kumagi さんが同じ立場だったらどうするか意見をいただきたいです。 色んな求人を見たりするのですが大体必須条件に CS の学士・修士または同等の実務経験と書かれていることが多く CS に関する知識の必要性を日々感じています。コーディングテスト?は受けたことが無いので分からないのですが一応 AtCoder 黄なのでなんとか行けるかな、、と思っていたりもするのですが… 競プロをやってきて凄い人に沢山出会うのですが、経歴を見ると大体東大を通っていて凄い事をやりたいなら自分もそういうところで学ぶべきなのかと考えてしまいます。 長文になってしまいました、申し訳ありません。 お手数をおかけしますがご回答いただけますと幸いです。

  • 全くですね。アセンブラを眺めるのなんて顕微鏡で拡大して観察するようなもので、今どこを見ているかを把握することすら難儀です。

    僕はアセンブラと日常的に戯れるエンジニアではないのですが、自分の書いたC++が自分の狙った通りの機械語に変換されているかを確認するために godbolt.org にコード片を入れています。ベンチマークを取っている時にタイトなループの内側でインライン化することを期待していた関数がやけに遅い時などに役立ちます。

    5か月
  • どれだけ正確に覚えているかは個人差があると思いますが、うちの子は語ってくれます。ただし「ママのおなかのなかにいるときにあーまーどこあくりあしたの」ぐらい適当な事いうので僕も「うんうん、お腹の中は暇だろうからプレステ入れといたんだよね」と応じています。

    7か月
  • 僕ならPostgreSQLを選びます。

    ローカルで立ち上がるのでアプリ開発中のデバッグが簡単なのとSpannerやAlloy DBやAurora PostgreSQL等のクラウドネイティブなRDBMSが互換インタフェースを備えている事が理由です。

    追記型という形を取っているため行内の更新が多いとインデックス側の更新が多くなりMySQLに乗り換えるUberのような事例もありますがそういうのは発生してから対策しても遅くないのでEarly Optimizationと割り切って行きます。

    1年
  • 岐阜県の山間部で育って東京に来ました。

    都心部の休日に出歩いている人間の多さに驚きました。こんな人だかりは夏祭りですら見たことねぇ!今日は何の祭りなの?えっ何もなくてこの人数!?!?

    1年
  • 特に気にしていません。美味しければ何でもOKです。カレーに牛乳は何だかカレーを甘く感じれて美味しいですよね。

    1年
  • 僕の専門ではありませんが、競技プログラミングの分野では異口同音にtouristことゲンナジー・コロトケビッチ氏の名前が挙がります。

    彼は競技プログラミングの分野で幼少(11歳!?)の頃から目覚ましい成果を出し続け、2023年に29歳になります。競技プログラミングの大抵の有名な大会で優勝を総なめにしています(詳細はwikipedia参照)。

    1年