ドメイン駆動設計 実践のための原則を4つ考えてみた

 『エリック・エヴァンスのドメイン駆動設計』(以下DDD本と呼ぶ)の原著出版から十数年が経過した今、DDD本に書かれている内容は、吟味されアップデートされるべき時が来ている。このアップデートに盛り込みたい内容を、4つの原則という形で考えてみた。

なお、以下では「EvansのDDD本の内容」と「ドメイン駆動設計というコンセプト」は重なる部分があるにせよ、それぞれが指す対象は異なるものだとしている。この違いは本文中で触れるが、表記として「DDD本」は本を指し、「ドメイン駆動設計」はコンセプトの方を指すようにしている。

DDD本とドメイン駆動設計

DDD本では、ドメイン駆動設計というコンセプトが導入された。ドメイン駆動設計というコンセプトは、ソフトウェアエンジニアの一般教養といえるほど、今ではその価値が認められている。同様のアイデアは、EvansがDDD本を執筆した時代ですら、すでに先人たちが口にしてきていたことだと思う。たとえそうだとしても、このコンセプトをドメイン駆動設計と名付け、著書としてまとめあげてソフトウェアエンジニア界にもたらしたことには、とても大きな価値があるだろう。

DDD本には何が書かれているのか?

DDD本に書かれている内容を、一歩ひいた立ち位置でまとめると次のようになる。

  • Evansがドメイン駆動設計というコンセプトを明に暗に思い浮かべながら、実務で取り組んだ成功/失敗エピソード 
  • Evansが自分の手持ちの技術スタック(=オブジェクト指向分析・設計・実装)と、ドメイン駆動設計というまだ明確にはなっていないコンセプトをミックスし、実務で試す中で生まれてきた、ビジネスドメイン向けのEvans流アプローチ(モデルのビルディングブロックや、いくつかのパターン)

DDD本にはエピソードが豊富に書かれている。特に、さまざまな理由によってモデルが変化していく過程が綴られているのは特徴的だし、DDD本の面白いところでもある。個人的なお気に入りを1つ挙げるならば、深いモデルの章で紹介される船荷証券のエピソードだ。何しろ、最初の時期に考えていたモデルの要素は、最終的にはまったく不要になる話で、読めば読むほど、その最初の時期はなぜそんなことになってしまったのかというような疑問が次々と湧いてくる。Evansが言う「深いモデル」の「深さ」とは一体何なのかを考えていく契機にもなった。

DDD本に書かれているEvans流アプローチで紹介されるのは、汎用的な概念・パターンが多い。これらは一見すると、さまざまなドメインに対して適用可能に思える。エンティティやリポジトリといったパターンを使い、ある程度うまく機能するシステムを作れるケースは、現在でも多くある。また、仕様パターンの提案や、仕様パターンをリポジトリやファクトリと協調させる設計などは、形はそのままでは無いにせよ、アイデアとしては今でも有用だ。このように、Evans流アプローチにも学びどころはある。

しかし、ビジネスドメインに的を絞っても、Evans流アプローチには弱い点がある。その弱点をこの記事では趣旨とだいぶズレてしまうため述べないが、Evans流に一点張りするのは危険だということだけ触れておく。

DDD本には何が書かれていないのか?

DDD本を、ドメイン駆動設計のコンセプトを的確に伝えるための書物として見た場合、率直に言って重要なことが書かれておらず、適切ではない。重要だが書かれていないことがあるのだ。

DDD本ではドメイン駆動設計というコンセプトに対して、その1つの実現形態であるEvans流のモデリングと設計のエピソードがパターン形式で綴られている。しかし、これだけがドメイン駆動設計に当てはまる手法というわけではない。

どんなアプローチも万能ではなく、必ず射程が存在する。Evans流アプローチの射程は、贔屓目にいってもビジネスドメインであり、SoR(記録系のシステム)ドメインであり、また、エンティティを中心に形作られるドメインだろう。

世の中には、これに当てはまらないドメインが多数ある。また、無理に当てはめると機能しないシステムができあがってしまうようなドメインも多数ある。グラフの探索機能や行列計算ライブラリ、機械学習のためのフレームワークなどは、エンティティやリポジトリ、値オブジェクトといったパターンを単純に当てはめることが難しかったり、無理に当てはめると失敗しそうなドメインとして分かりやすい。

