2019年3月10日日曜日

低スキル志向なチームの育て方3選

先日、低スキル志向なチームについて考えてみた。

それは、ある時点で比べたらたまたま高スキルなチームよりは相対的にレベル低かったというものではなく、落ちるべくして低スキル方向に転がっていくという性質をもったチームだった。

今回は低スキル志向チームをより低スキルに育てるポンコツ育成プラクティスを考えてみる。

■ 低スキル側に合わせてルールを設定する

  • あるプログラミングテクニックやライブラリについて、初心者には無理だとか、以前にだれかが間違った使い方をしたといった理由で、全面禁止とする文化。
  • 実行しながら学習する文化、上手に失敗しながら成長する文化が醸成されず、低いレベルで成長が頭打ちになる。
  • 出来るメンバーからアホらしくなって離脱してチームのスキルレベルが下がる一方となり、ルール設定がさらに低スキル向けになって負の強化ループが発生。
  • 「メンバーのレベルが上がったら解禁しよう」などと言うが、そんな機会は永遠に来ない。
    • VC++ と MFC を使った Windows アプリ開発に、クラサバ業界から Cプログラマや Pro*Cプログラマが流れ込んできた時、オブジェクト指向がわからないといった理由でポリモーフィズムが禁止されたり、IDEが使えないからといった理由で小さな関数の禁止といったルールが定められた。
    • Java のサーバサード開発の普及期の現場に、大量の COBOLer や VB厨の軍団が流れ込んできた時にも、小さなクラスやメソッドの禁止だとか、ポリモーフィズムを活用したデザインパターンが禁止された。
    • 最近では Scala 開発で Cats や Scalaz などの圏論ライブラリ禁止や、Shapeless などを用いた型レベルプログラミングが禁止されたりする。
    • 一般的には、小学校のテストの「可換則使用禁止問題」などと同根。

■ テッキー君に「共通コード」を担当させる

  • そこそこプログラミングが好きなメンバーに、共通コードや、ラッパーフレームワークを書かせる。で、人材市場で安くかき集めたポンコツ人海戦術軍団に、その共通コードを使った「業務ロジック」を、書かせる。
  • 実は人海戦術軍団の中にもレベルの高低ムラがあり、中には共通コード担当のテッキー君と同等以上のメンバーが含まれることもあるが、組織の空気として、人海戦術軍団には技術面は期待しないという暗黙のメッセージが常に発せられているので、レベル高めのメンバーから順にチームを離れていく。
  • テッキー君自身も、技術的アンテナの感度が高くて向上心をあればあるほど、劣化する一方のチームの淀んだ空気にも、自分自身の井の中の蛙的ポジションにも耐えられなくなり、早晩離脱する。後釜のテッキー君はさらに劣化したテッキー君になるので、テッキーポジション自体も劣化する。
  • Eric Evans が 青い DDD本で言ってたような、「Apply top talent to the CORE DOMAIN, and recruit accordingly.」といった高スキルチーム向けのガイドラインは、邪念として却下する。
  • 反省: 自分もプログラマになりたての、サーバーサイド Java に Servlet と JSP しかなかった頃に、こうしたテッキー君ポジションで、ポンコツ軍団向けフレームワークを書いたことがあるが、今では後悔している。業務ロジックチームでメンバーに直接スキル移譲しながら、ドメインのコードを直接洗練させるべきだった。

■ チケット駆動開発「だけ」しかやらない

  • チーミングの工夫や、コミュニケーションの活性化はいっさい無視して、とにかくチケットだけ回しておけばOK、それしかないのだ、それで充分だと思い込む。なにもかも JIRA / Github のコメントだけで仕事を進めようとする。
  • アジャイルを参考にすると、マニフェストの「プロセスやツールよりも個人と対話を」という価値観に抵触してしまうので、アジャイルは禁教とする。
  • フェイス・トゥ・フェイスのコミュニケーションはムダな時間として廃止。自分にアサインされたタスクに無関係な情報には耳をふさぎ、他人の仕事には我関せずを貫徹する。
  • 浸透的(osmotic)コミュニーケーションが発生せず、自然なスキルの伝播が起きないので、チーム全体のスキル向上が伸び悩む。
  • 誰もが無言で働くようになり、沈黙を破る心理的障壁がたかまる。雰囲気も悪くなって、行き場所のあるレベル高めメンバーからチームを離脱していく。
  • 高スキルメンバー離脱 → チームの平均スキル低下 → リソース逼迫 → コミュニケーション省略で負のループが加速。
  • 補足:いろんな現場で話を聞くと、「うちは仕様や計画の変更が多いからアジャイルは向かない」なんて真逆すぎるアジャイル理解の発言を聞くことが最近は多いが、そうした無知・無策にも程がある現場で「そういえばJIRA使ってたなあ、てことはチケット駆動開発になるのかなあ」みたいな適当な流れで、ちゃんとチケット駆動開発を研究することもなく謳われるのが、低スキル志向現場のチケット駆動開発

