小さな機能の害







Cindy Sridharan による記事の翻訳。



この記事では、著者は次のことを行います。





一般的なプログラミングのヒントの中で、小さな関数の優雅さと効率は常に称賛されます。 プログラマの聖書と広くみなされている本Clean Codeは、機能のみに関する章を持ち、本当にひどい、そしてまた長い機能の例から始まります。 さらに、本の中で、関数の長さは最悪の罪とされています:



この関数は長いだけでなく、重複するコード、あいまいな文字列値のセット、多くの奇妙で非自明なデータ型とAPIを含んでいます。 3分間の勉強の後、それを理解しましたか? おそらくない。 それと、抽象化のレベルが多すぎます。 ここでは、式がフラグによって制御されている場合、あいまいな文字列値と奇妙な関数呼び出しが二重に入れ子になっています。


同じ章では、コードを「読みやすく、理解しやすくする」ための品質について簡単に説明し、「カジュアルな読者がコードの種類を直感的に理解できるようにします」。その後、関数を小さくする必要があると述べています。



関数の最初のルールは、関数は小さくなければならないということです。 2番目のルールは、関数をさらに小さくする必要があることを示しています



機能は小さくあるべきであるという考えは、ほとんど神聖であると考えられており、修正の対象ではありません。 多くの場合、コードの修正、Twitterでの議論、会議、書籍やポッドキャスト、最適なリファクタリング技術に関する記事などでポップアップします。 そして最近、このアイデアがそのようなツイートの形でストリームに現れました:



私のRubyコードでは、メソッドの半分はわずか1〜2行の長さです。 10より93%短いhttps://t.co/Qs8BoapjoP https://t.co/ymNj7al57j

- @martinfowler


著者は、関数の長さに関する彼の記事へのリンクを提供します。



コードを見て、何が行われているのかを理解しようとする場合は、それを関数に抽出し、この「何」に敬意を表して名前を付ける必要があります。



私はこの原則を受け入れ、非常に小さな関数を書く習慣を身に付けました-通常は数行の長さです[ 2 ]。 5行より長い関数を心配しており、1行の長さの関数を書くことがよくあります[ 3 ]。


小さな機能の美徳は非常に頻繁に広まり、ほんの数日後にこのトピックがそのようなツイートの形で浮上しました。



@ dc0d_のアドバイスが好きです

- @davecheney


一部の関数は小さな関数に没頭しているため、名目上複雑なロジックのあらゆる部分を個別の関数に抽象化するという考えを情熱的に支持しています。



最終的には地獄のような、そして道を開いたすべての善意に完全に反するほど、この考えを吸収した人々によって書かれたコードベースで作業しなければなりませんでした。 この記事では、広く公開されている小さな関数の利点の一部が、必ずしも期待を満たせず、時には完全に非生産的である理由を説明します。



小さな機能の認識されている利点



小さな関数の長所をサポートするために、通常、一連のステートメントが展開されます。



一つのことをする



小さな関数は、1つのことを行う可能性が高くなります。 注:Small!= 1行。

- @davecheney


アイデアは単純です。関数は1つのことだけを行い、それをうまく行う必要があります。 一見すると、Unixの哲学とある程度調和していても、非常に理にかなっています。



「1つのこと」を定義する必要がある場合、不確実性が生じます。 単純なリターン式から条件式、数学的計算の一部、またはネットワーク呼び出しまで、何でもかまいません。 よくあることですが、「1つのこと」とは、あるロジック(通常はビジネスロジック)の1レベルの抽象化を意味します。



たとえば、Webアプリケーションでは、「1つのこと」は「ユーザーの作成」などのCRUD操作になります。 ユーザーを作成するときは、少なくともデータベースにレコードを作成する必要があります(そして、関連するすべてのエラーを処理します)。 また、人にウェルカムレターを送る必要があるかもしれません。 さらに、他の誰かが、Kafkaなどのメッセージブローカーで特別なメッセージをトリガーして、イベントを他のシステムにフィードしたいと思うでしょう。