このようなドメインに取り組む場合でも、ドメイン駆動設計というコンセプトは役立つはずだ。ドメイン駆動設計というコンセプトは、あらゆるドメインの問題に取り組む際に有用だからだ。しかし、このようなコンセプトの本質的な内容を知りたくても、DDD本に書かれているエピソードからは、フワフワした輪郭としてしか浮かび上がってこない。DDD本には明確には述べられていないのだ。

まとめると、次の2つが明確な形では書かれていないことになる。

  • ドメイン駆動設計というコンセプト
  • ドメイン駆動設計というコンセプトと、その1つの実現形態であるEvans流アプローチとの関係性およびその位置づけ

この2つの欠点を補うようなアップデートがDDD本になされるか、または新たな書籍が執筆されるべき時だと思う。そんなささやかな期待を持ちつつ、私はこの記事で、DDD本の2つの欠点を補う内容を4つの原則にあらわしてみた。 

どうすればドメイン駆動設計を学べるのか?

核心を述べよう。どうすればドメイン駆動設計を学べるのか? この問いに対する私の答えは「ドメイン駆動設計を学ぼうとするな。ドメインについて学べ。」だ。多くの先人達も同じことを言われている。私はこのことをもっと強調したい。これは、ドメイン駆動設計を学ぶ際に必ず心にとめておかなければならない原則なのだ。

ドメイン駆動設計を学ぶ際に心にとめておく原則

ドメインについて学ぶ > ドメイン駆動設計を学ぶ

ドメイン駆動設計というコンセプトは、詰まるところ設計技法そのものではない。これについては、twitterでsugimoto_kei氏の次のtweetでも言われている。

ドメイン駆動設計について学ぶな、DDD本を読むな、とまで言うつもりはない。 しかし、ドメイン駆動設計というコンセプトで表される設計活動を学んで実践し会得するには、実際にドメインの問題と向き合って格闘するのが一番なのだ。それ以外に身につける方法はないとも言える。それに加え、自分が向き合っているドメインの問題は、どのように分析できるのか、どのようにモデル化できるのか、どんな設計が使えるか、、、こういったことを考えるヒントは、DDD本にしかないわけではない。むしろDDD本から離れて、そのドメインに向き合った先人たちの考えたことを素直に参考にした方がよい場合が多い(もちろん、技術の進歩というエッセンスは自分で加える必要があることは言うまでもない)。そうして、ドメインの問題の解決に没頭することが、ドメイン駆動設計であるとも言える。

DDD本に書いてあるEvansのエピソードは、そんな没頭の合間に、自分の向いている目線を確かめ、気持ちを再びドメインに引き戻すためのリフレッシュ材料として読めばよいのだ。

しかし、これだけでは結局「ドメイン駆動設計」というコンセプトが何なのか分からない。「ドメインに向き合っていれば自然と身につく」なんて言われても、その経験がないうちに納得できるはずがないし、「間違ったドメイン駆動設計」が存在し得ないようなら、コンセプトとして持ち出す意義も納得できない。ドメイン駆動設計のコンセプトを、日々の活動レベルで使っていくためには、実践者が自分の進む方向を自ら見出していけるような、分かりやすい指針があるとよい。これを3つの原則として表してみた。

ドメインモデルに取り組むハート

 ドメインモデルに取り組むハートの3原則

1. ドメインモデルとは、開発者=設計者が創り出すものだ

2. ドメインの問題にウェイトを置こう

3. ドメインを見る目、解決策を見る目を養おう

ドメインモデルは、開発者=設計者が自ら創り出すもの、というのが私の考えだ。設計は、大なり小なり何らかの解決の仕組みを創り出すプロセスであって、そこにクリエイティブなマインドは欠かせない。ドメイン駆動設計では、このクリエイティブ・マインドを、ドメインモデルにおいて発揮することになる。ドメインモデルのモデリングと設計は、外から与えられた要件をなぞるだけの行為ではないのだ。 