■ 逆3行要約

  • 禁止ルールで縛るより上手に失敗しながら成長しよう
  • スキル高い人こそ「業務ロジック(≒コア・ドメイン)」にアサインしよう
  • チケット管理ツール使うならチーミングも工夫しよう

2019年3月7日木曜日

ドメイン層にメタデータは入れないでね

某社内フレームワークがOSS化されたという記事が出て、ツイッターでいろいろつっこまれていたが、低スキル志向な組織では結構普遍性がある話なので、ちょっとメモしておこう。

どういうものかというと、「DDDを意識した」と謳ってる Scala フレームワークで、全てのエンティティの基底となる trait として EntityModel なるものが定義されていて、以下の属性を持つという。
  • エンティティのIDを表す id
  • データ更新日を表す updatedAt
  • データ作成日を表す createdAt
まあ、ID をエンティティに含めるかどうかについては、最近の関数型DDD界隈では議論があるけど、一応ここでは良しとしておこう。でも、データ更新日とデータ作成日はないわな。メタデータやんけ。

注文日時とか支払い日時とかならわかるけど、データ生成日って・・・どうしてこうなった?

百歩ゆずって、「データ○○日」がユビキタス言語になるような、ある種のドメインのある種のエンティティがあったとしても、そんなのむしろ特殊ケースだわな。全ての DDD エンティティの共通属性なんかにはならない。まして OSSとか・・・

要するにこれ、永続化層の都合で考えてるんじゃないのかね。ドメイン駆動とは正反対に。

なんか関連記事では「DDDを意識した」とか言ってるけど、むしろ逆にドメインモデリングなんか全然意識したこともなく、まして Persistence Ignorance とか聞いたこともない感じの技術者が、エンティティを「DBテーブルの受け皿」くらいにしか認識できてないまま、社内標準共通カラムとかをケースクラスに反映させちゃうときにやらかす、ありがちパターンなんだが。

こういう、下手くそなフレームワークを作って組織内に展開すると、ずっとこれ使うことが強制される部下たちが可哀そうなんだよな。

「プロダクトの標準化」とか言っても低レベル側に倒してるだけだから、これだとスキルが高い側に淘汰圧がかかって、低スキルメンバーしか残らなくなる。出来るメンバーからアホらしくて抜けていくから、組織的にも良くないだろうし。

もしオフショアやら若手やらでスキルムラが酷すぎて、標準化目的のフレームワークで型にはまった金太郎飴を作らせざるを得ないってあれなら、まず安易な人材調達から改善しないとダメだろうな。高スキルメンバーだけで数十〜数百人集めてる組織だってあるわけだし。

三行要約

  • メタデータをドメイン層に入れるのは止めましょう
  • DDD って言いたいだけで DDD って言うのは止めましょう
  • ポンコツフレームワークを社内展開するのは止めましょう

補足

  • メタデータがドメインモデルに含まれないのは当然として、関数型DDD界隈では、エンティティは自分の ID を持つべきではないという流派もある。(参考)
  • ツイッターで突っ込まれていたのは ID の型の指定の仕方だったが、ドメイン層にメタデータを混入させてしまっている事の方が余程ひどい問題。
  • フレームワークを標準化目的---プログラマを型にはめるために作ったり使ったりするのって、本当に酷い愚行で、組織学習の強烈な阻害要因だと思うけど、別の機会に書きたい。

2019年2月25日月曜日

「データと振る舞いの一体化」と擬人化の弊害

最近 Functional Programming for the Dysfunctional という、面白い関数型プログラミングの紹介記事を読んだ。

序盤あたりに OOP と FP の対比があるが、ざっと要約すると下のようになる。

OOPは WHAT=データ, HOW=振る舞い, WHEN=時間を編み合わせて新たな複雑性を生み出してしまうが、逆に FPはこれらを分離してシンプルにする。

この説によれば、よく言われるような OOP と FP との直交性どころか、二つは相反する真逆のアプローチってことになるけど、オブジェクト指向から純粋関数型に移ってきた人なら、結構、実感としてわかるんじゃないだろうか。

さらに OOP に着目して少し敷衍すると、低結合・高凝集を目指してたはずの OOP 自らが、結合度を高め、凝集性を低める元凶になってしまっているとも言えないこともない。OOPやってた頃は考えもしなかったが、少なくとも今はそのように理解している。

ところで、ここで二つの疑問が湧いてくる。一つは、どうしてデータと振る舞いの一体化なんて愚行が、OOPの現場で未だに行われ続けてるのだろうって疑問(発祥はともかく)。もう一つは、どうしてこの手法の拙さが推奨されたまま疑問視されないのかって疑問。