「1レベルの抽象化」はまったく1ではないことがわかります。 関数が「1つのこと」を行うという考えを無条件に受け入れるプログラマーの中には、この原則をその関数またはメソッドのそれぞれに再帰的に適用する衝動にほとんど抵抗しないものがあります。



それらの多くは、機能を完全に乾燥させてモジュール化するまで停止できません-これは完全には機能しません

- @copyconstruct


つまり、1つの要素として理解(およびテスト)できる合理的で揺るぎない抽象化の代わりに、この要素が完全にモジュール化され完全に乾くまで、「1つのもの」のすべてのコンポーネントが形成されるさらに小さな要素を作成します。



乾燥誤fall



DRYは最も危険な設計原理の1つです(34)floatiα(25)aα(28)およびα(29)tα(13)α(27)etoα(22)y

- @xaprb


DRYは、機能を可能な限り小さくする中毒と必ずしも同義ではありません。 しかし、私は何度も2番目が1番目につながる方法を見てきました。 DRYは良いガイドラインであると思いますが、プラグマティズムと理性は、特にRailsの信念を持つプログラマーによって、この原則に従って独断的に祭壇に置かれることが非常に多いと思います。



Pythonの中核開発者の1人であるRaymond Hettingerは、 Beyond PEP8による素晴らしいパフォーマンスを持っています美しい、わかりやすいコードのベストプラクティスです 。 Pythonプログラマーだけでなく、プログラミングに興味を持っているか、それから生計を立てている人が見る必要があります。 多くのリンターに実装されているPythonスタイルガイドであるPEP8の独断的なフォローの欠陥を非常に巧妙に公開しました。 そして、スピーチの価値は、それがPEP8に捧げられているということではなく、描かれることができる貴重な結論であり、その多くは特定の言語から独立しています。



DRYの陰湿な呼び出しと恐ろしく正確なアナロジーが描かれているスピーチから少なくとも1分間見てください。 DRYの可能な限り幅広い使用を主張するプログラマーは、木の後ろに森が見えないというリスクを冒しています。



DRYの主な欠陥は、ネストされた時期尚早な抽象化を強制することです。 完全に抽象化することは不可能であるため、できる限りうまくやらなければなりません。 同時に、それがどの程度「良好」であるかを正確に定義することは不可能であり、多くの要因に依存します。



このグラフでは、「抽象化」という用語を「関数」に置き換えることができます。 たとえば、抽象化レベルAをどのように設計するのが最善かを考えて、次のことを考えることができます。









私たちが開発した抽象化Aは、部分的または完全に拒否されるまで、絶えず見直されます。 したがって、必然的に変更されることになる抽象化の基本的な特性は、 柔軟性でなければなりません。



そして、DRY原則を使用するあらゆる機会に今すぐ始めれば、将来的にはこの柔軟性、考えられるあらゆる変化に適応する能力を失うことになります。 私たちが本当にしなければならないことは、すぐに完璧なソリューションを構築し始めるのではなく、遅かれ早かれ必要とされる避けられない変更を行う自由を少しだけ与えることです。



最適抽象化は、 完全ではなく、 十分に最適化されたものです。 これは機能であり、バグではありません。 抽象化の設計を成功させるには、この抽象化の最も重要な機能を理解する必要があります。



「ダックタイピング」というフレーズと有名なPythonistaを生み出したAlex Martelliは、The Tower Of Abstractionと呼ばれるパフォーマンスをしています。 プレゼンテーションからこれらのスライドを読む:











有名なルビストのSandy MetzはAll The Little Thingsのパフォーマンスで、「複製は誤った抽象化よりもはるかに安い」、つまり「誤った抽象化の複製を好む」と仮定しました。



これらの概念の境界は曖昧であり、永遠に変化するため、一般的な抽象化は「正しい」または「間違った」ことはできないと考えています。 「誤った」状態から慎重に育成された「理想的な」抽象化は、1つのビジネス要件またはエラーレポートによってのみ分離されます。



上記のグラフのように、抽象化は特定の範囲として認識されるべきであるように思えます。 範囲の一端は、 精度の観点からの最適化ですが、コードのすべての側面は絶対精度の状態に最適化する必要があります 。 しかし、最善は善の敵です。理想を追求することは、完璧なフィット感を必要とするため、 優れた抽象化の設計には役立ちません。 スペクトルのもう1つの部分は、不正確さと境界の欠如に関する最適化です。 そして、最大限の柔軟性にもかかわらず、このアプローチには欠点があります。