そして、ドメインモデルにクリエイティブに取り組む際、設計者の先入観が邪魔になることがある。どういうことか。開発者=設計者は、問題を理解するためのスタート地点として、必然的に「手持ちの技術」 で捉えようとしてしまう。その「手持ちの技術」は自分の手足のような存在、さらに言えば空気のような存在なので、あえてそれを使っているとは意識しない。問題のスタートから少しでも理解が進んで何らかの形が見え始めると、空気として存在している手持ちの技術が、その問題の解決に適しているのかを疑おうとしなくなってしまうのだ。

しかし、大事なのは、ドメインの問題をより上手く解決することだ。これを達成するためには、理解が進んで出来上がってきた形を疑うことだけでなく、ときには最初に用意した手持ちの技術さえ疑ってみる必要がある。この疑いは、慣れていないととても苦しい行為だ。なぜなら、自分自身のスキルや成果を否定するように感じるからだ。だが、ドメインの問題を解決することにウェイトを置くという共通理解があれば、余計な不安を抱えることもなくなる。自信を持ってスタート地点のはしごを外せるようになる。それに加え、自分にはまだ未知の技術だとしても、ドメインの問題をより上手く解決しそうだと客観的に判断できれば、学んで採用していける。

このようなドメインモデルに対する取り組みでは、開発者=設計者の「ドメインを見る目」を育てなければならないが、それと同時に、あらためて「解決策=技術を見る目」も育てなければならない。この2つの目は、ドメインに取り組む開発者にとって、どちらも欠かせない両輪なのだ。

ドメインの問題をより上手く解決するという基準に立つと、この2つの目が常に問われ続ける。その目の中には、ドメインの問題に適合するかどうかを判断するための論理力や、必要な時に必要なことを学んで取り入れていける柔軟性も含まれる。とてもハードルが高く聞こえるかもしれないが、これらの技術は、ソフトウェアエンジニアにとって普遍的に役立つ。 

さいごに

ここに述べた4つの原則が、私が『エリック・エヴァンスのドメイン駆動設計』から学んで得たことだ。もちろん、DDD本だけからこのような理解が得られたわけではない。多くの本を読み、先輩方や仲間との議論や対話、さまざまな試行錯誤の結果として得られたものだ。このような経験は私にとっては言葉にできないほど有益だったが、これだけの労力と時間を世の中の多くのエンジニアに強いるのは、良いことではない。ドメイン駆動設計のコンセプトの伝え方、そして何よりドメイン駆動設計というコンセプト自体は、今後もっと洗練されるべきだろう。そうすれば、ドメイン駆動設計のコンセプトが薄れるのではなく、蒸留されたエッセンスとして後世に伝わっていく。

この4つの原則が、今この瞬間にも生まれてくるドメインの問題を上手く解決するモデルを創り出す一助に(間接的にでも)なれば幸いだ。

 

ソフトウェア開発者の世界観を考える

ソフトウェア開発者の勉強会などに参加すると、最初に持ち時間一人30秒くらいの全員自己紹介タイムがあったりする。「好きなプログラミング言語は?」だとか「使っているフレームワークは?」など、勉強会の参加者層に対して比較的通じやすいお題が都度用意されたりもする。

そんな自己紹介のお題として「あなたのソフトウェアシステムに対する世界観は?」なんて出される勉強会があったら面白い、と思うのは少数派だろうか。

私の尊敬するエンジニアの先輩方は、必ずと言ってよいほど溢れんばかりの世界観をお持ちだ。システム観、モデル観、設計観、設計者観。そう呼べる何かが話す言葉の端々から滲み出ていて、興味をそそられずにはいられない。

しかし果たして、私自身はどんな世界観でもってソフトウェアシステムを眺めているのだろうか。自己紹介でネタにできるほどの世界観を持ち合わせてはいないのかもしれない。自分の世界観を客観的に考えるためにも、今持っている感覚から一歩引いて、いくつかの軸から有り得そうな世界観を想像してみることにしよう。

あらかじめ断っておくと、以下でとりあげる軸は、私が自分の考えを見つめるためにでっち上げたものであって、決してソフトウェア工学で議論されてきた用語などではない。

ドメイン

ソフトウェア工学の中にドメイン工学という分野がある。また、ソフトウェアの設計パターンとしてのドメインモデルという用語がファウラーの書籍でよく知られるようになった。エヴァンスのドメイン駆動設計以降、ドメインというのはソフトウェア開発におけるメジャーな概念になった。しかし、ドメインという言葉に託しているイメージは人それぞれかなり異なっているようだ。その異なり方を分析してさまざまな軸を洗い出すのも有益だと思うが、ここでは2つだけとりあげてみる。