■ なぜデータと振る舞いの一体化を止めないか

Simple Made Easy という、Clojure の開発者 Rich Hickey 氏が Simple と Easy の違いを解説した有名なプレゼンがあるが、その中で OOP では Simple と Easy を混同した挙句、初期のハードルが高めの Simple を避けて Easy に走ってしまいがちなことが詳説されている。

つまり「データと振る舞いを一体化」も、例のごとくOOP技術者が易きに流れてるだけって話ではないだろうか。OOP界隈では DB と HTTP の間の全てを巨大な手続きに混ぜ込んだトランザクションスクリプトがよく批判されるけど、OOP自身もせいぜい「データと振る舞いの一体化」に留まった中途半端なレベルから出ていなかったのではないかと。

実際に、そのレベルから脱却した純粋関数型DDD の近年の発展を見ていると、そのように思えてしまう。

■ なぜデータと振る舞いの一体化に疑問を持たないのか

最初に紹介した記事では、OOP と anthropomorphized=擬人化の関連も指摘されている。この擬人化には、協働(collaborationDictionary)と共に責務(responsibility)も含まれるけど、OOP界隈ではこれが特に重視されている。

まあ「どこに何を置くか」考えるのは大事だし、それを主体性や自意識をもった何かのごとく責務と呼ぶことは別に良しとしよう。

ただ困ったことに、これが神聖視されすぎたまま魔法のワードというか免罪符になってしまって、それでデータと振る舞いの一体化なんてよく考えたら変なことまでも、なんか責務!って言っちゃうとそれで正しいような錯覚が生まれてしまうのではなかろうかと思う。


まあ自分も、キャリアの大半をオブジェクト指向でやってきたので、ついつい責務って言葉を頻用してしまうけど、関数型プログラミングの現場だとやっぱそろそろ控えた方が良いかもしれない。恥ずかしいしな。

2019年2月23日土曜日

「チケット駆動開発」案件から感じるヤバさ

ウォーターフォールでもアジャイル系でもその他のプロセスでもなく、単に「チケット駆動開発」とだけ書いてる案件たまにあるけど、ほぼヤバさしか感じないのだが...

要するに、アジャイル的な変化への対応自己組織化をマスターしてるわけでもなく、かといってWF+PMBOK 的な計画ベースのプロジェクト管理スキル持ってるわけでもなく、出来ること出来ないことの区別もないまま、ビジネス側=神の声に為すすべもなくただ振り回されてるだけの集団が、「何もわかりませんし何もできません」って素直に認めるのもアレだから、「そういえば Jira 使ってたなあ」だとか、ふと思い出してチケット駆動開発って言ってるだけなんじゃないの、どうせ?

なんて、まあ想像だけど疑ってしまう。

別に「チケット駆動開発」それ自体には、若干のモヤモヤを除けばあまり文句はない。

関わりたくないのは例えば、アジャイルについてまともに調べた事もなく、ウワサの又聞きの雰囲気の伝聞程度の知識と、下手につまみ食いして下手に失敗した下手くそな体験で「完全理解!」気分になったテックリードが、無知の上にいろんな勘違いを積み重ねて「うちは仕様や方針の変化が多いからアジャイルは向いてない」とか言ってドヤっちゃうみたいな現場の「チケット駆動開発」。