特定のコンテキストに対して、たった1つの完璧なソリューションがある場合があります。 ただし、コンテキストはいつでも変更でき、理想的なソリューションhttps://t.co/ML7paTXtdu

- @copyconstruct


ほとんどの場合と同様に、「理想」は中間のどこかにあります。 普遍的な理想的な解決策はありません。 「理想」は多くの要因(プログラマーと対人関係)に依存し、優れた開発者は各コンテキストのスペクトルの「理想的な」ポイントがどこにあるかを認識し、この理想を常に過大評価する必要があります。



名前



どのように抽象化するかを決定し後、抽象化に名前を付けることが重要です。



そして名前付けるのは難しいです。



プログラミングにおいて、長くて説明的な名前を付けることは良いことであり、コード内のコメントを名前がコメントである関数で置き換えることを支持する人もいます。 ポイントは、名前がわかりやすいほど、カプセル化が優れているということです。



そして最後に命名。 ファウラーと友人は説明的な名前を支持し、

だから私たちは名前を読んだので読むのがとても難しい

- @copyconstruct


おそらくこれは、冗長性が物事の順序であるJavaの世界に転がり込むでしょう。 しかし、そのような名前のコードは読みにくいです。 コードを読むとき、単語の束からそのようなナゲットは私をst迷に導きますが、関数名でこれらのすべての音節を強調し、その瞬間に私の頭に形成された精神モデルにそれを埋め込み、定義に進むかどうかを決定します機能し、その実装を研究します。



しかし、「小さな関数」には別の問題があります。それらを追求すると、 さらに小さな関数があり、コメントを拒否してコードを自己文書化するためにすべての名前が冗長になります。



また、関数(および変数)の冗長名を理解し、それらをメンタルモデルに埋め込み、より詳細に学習するものとスキップするものを決定し、最終的にモザイクのすべての部分を1つの画像に追加することに非常にうんざりしています。



機能が少なければ少ないほど、それらと名前が多くなります。 関数名ではなくコードを読みたいです。

- @copyconstruct


, , , , , . , if-else



, if



elseif



, .



, - aVeryVeryLongFuncNameAndArgList



. . , , , , .



, — . createUser



, renderPageWithSetupsAndTeardowns



( Clean Code), , . , , .





, . Clean Code (The Stepdown Rule).



, . , , . .


, , . , , .



, , , ( ) . , , .







, . , «- » ( ). Clean Code , , .







.







, The Wrong Abstraction. :



. . , , . , , , , , (« »).


, , , , ( ). , , -, .



- , . . , , (graceful death). , , , .



+1. , . /,

 — @copyconstruct


«» , , . , , Git-, , . , , , ( ) . , , Clean Code.





, , . , Go ( ) .



- . //, , //.





.



, - .



, , Ruby,

 — @copyconstruct


Ruby 5-10 , - - . , .



, , .





, : , , . , .



« »: 1. 2. 3.

 — @sdboyer



, — 1) 2) (rails, django ) 3)

 — @copyconstruct


. -, «». - . , , .



, DRY. , , . , , , «» «».



«» , / , — - . , /, , , «- » , , .



, :



, . . DRY. .


, , , .



( , ), .

 — @copyconstruct


, , , open source-.





, , .



-



, , , dbs macbook.

 — @tyler_treat



, , , , .

 — @tyler_treat


, , . -, .



/ , / .

 — @copyconstruct


. . , — - . , , . , , , . , .



, -. ( ) , . , .



, . API , , HTTP-. . 1-2 , HTTP- . Kafka .





, (property based testing) , . Haskell- QuickCheck, , Scala (ScalaCheck) Python (Hypothesis). - .



, , . , JSON/msgpack, .





DRY — ( ). .



, — . 2016 Pycon onelineizer, , Python ( ) . , production- .



:



Go: , .

 — @rakyll


, Go. , , , , , , .



, , « ». . , . , , .



All Articles