ドメインの個数(または粒度)

ソフトウェアシステムには、いくつのドメインがあるのか? またはその裏返しとして、どのような単位をドメインと呼ぶのか?

  • 単一ドメイン的世界
    1つのソフトウェアシステムは、1つのドメインに対応すると見ている。システムとして機能する1つの固まりが、ドメインである。
  • 複数ドメイン的世界
    1つのソフトウェアシステムは、複数のドメインに分解できると見ている。ドメインによって浮かび上がる対象の粒度や抽象度は様々。

ドメインという言葉の指す対象の粒度としては、複数ドメイン的世界よりも、単一ドメイン的世界の方が大きいものとなっている。複数ドメイン的世界観では、かなり小さな対象でもドメインと呼ぶ。

コアドメイン

ソフトウェアシステムの中で、重要な部分はどれか? エヴァンスのドメイン駆動設計で、「コアドメイン」という1つのパターンとして紹介された。

  • コアドメイン絶対主義
    ソフトウェアシステムには、最も重要なドメインがただ1つ存在すると考えている。
  • コアドメイン相対主義
    ソフトウェアシステムの開発時期などによって取り上げる部分、つまり開発者が対象として見ている部分がコアである。関わる人たちの意思によってコアが決まる。
  • 非コアドメイン主義
    ソフトウェアシステムを構成する個々のドメインにはそれぞれ意味・役割があり、どれか1つを絶対的に重要視することはない。

エヴァンスのドメイン駆動設計では、コアドメインに最も優秀なメンバーを投入せよ、コアドメインを見つけよ等、コアドメイン絶対主義的に読める表現がある。しかしその一方で、コアドメインは、別のアプリケーションにとっては補助的な汎用コンポーネントになるといった記述もあり、コアドメイン相対主義の雰囲気もある。しかし、どちらかといえばコアドメイン絶対主義なのだろう。

しかし、ヴァーン・バーノンの実践ドメイン駆動設計では、複数のチームが異なる対象を担当する。これはコンテキストが違うというだけでなく、それぞれのチームが作り上げるコアが異なると見ることもできるだろう。したがって、ややコアドメイン相対主義だといえる。

コプリンのマルチパラダイムデザインでは、コアドメインという用語は登場せず、問題ドメインや解決ドメインが大小さまざまなドメインによって構成され、そのどれも等しくドメインと呼ぶ。したがって、非コアドメイン主義だといえる。

他方、伝統的なソフトウェア工学およびドメイン工学ではコアドメインという用語は使われず単にドメインと呼ばれるが、それが指すものはいわゆる業務システムのための仕様群であることが多く、実質コアドメイン絶対主義に近いといえる。

オブジェクト

ソフトウェアシステム開発には様々なパラダイムが使われうる。その中のオブジェクト指向のみに焦点をあてても、とても多くの立場がある。「オブジェクトはどこからくるのか」という考えをよく表す軸を1つ取り上げる。 

オブジェクトの由来

  • 自然オブジェクト主義
    ソフトウェアシステムの概念を構成するオブジェクトは、本来現実世界に存在するモノを写し取ったものであるべきと考えている。
  • 自律オブジェクト主義
    ソフトウェアシステムの概念を構成するオブジェクトは、それぞれ自律的な存在であるべきと考えている。
  • 人工オブジェクト主義
    ソフトウェアシステムの概念を構成するオブジェクトは、現実世界の存在や人間の行動様式、概念を参考にしながらも、ソフトウェアの中でうまく機能するように作られた人工物だと考えている。

オブジェクト指向の発明者であるアラン・ケイの文脈では、メッセージによって自律的に制御されるのがオブジェクトだ。

これとは別に、オブジェクトはあくまで現実世界を写し取ったものであるべきとする立場がある。可能な限り現実世界の有様を忠実に表現したオブジェクト群こそが変化に強くソフトウェアとして有益であるという立場だ。

その反対で、オブジェクトはあくまでソフトウェアシステムおよびプログラムコードの設計パーツとして捉え、さまざまな要請やその時使える技術インフラ、プログラミング言語の機能などから、開発者が作り出すものという立場もある。

 