そういう勉強も研究もしないのがデフォな現場だと、冒頭に書いたように、計画ベースの管理と変化への順応のどちらにも対応する能力がない上に、チケット駆動としても初期の提唱者達が謳ってたような効果を得るには程遠いものにしかなりようがない。ルールも徹底されないから、なんとなく思いついたところから Jira に起票して、思い出したらプルリクに書いとくくらいが関の山。(なぜか決まって Jira なんだよな

あと、こないだ書いた「プログラミングとはSEが書いた設計書に従ってPG=IT土方が黙って手を動かす作業である」って文化的遺伝子が、大半のメンバーに受け継がれてるような低スキル志向な現場での「チケット駆動開発」だと更にやばい。

そういうとこで認識されている「チケット駆動開発」とは、「チケットに書いてる作業だけ、所定のフローに従ってとっとと処理して回してくこと」だから、自分にアサインされてないチケットには我関せずで、自然と他人に構うのは損という価値観になる。

チーム全体の現状や目標についても無関心になってくるし、しまいには出社してチケットだけ見ながら仕事して、誰とも話さず退社する人も出てきたりする。チケットがむしろコミュニケーション分断の道具になって、個室のタコツボに閉じ込められて仕事してる感じになってしまう。

つうわけで、やっぱ却下だわな。

----
モヤモヤ1: たかが「コミットをチケットに関連付ける」ってだけのルールを、わざわざ○○駆動開発って言うのは大げさな気がする

モヤモヤ2:かといってタスク管理フローとチケットの重要度を上げると、「プロセスやツールよりも個人と対話」に逆行して、売りになってる「アジャイルとの親和性」も損なわれる気がするし

2019年2月16日土曜日

低スキル志向な現場とは何か

低スキルと言っても、上には上、下には下がいるわけで、高いところと比べたら低いといった相対的な程度問題ではない。ベクトルの大きさではなく向きが、いろいろ正反対になっていたりする。

なんと言うか「ソフトウェア開発とは低レベルな人間を集めてやる苦業」という、半ば無意識だけど強固なメンタルモデルがまずあって、それに即して人が集められ、技術が選定され、開発プロセスやコーディングルールが策定され、さらにそうした信念を再生産する形で世代交代もなされていくような。

そういう現場を、ここでは差し当たり低スキル志向な現場と呼んでみたい。

----

低スキル志向な現場の特徴は、まずルールやガイドラインに分かりやすく現れる。とにかく初心者、新人、未経験者、不勉強者、老害といった、低スキルサイドに基準が置かれる。

たとえば 2007年ごろに C# が3.0になったときも、低スキル志向現場ではラムダ式が禁止された。もっと昔には、C++ のプロジェクトに参入してきたC言語プログラマのために、OOPの技法(特にポリモーフィズム)が禁止されたという。最近では、Scala の現場で、OOPすら怪しいレベルの Java プログラマ達に合わせて、Cats などを用いた高度な関数型プログラミングが禁止されたりする。

「フレームワークとはなんぞや」といったそもそも論レベルでも考え方が全然違う。元来はそれなりに分かっている人間が、ドメイン固有部分とテクノロジー共通部分を切り分けて関心事を分離するために使っていたはずの道具が、いつの間にか、いくらでも交換可能な無知蒙昧なIT土方軍団を、拘束して矯正するための型枠として使われるようになった
※(個人的には Terasoluna なども、少なくとも現場ではそうした思想で使われていたように思う。

こうしたルールは、その時点で中級以上の技術の使用を禁止しているだけじゃなく、低レベラーもいつか中レベラー以上になりうるという成長の可能性までをも事実上制限してしまっている。だから、そういう現場でいくら年数を詰んでもスキルは伸びないのだけど、困ったことに、年数が経てばスキルは低いまま肩書だけナントカリーダとかナントカマネージャに昇格して、ルール策定やチーム作りを主導するようになるから、低レベラーの輪廻が永遠に続くということになる。

また低スキル志向な現場では、周囲の生態系も低スキル志向になりがちで、例えば人材市場へのチャンネルでも、正味のスキルは等閑視されたまま、注文分の頭数がなるべく早く安く調達できるような人材業者が重宝されようになる。

高スキル志向な組織では、日頃から世の中のデキる技術者を探してつながりを作るような働きかけをしていて、採用面談なんかもそれなりの高倍率になるものだけど、低スキル志向な現場では、業者から供給されるままに受け入れて、頭数だけそろえばOKということになる。また離職率も高いから、早く安くタイプの人材業者とのつながりがますます強化されることになる。

こう書くと、なんだかいかにも受託SIer の現場風景ぽいけど、最近では自社サービスのWeb開発業界でもめちゃくちゃ多い。

思い起こせば、サーバーサイドJavaが興隆した2000年前後に、大手 SIer 系の現場にいわゆる「VB厨」や「コボラー」が大量に流れ込んできたのが、個人的には低スキル志向な現場の原風景だったりする。ああいう環境に浸って中堅くらいまで育ってきた叩き上げが、特に反省も勉強もないまま世渡りしてるうちに、何かの拍子で自社サービスWeb業界に入り込むパターンが多い昨今なのだと想像する。

とは言っても、実は、個人的には全否定するつもりはない。それで雇用が生まれて世の中が回っているという面もあるけど、それはそれで別としても、技術者として敢えて低スキル志向な現場に入ってみるメリットもなくはないと思う。

  • 糞コードへの耐性ができる: きれいなコードばかり読み書きしていると、汚いコードが本当に全然読めなくなる。現代人が泥水を飲んだり腐肉や芋虫を食べたりできないのと似ているかもしれない。

    実は高スキル志向な現場でも、トレードオフスライダーの定め方によっては読みにくいコードが仕方なくコミットされることはある。職業プログラマとしては、そうした現場に途中参加してもスムーズに適応するための耐久力がほしい。

    低スキル志向な現場では、美しいコードなんか生まれてこの方考えたことも見たこともないようなプログラマが、なんなら「コードなど汚いほどプロっぽい」みたいな謎の価値観に則って、猛烈な糞コードを日夜積み上げているから、定期的にそういうのに接すると免疫力向上に効果がある。

  • 当たり前な事をあえて省みる機会になる: 例えば「コードは読みやすいほうが良い」とか、「関心事は分離したほうが良い」とか、「パフォーマンス改善のためには計測が必要だ」とか、「チームメンバーは互いにコミュニケーションをとった方が良い」などといったことは、ふだん当たり前すぎていちいち疑問を持ったりしない。

    こうした事も、低スキル志向なチームの面々と話すときにはちゃんと言語化する必要がある。ときには根拠の根拠の根拠の根拠くらいから説明することにもなるので、ある意味、哲学とも言えそうな思考の訓練になる。

  • ちょっとした冒険になる:若干中二っぽいが、科学も人権も存在しない古代〜中世の異国に、文明の利器を持たずにタイムスリップしてサバイバルするような冒険心をくすぐる体験ができる。

    現代社会では当たり前の技術や考え方が通用しないので、いろいろ工夫が必要になるし、低スキル志向な現場ならではの人間模様やドラマもあって興奮させられる。特に、チーミングの面で昨年流行った「一人から始めて越境する」的なやつも実践できたりして、わりとまじで勉強になることも少なくない。
デメリットとしては、自分のスキルまで落ちてしまうのが大きい。宇宙飛行士の筋肉のようなものかもしれない。変な話、プライベートな時間に10個の知識を独習している一方で、勤務時間に20個の知識が溶けていく感じになる。世の中の進歩から取り残される不安がどんどん迫ってきて、これは結構怖い。
※ 書籍『Learn Better』には、全然使わない知識は母国語ですら忘れてしまうという事例が紹介されている。

だから、もし低スキル志向の現場をやるとしたら、半年を越えないくらいの任期で、なおかつ高スキル志向な現場の任期との比率が2:1以下くらいになるように、案件を選ぶと良いと思う。

ただし業界に初めて入って来てから、高モチベなメンバーに囲まれた楽しいチームしか知らないようなアジャイルネイティブな若者は、こういう現場に入ってきても単に心が折れて変なんなっちゃう可能性もあるので要注意。経験豊富な中堅以上で、ある程度自由の効くフリーランス向け。

2019年2月14日木曜日

ドメイン軽視のメンタルモデル

自分はわりとシステム開発の対象とする問題領域、つまりドメインをどうモデリングするかについて関心がある方なので、ツイッターのTLなんかでも、ドメインのモデリング/コーディングについて熱心に語っているツイートが自然と多くなる。なので例えば DDD を応用して日々研鑽している人が多いなあという感想をもってしまいそうになる。

ところが、世間一般ではかならずしもそうではない。

一応それなりに高スキルなメンバーを集めたチームですら、ドメインを扱う技能は意外と重視されない。そもそも高スキルチームを目指してのメンバー集めの段階で、インフラ〜ミドルウェアにかけての最新プロダクトやライブラリの経験が評価されることはあっても、ドメインのモデリングについて触れられることはまず無い。

技術者評価の面でも、ドメイン以外に関するスキルだけが注目される。大規模で複雑なドメインの中に適切に境界を定めて粒度と整合性のトレードオフを解決したとか、関心事の分離を徹底してドメインのコードをより純化したとか、そういったことは話題にもあがらない。ドメインモデリングに関する功績や努力はほぼ常に無視される。

ましてや低スキルチームでは、そのチーム内では若干マシなプログラマが「共通コード」やら「フレームワーク周り」やらを担当する一方で、コードベース全体のその他 90〜95%くらいを占めるビジネスロジックを、人材市場でかき集めた十把一絡げの人材と、経験1・2年の初心者で構成された、何にも知らない人海戦術軍団で対処することになる。

そうした現場では、ドメインモデルなど最初から最後まで一瞬も考慮されることなく、DBアクセスとHTTP入出力のあいだに、うず高く積まれた手続き型コピペコードからなる糞コードの大山脈が形成されるが、低スキルチームでは管理職以下だれもがそれで当たり前だと思ってる。ビジネスロジックのコーディングとはそういうものだと、上から下まで普通に認識されている。

ちなみに DDD の Eric Evansはこう言っている。

Apply top talent to the CORE DOMAIN, and recruit accordingly.

これが真逆だから、チームのスキルバランスもおかしくなる。成果物となるプログラムの大部分はドメイン固有のコードなわけで、時間もマンパワーも大部分そこに費やされるのだから、ドメイン層にこそ知識や技術や経験や才能を集めて洗練させるのが本来優先になる。「フレームワーク周り」の層なんか、ドメインを洗練する初期の過程で必要性が高いものから自然に形成されれば良い。

またビジネスロジックに永続化層の都合を混在させて Persistence Ignorance を壊したり、ひどい場合は「大規模なドメインでのトランザクションスクリプト」に至ってしまうのも、ドメインの軽視が主因。ビジネスアプリケーションのドメインとはそもそも複雑なものだという認識が足りないからそうなる。

さらに、ドメインモデルは一発で正解を出すものではなく継続的に洞察を深めながら進化させるものだという認識も、ふつうは全く足りないからテストもお気楽に省略される。MVPを厳選してなんとかファーストリリースにこぎつけたとしても、その後早い段階で詰んでしまう。

ちなみにそういう風景って、なんとなく受託 SIer あるある的なイメージだけど、今では自社Webサービス業界でもすごく多い。推測だけど、受託SIer の土建的世界観で育った中堅「SE」が、そのままのメンタルモデルを強固に維持したまま、いわゆる「自社サービス」の「Web業界」に流れてきて同じことをやってるのではないかと思う。

こうしたドメイン軽視のメンタルモデルには共通の起源があるように思うが、別の機会に書きたい。

2019年2月11日月曜日

オブジェクト指向エクササイズの陳腐化

オブジェクト指向エクササイズというのが一頃流行った。自分も Java プログラマだったころは、1,000〜2,000行ほどのプログラムに適用して試したり、同僚にも勧めたりしたことがある。

ただ今の時代、パラダイム面でオブジェクト指向一強だった昔とは違うし、自分でもフルタイムで関数型プログラミングをやるようになったりして、改めて見直してみるとオブジェクト指向エクササイズも色々と怪しいところが多い。

この記事では関数型の視点も取り入れつつ再評価してみたい。

■ 評価の観点
オブジェクト指向エクササイズは『ThoughtWorks アンソロジー』所収のエッセイで紹介されたもので、著者によればオブジェクト指向の考え方を磨くのに役立つという9つのルールから成る。

原語だと Object Calisthenics と言うが、Calisthenics とは「懸垂、腕立て伏せ、ストレッチ、ジャンピングジャックのような、健康状態や体型を維持・改善するための器具を使わない運動(Vocaburary.com)」の事を指す。カタカナでエクササイズというと練習問題のような語感もあるが、もともとは体育・スポーツ・健康管理に関連する言葉らしい。

メタファーの背景にこうした語義があることを踏まえつつ、次の4段階で9つのルールを見直してみる。
  • 有益: 練習効果だけではなく、実プロジェクトでもルールやガイドラインとして取り入れてみる価値のあるもの。野球の素振りや格闘技の技の練習など、本番で確実に再現するための反復練習にも似たもの。
  • 練習としては有効: 上述の Calithenics の語義にまさに近く、著者が意図している通りのもの。実戦でそのまま使う所作でははないが、基礎体力育成のための筋トレやストレッチのような効果が期待できるエクササイズ。
  • ほぼ無意味: あえて実施してみたところで、せいぜい、やはり意味はなかったと納得するしかなさそうなルール。時間の無駄なので、なにか他の勉強でもしていた方が吉なもの。
  • 有害: むかーしの運動部では、ウサギ跳びや練習中の水飲み禁止など、今では医学的に否定されている練習や慣行が奨励されていた。それらと同じように効果が疑わしいどころか、むしろ悪い癖がついて不健康にすらなりそうなプラクティス。
以下、それぞれ見てみる。


■ 1. Only One Level Of Indentation Per Method
〜 一つのメソッドにつきインデントは1段階までにすること 〜

これは有益で、実プロジェクトでもある程度取り入れる価値がある。

エッセイでは SRP(単一責任原則)や短いメソッド(3行のメソッド)に関連して解説されているが、実は SLAP(Single Level of Abstraction Principles)にも関係が深い。

Kent Beck が 『Smalltalk Best Practice Patterns』で紹介していたComposed Methodにも関連するが、抽象度を適切にそろえて構成したメソッドは、5行前後の1段階のコードブロックで表現できるというもの。

これはオブジェクト指向ではなくても言えることで、Scala だと特に、for comprehension のネストは、抽象レベルが混在している可能性が高いので普段から避けたい。


■ 2. Don’t Use The ELSE Keyword
〜 ELSE 句を使用しないこと 〜
これはほぼ無意味

たとえば、下の式は連続一様分布の関数を普通の数式として表したものだけど、これを自然にコーディングすると当然 ELSE 句が生じる。これを ELSE句を使わずに書いてもかえって不自然すぎというか間違ってるので練習としての意味もない。
\[y = \begin{cases} \frac{1}{b - a}, & \text{for } x \in [a, b] \\ 0, & \text{otherwise} \end{cases} \]
また、エッセイでは IF 〜 ELSE を三項演算子で置き換えているサンプルもあるが、三項演算子は式だから OKということなら Scala で IF 文を式として扱えば、ELSE 句を禁止できないことになり、そもそもの基準があやふやになる。

あと、いつものオブジェクト指向のアレで、やたらとポリモーフィズムを連呼して Strategy パターンや NullObject パターンを推奨しているが、せっかく代数的データ型とパターンマッチで書いたシンプルなコードを、ムダな間接層を伴うパターンで置き換えてもまともな知恵は何一つ得られない。やってみてがっかりしても害にはならないが時間の無駄。


■ 3. Wrap All Primitives And Strings
〜 すべてのプリミティブ型とストリング型をラップすること 〜

これは有益。エクササイズに留めず、実戦のコーディングやレビュー観点に取り入れてみる価値があると思う。

もっと言えば、昔の Java ではラップするだけで精一杯だったかもしれないが、現代の Scala プログラミングではジェネリクスや型レベルプログラミングや依存型など、のパワーを追求する道具立てが昔より豊富なので、どんどん活用すると良いと思う。


■ 4. First Class Collections
〜 ファーストクラスコレクションを使用すること 〜

これはほぼ無意味。オブジェクト指向では List は準プリミティブなコンテナオブジェクトに過ぎないのだろうけど、関数型ではあえてドメイン固有の要素から切り離した普遍的な代数的性質なのだから(内部実装はともかく)、せっかく導出した抽象構造をラップして元に戻すのは色々逆行することになり不毛。

また「0または1以上」の多重度をファーストクラスコレクションにするなら、「0 または 1」でも同じことが成り立つはずで、だとすると Option もダメってことになるが、Option[Name] を MaybeName にラップする不毛さはすぐ分かると思う。さらに関数の定義域や値域に使うのもダメとなれば、自然なパターンマッチすらもできなくなる(無理して unapply を書けなくもないが無意味)し、言語が提供する利点を無駄に捨てているだけで、練習としての効果もない。

普通に Option、List、NonEmptyList(Catsなどの)、Sized(Shapelessの) などで表現した方が端的に表現できるデータの性質を、オブジェクト指向ではどうだからといった理由だけでむやみにラップしても何も良いことがない。

カプセル化の観点で見ても、参照透過でイミュータブルなコードを書いていれば、コレクション内部の値を外から勝手に変更することはできず「隠蔽」の価値は半減するので、無駄なラッパー層のコストに釣り合うメリットはやはり無い。


■ 5. One Dot Per Line
〜 1行につきドットは1つまでにすること 〜

ドットの連鎖で生じるいくつかのオブジェクトの責務を、「仲介者」が持ってしまうことになる状況を、単一責任原則デメテルの法則に則って防ぎたい、あるいはその発想を身にけたいって主旨だが、、、ほぼ無意味

ドットの連鎖禁止でできなくなることには、以下のようなものがあるが、、、
  • List や Stream を、map して filter して reduce するような計算
  • DDD でいう Closure of Operations (例えば数値計算の演算子もメソッド呼び出しだと考えれば、a + b はOKでも a + b + c は a.plus(b).plus(c) だからアウト。三角形の面積すら計算できない。)
  • 関数や計算の合成
  • fluent interface な EDSL
「オモチャのオモチャ」で遊ぶのをやめさせるための縛りとしてドットの連鎖に着目するのは、普及期ごろの Java ではそれで良かったかもしれないが、昨今のプログラミング技法を鑑みると時代遅れだし、ましてや関数型プログラミングでは的ハズレすぎてなんの学びも得られない。

※ドットで改行しても同じことだから、「一行あたりのドット」というよりドットの連鎖の禁止として考えている。


■ 6. Don’t Abbreviate
〜 名前を省略しないこと 〜

クラス名、メソッド名、フィールド名を省略しないことには別に異存はない。というか別にあえて禁止するまでもなく普通そうなのだから、練習としては毒にも薬にもならない。ただし逆にローカル変数の命名では、一文字に省略しても可読性が落ちないようにスコープを工夫したほうが良いので、むしろ有害の可能性もある。

つまり省略により可読性が落ちるしたら、関数が大きすぎて今読んでいる行とローカル変数の宣言行が離れすぎているために型が視界の外に出てしまっているとか、あるいは変数が多すぎて紛らわしくなっているとかなので、スコープをコンパクトにすれば済む。むしろそうする方が、名前をフルスペルにする事なんかより遥かにコード改善効果がある。

そもそも本当に命名の省略が常に可読性を劣化させるなら、数学や物理の公式もフルスペルの変数や記号で書かれてるはずだろうが、そうはなってないし、それどころか全部フルスペルにしたら逆に可読性が落ちて読みにくいことくらい少し想像すればわかる。

さらに関数型だと抽象度が高いコードも増えて、具体的な名前をつけようがない f、g、h としか呼べない関数を操作することが頻繁にある。ジェネリクスの型パラメータの名前だって、フルスペルにしたら逆に読みにくい。

大昔は「1文字変数名はループの i と j のみしか許さない」みたいなルールがあったものだけど、本当はクソ長いコードでループや条件ブロックを入れ子にしてるから可読性が落ちてただけで、直す場所が違う。


■ 7. Keep All Entities Small
〜 全てのエンティティを小さくすること 〜

これは有益。プログラムの構成要素について「いくら何でもこれ以上大きくなったら異常」という上限は、「Rule of 30」あたりを目安にすれば良いだろうけど、ちょうどよい小ささの発見は対象とスキル次第になる。

ただし Scala で上手く関数型プログラミングすれば、従来の Java よりは小さくなることはほぼ確実なので、『FP in Scala』などを参考にしながら、オブジェクト指向エクササイズというより関数型エクササイズとして練習すれば良いと思う。


■ 8. No Classes With More Than Two Instance Variables
〜 一つのクラスにつきインスタンス変数は2つまでにすること 〜

実プロジェクトのルールには使えないが練習としては有効かもしれない。

このルールを適用すると全ての複合型を2分木状の型構成で表現することになるけど、3要素以上で構成するのが自然な型も普通に多い。たとえば、AWS EC2 の `describe instances` コマンドの Output を2分木で表現することを想像すると、ひどく不自然になるのはすぐ分かる。だから 2という縛りは飽くまでトレーニング用の人工的な制約でしかない。

とはいえ、スポーツなどでも実戦にはない負荷をかけたり人工的に作った状況下での練習に効果があるように、このエクササイズも一度やってみる価値はあるかもしれない。ちなみに関数型な Scala で練習するとしたら、case class 等の Product Type だけではなく、sealed trait と case object で構成した Sum Type にもこのルールを適用すると、良いモデリング練習になると思う。


■ 9. No Getters/Setters/Properties
〜 Getter/Setter/プロパティを使用しないこと 〜

ほぼ無意味。代数的データ型の Product Type に「Tell, Don't Ask」を適用するのはナンセンス。むしろ無駄な責務の肥大化を招くだけ。

例えば、エッセイに Name クラスがサンプルとして載っているが、これを文字列に書式化したり Json に変換したりする場合、メソッドを Name に持たせるのは責務の置き場所が違う。`Visitor` パターンなどを使えばできるかもしれないが、コスト以上のメリットも得られず無駄な複雑さを招くだけ。

また例えば、数値と単位をそれぞれフィールドとしてもつ体重クラスと身長クラスから BMI を求めるコードを考えると、フィールドにアクセスできない以上クラスの外では計算できないし、かといってBMIの計算は体重の責務でも身長の責務でもないし、すぐに詰んでしまう。

「Tell, Don't Ask」を適用できるある種の文脈もないことはないが(特にOOPでは)、これを一般化してプログラム全体に適用するには無理がある。ましてや関数型プログラミングの場面では、よほど暇ならばあえて実験してみてやはり意味無しという結果を得るのも一興かもしれないけど、不自然なプログラムを書く練習にしかならないから不毛。


■ 結論
関数型からみた9つのルールの再評価結果
  • 有益: 1, 3, 7 の 3個
  • 練習としては有効: 8 の 1個
  • ほぼ無意味: 2, 4, 5, 9 の 4個
  • 有害: 6 の 1個
「無意味」と「有害」で過半数。残った「有益」と「有効」も、別にオブジェクト指向に限った話ではなく、「プログラミングエクササイズ」でも「関数型エクササイズ」でも成り立つし、なんなら「ベターな手続き型プログラムを書くための練習ルール」としても採用できる普通の話だった。まあ Java とか、"Better Java" 程度の Scalaプログラミングで精一杯の感じのあれなら、やってみても良いかもしれない。

■ 補足
オブジェクト指向について
オブジェクト指向について語りだすと、真の起源はどうだったとか、いや実は分派があってとか面倒だが、ここでは wikipedia に載ってるシンプルなパラダイムの分類で考えている。

┌ 命令型┬─ 手続き型
│       └─ オブジェクト指向
└ 宣言型┬─ 関数型
         └─ 論理型
一般にオブジェクト指向と関数型を対立概念と据えて語られることが多いが、こうして見てみると、COBOL や C や Java や Smalltalk みたいな命令型の一群と、Haskell や Prolog のような宣言型の一群で、大きく別れていることになる。昔から繰り返されてきたオブジェクト指向勢による手続き型叩きが(正直、自分も心当たりあるが)、一段上の観点で見直すと、命令型の枠内での内紛でしかなかったことが分かる。