私の世界観

上に挙げた軸から、私が現在どのような世界観を持っているのかを選んでみると、以下のようになる。

  • 複数ドメイン的世界
  • 非コアドメイン主義
  • 人工オブジェクト主義

今の私の考えでは、ドメインが指す対象の粒度はかなり細かい。エヴァンスの書にあるような「輸送」「販売」などをドメインと呼ぶのは間違いではないにしても、ほとんどの場合、その大きさの単位をそのまま扱うようなことがないので、それを1つの範囲として実感しづらいのだ。もっと細かな業務単位だったり、業務に必要な機構だったりをドメインと呼んでいる。ソフトウェアシステムであれば、コンポーネントくらいの単位だ。リクエスト、レスポンス、コネクション、ステートマシン、ストリーム・・・。それぞれが何か1つの概念で表される固まりをドメインと呼んでいる。

これらの細かなパーツが組み合わさり、折り重なりながらソフトウェアシステムを作る。システムには「仕様」というものがあるが、それは商取引のルールと同じようなレイヤーのものだけではない。たとえば、ユーザー向けの分かりやすいユーザーインターフェイス上で作られる情報群を、システム内部に持っている計算ロジックモデルへの入力を表わす情報ツリーに変換して処理するような機能があるとする。この機能において、システム的に重要なのは、ユーザーが操作する部分の情報の構造だろうか? それとも、内部に持っている計算ロジックやそのための入力情報の構造の仕様だろうか? 後者はユーザーが操作するソフトウェアの表面の仕様と何らかの関係はあるにせよ、ソフトウェア内でそれが表される位置やレイヤーは、どちらかというとソフトウェアの内側にあるだろう。さらに付け足すと、この計算ロジックの処理のための数学的な演算機構は、コンポーネントとして独立して作られている、なんてこともある。

何が言いたいのかというと、どれかをコアと定めることはさほど有益ではないと考えているということだ。

そして、上に挙げた「パーツ」というのは、とても人工的だ。何も無いところからスタートしなければいけない場合を除いて、通常は、目の前に人が作ってきた何かがある。自分たちで作ってきたシステムもそこに含まれる。そこにある問題を解決するための方法を大なり小なり考案しなければいけない。既存のソフトウェアや要望と、開発者が持っているプログラミング言語などの道具、新しい技術などから、解決策が生み出される。解決のための仕組み・モデルは、常に開発者が設計し、作り出すものだと考えている。

 

おわりに

自分が持っている世界観を考えてみるというのは、とても面白いし、そんな世界観を議論しあうような場があれば、是非参加したいと思う。だが、語ったり議論したりするには、いくつもの軸を明確にしておく必要もある。そういった理解の積み重ねが必要だから、難しい。

「語りえぬものについては、沈黙せねばならない。」

と、どこかからお叱りを受けぬよう、ソフトウェア開発者として語りうる地平を地道に広げていきたい。

 

「たとえる技術」を読んだ

せきしろ著『たとえる技術』を読んだ。国語に対するニガテ意識が消えない私が、文章になんとかオリジナリティのあるたとえを入れてやろうと、つい頭をひねってしまうほど、たとえ方の技術がやさしく語られた本だ。

たとえる技術

たとえる技術

 

この本では、「たとえる技術」が、時折クスッと笑ってしまうようなたとえの例とともに語られる。この本を読んで私が強く感じたのは、「たとえって、パーソナルな体験の表現で良いのだ」ということだった。本の中では、共感を得やすいたとえを生むために選ぶと良い題材なども紹介されていたので、一般的にはそのようなたとえ方の技術を磨くとよさそうだとは理解できる。しかし、私はそういった共感を得る技術としての「たとえ方」よりも、そのたとえを作り出す話者の経験などに興味が湧いた。著者せきしろ氏が人生でこれまで見てきたであろう風景、感動したであろう出来事などを想像せずにはいられなかった。そこから作られる、全然おもしろくないたとえ、共感されないたとえ。それでも、何らかの話者の体験が、別の体験とあるポイントで結び付けられた結果として生まれるのがたとえだ。「これとそれを、そんなところで結びつけるのか!」という驚き。世界で初めて塩キャラメルを食べた人が感じたであろう、未知の組み合わせ方の面白さが、私には強く印象に残った。

 

そして、これからは積極的にたとえを使ってやろうという気分はすごく高まった。まるで、ためしてガッテンで「たとえを使うと脳に良い」なんて放送された直後のように、私の中でたとえがブームになっている。

私の国語に対するニガテ意識は、この先まだまだ克服できそうにないが・・・。

 

プログラミング問題「六角形のテトロミノ」を解いてみた

オフラインどう書くシリーズの、「六角形のテトロミノ」問題を解いてみた。

この記事はネタバレになってしまうので、日々のコーディング筋トレネタに困っているプログラマの方は、先に問題にチャレンジすることをオススメする。

また、今回私が考えたことなどを振り返って、あらためて言うまでもないのだが、私には数学の技術的な知識が不足していることを痛感した。地道に学んでいきたい。今回私がとった解法について、すでに数学の世界には理論やアルゴリズムが確立されているはずだと思うのだが、浅学な私はそのような知見にたどり着けなかった(何を調べたらよいかも分かっていない)。もしご存知の方がいらしたら、ポインタだけでも教えていただけると幸いだ。

 

 

さて、今回の問題を見て最初に思い浮かぶ常套的な解法は、テトロミノの形を「4つの六角形のうち1つを原点とした位置ベクトル」で表し、そのベクトル列によって形を比較するというものだ。どのように座標に表わすかといった部分で、問題をきれいに表現できたり解けたりする。

このアプローチで解きかけていたのだが、途中でどうしても「回転」のことが気になり始めた。今回の問題では、回転や並行移動を行って重なる図形は同じ形とみなすのだ。つまり、「回転」や「移動」という操作を行っても変化しない「形の特徴」のみを抽出し、それ同士を比較するようにすればよいのではないか?

そんなアイデアが浮かんでしまい、どうしてもその道で行けるところまで進んでみたくなった。

六角形テトロミノの形をどう表わすか

そこで自分なりに考えてみた。考えるヒントとなったのは、中西昌武先生の概念フォーム理論で、データソース間の関係の構造を行列で扱っていたことだ。今回の問題の入口として、ある1つの六角形テトロミノを次のような規則で行列で表わすことにした。

(1) 六角形の各辺を、右上を0として0〜5のインデックスで表わす

(2) 六角形の位置を表わす文字を、六角形の識別子とする

f:id:innx_hidenori:20170415211139p:plain

 

(3) テトロミノを構成する各六角形ごとに、「隣接している六角形」を、隣接している辺インデックスと対象六角形の識別子とで表わす。

例:以下の六角形テトロミノの場合、次のような情報が抽出できる。

f:id:innx_hidenori:20170415212113p:plain

a: (2 → f)、f: (1 → g, 2 →k, 5 → a)、k: (0 → g, 5 → f)、g: (3 → k, 4 → f)

 

(4) 取り出した情報から行列を作る。行: 六角形ごとの情報、列: 辺ごとの情報。4行6列の行列になる。

f:id:innx_hidenori:20170415212523p:plain

 

これで、一旦形の情報を表現することができた。しかし、このままでは問題がある。

最初の行列表現の問題

これまでの手順では、最初に構成されたテトロミノの記号などをそのまま反映しただけなので、当然ながら以下の問題には対処していない。

  • 行列の情報が、テトロミノの回転に依存したまま
  • 行列の情報が、テトロミノの位置に依存したまま

この行列に何らかの手を施して、位置と回転に関する要素を取り除かなければいけない。一体どうしたら・・・

まず、現段階の行列でも、次の特徴は持っている。

  1. 行の順序を入れ替え(aを3行目、kを1行目にするなど)ても、同じ形を表現している
  2. 列をローテーション(インデックス0の列を一番右へ持ってくる)させても、同じ形を表現している

2はテトロミノを回転させる操作にあたる。

1と2を組み合わせると、行の順序を入れ替えたり、列のローテーションを行っても同じ形を表していることになるので、何らかのアルゴリズムで行の順序とローテーション回数が一意に定まるようにしてやれば、位置や回転に依存しない「構造行列」を導けるはずだ。

テトロミノの構造行列を導くアルゴリズム

  1. 行の順序(=テトロミノの各要素の取り出し順)を決めるため、まず、どこを起点にするのかを決める。
    この際、六角形毎の隣接数を評価して最小のものを選択する。これが同数ある場合は、1つ先の隣接要素の隣接数も可算して再評価する。テトロミノの場合は全要素数が4で、その半数である2、つまり今回は1つ先の隣接要素まで評価し、それでも最小スコアのものが同数ある場合は、その中の1つに決める。
  2. 起点六角形で隣接がある辺のうち最小のインデックスをもつものがインデックス0になるように、テトロミノ全体をローテーションする。
  3. 行の順序を決める。ローテーション後のテトロミノに対して起点六角形から開始して、隣接辺インデックスの昇順に、深さ優先で辿っていく。(ローテーションしているので、この時点で辺インデックスが変わっていることに注意)
  4. 行の順序に従って、行を入れ替える。
  5. 六角形の識別子を、行インデックスに変換する。

この操作を行うこと、最初の行列は、

  • 起点六角形:a
  • 順序:a→f→k→g

となり、変換を施すと次のような構造行列になる。

f:id:innx_hidenori:20170415224919p:plain

 

プログラムでは、10個の形の構造行列を最初に求めておき、テスト入力のテトロミノの構造行列を都度求めて、行列同士のマッチングにより形を決定している。ただそれだけだ。

 

この先の課題

もう少し先へ進んでみたいと思っており、具体的には以下の点をなんとかしたい。

  • アルゴリズムの汎用化:N角形の場合、ポリオミノの場合
  • 別のプログラミング言語での実装:この種の問題を解くコードをPHPで書くのはなんだかツライ・・
  • 概念フォーム理論との対比:構造を行列で表わすという点は似ているが、実際に表現している特徴点が異なる、と思っている。その違いをハッキリさせておきたい。
  • ユニットテスト:書く

 

コードの読みやすさの話

読みやすいコードの書き方について、次の記事が話題になっていた。

これについて、 twitterで@koriym氏から問いかけがあった。

 「put B+C into A」と「a = b + c」のどちらが読みやすいコードといえるのか。現時点での私の考えでは、後者の方が読みやすいという考えだ。こう考えるのはなぜか、書いてみる。

 

まず、コードの読みやすさと一括りにしているが、最初に挙げた記事や私のtwitterでの返答で想定しているのは、何らかのアプリケーションのソースコードとしての読みやすさだ。この類のソフトウェアでは、アプリケーションが扱っている問題(What)とそれをどのように解決しようとしているのかといった意図(How)を、コードを読んだ開発者が正しく認知するのに必要なコストが低ければ、概ねそのコードは読みやすいとされるだろう。このように、アプリケーションコードの読みやすさの基準は、どちらかというと問題の側にある。

@koriym氏が挙げた「put B+C into A」と「a = b + c」との違いは、このような目線で評価しうるだろうか? いくつか意見はありそうだが、同じ目線では評価不可能だと私は考える。この比較においては扱っている変数の部分がABC、abcのようなパラメータに置き換えられており、扱っている問題そのものに由来するような表現を見いだせないからだ。したがって、問われているのは、構文としての読みやすさということになる。表している意味が同じだが、形式が異なっている2つの文の、どちらが良いのかという話だ。

この点で、私の考えでは「a = b + c」の方が読みやすい。

「put B+C into A」は、そのコードが行う操作を自然言語的に表していて、読めば操作をイメージできるのだが、そのイメージはコンピュータのCPUで計算した結果をメモリの何処かのアドレスに書き込むような、限定されたイメージだ。putやintoという単語は、読み手の最初の認識を誘導してすばやく意味を連想させるのに役立つ反面、意味の応用力がないのだ。=や+も、同じようなメリットデメリットを持つが、英単語を使ってしまうよりも、その場での意味に馴染ませやすい。

また、構文自身が意味を連想させまた限定もするということは、アプリケーションコードの記述においては、とても邪魔になってしまう。アプリケーションコードを記述するときには、表現したい問題などに由来する言葉や意味が際立っていた方が読みやすい。putやintoなど構文側の単語がいろいろ出てくると、そちらに読み手の意識が引きづられてしまうだろう。

また、順序の点でも「a = b + c」の方が読みやすい。左辺に結果が書いてあることで、そこから右に書いてあることの目的を最初につかめるからだ。