コーディングスタイルの原則に関する科学的に厳密な研究はありますか?[閉まっている]


25

コーディングスタイルの原則(たとえば、単一出口の原則)は本当に良いことですか?常にですか、それとも時々ですか?それは実際にどのくらい違いますか?

あなたの意見がどうであれ、これらは明らかに主観的な質問です。それとも彼らですか?

コーディングスタイルの原則について客観的で科学的に厳密な研究を試みた人はいますか?

誰がどのように読みやすさの二重盲検研究を行うか想像できませんが、おそらく二重無知が可能かもしれません-被験者として研究されている原則を知らない学生と、研究を管理する非プログラマーを使用してください。


5
完全なコードを読むことに興味があるかもしれません。すべてを測定できるわけではありませんが、多くのことが測定できます。この本には、生データまたはソースの概要が記載されています。
deadalnix

また、いくつかの原則が特定の言語に適用され、他の言語には適用されない言語に大きく依存しています。例えばsingle-exit principle、本当にためにRAIIのC ++には適用されません
マーティンニューヨーク


@Loki-私はそれについて考えなければならなかった、そして私は同意するかどうかわからない。これはRAIIは(少なくとも一部の人に)代替出口ポイントです例外に対処するために、大部分で設計されているが、彼らはと数えることは事実だ代替代替出口点-本当にような方法で、単一の出口の原則に反する数えていないbreakgotoまたはreturn行う。IOW単一出口はC ++では絶対ではありませんが、それはとにかくCおよび他のほとんどの言語での私の見解です。しかし、それはまだ厳密ではない意味で関連しています。
Steve314

1
@ Steve314、記事は少なくとも遠い関連性があります-それはそのような実験の方法論のための設計の概要を示しています。これはこの分野で適切に記録された実験的証拠の明らかな欠如のために非常に重要です。
SKロジック

回答:


11

deadalnixのコメントをエコーし​​ています:Code Complete 2を読んでください。著者(Steve McConnell)は、コーディングスタイルについて詳細に議論し、論文やデータの参照を頻繁に行っています。


プロフェッショナルなソフトウェア開発の基本的かつ十分に提示された概要、いつか品質保証のために似たようなものが見つかることを願っています。防衛的プログラミングと擬似コードプログラミングに関する章は、特に役立ちました。共同開発の実践に関する章は、これまでこれらの問題について読んだ中で最も説得力があるようです。
ブヨ

私はこの本を読んでいませんし、おそらくそうすべきです、しかし-gnats answerのコメントに基づいて-これらの論文は本当に科学的に厳密で客観的ですか?答えが「可能な限り」である場合、どのような妥協が必要でしたか?質問で提案したように、二重盲検をより弱い標準に置き換える必要がありましたか?
Steve314

@ Steve314:わかりません、ソースをチェックしていません!しかし、ベストプラクティスを確立するために科学的な厳密さが常に必要なわけではありません。長所と短所の議論で十分な場合があります。
M.ダドリー

@emddudley-絶対に正しいが、実際にはこの質問が何であったかではない。
Steve314

@ Steve314:Code Completeはあなたにとって素晴らしい出発点です。そして、その参考文献のいくつかは、コーディングスタイルの科学的分析の問題に対処していると確信しています。
M.ダドリー

12

客観的な結果をもたらす主題の研究の可能性を非常に疑っており、説得力のある研究が示されるまで私は懐疑的なままです。

特定のコーディングスタイルに従ったコードを読み書きするのに何年も費やしたプログラマーは、人生で初めて見た完璧なコーディングスタイルよりも明らかに読みやすいと感じるでしょう。

最も一般的なQWERTYのタイピングレイアウトとまったく同じです-人間工学の点で非常に最適でないことを証明するのは簡単です(単語TYPEWRITERのすべての文字が私たちの日常の利便性を念頭に置いて最上行に置かれたと思いますか?) 。

しかし、ドヴォルザークやコレマクなどの改善された代替案は決して流行りません。そのため、人々は彼らとの生産性を高めていません -事実。たとえ抽象的な意味で優れていても。

また、事前にプログラミングにさらされていない被験者を見つけることは困難です(これは私たちの研究の結果を汚染するため)、しかしプログラミングの適性、そして両方を短時間で示すために十分な期間研究に参加する意志相互に重みを付けることができるように、時間の利点と長期の利点...(それらが相互に排他的であるかどうかはわかりませんが、研究者は単純にそれらが決して絶対ではないと仮定できませんでした)


1
クール、私は前にColemakのことを聞いたことがなかった
CaffGeek

1
@Chadは、あまり知られていないCarpal Xです。私はそれがColemakよりも優れていることを発見しました(carpalxで90-100 wpmに達しました)。エキゾチックなレイアウトに切り替えるつもりがなくても、carpalxのWebサイトでは、キーボードレイアウトの評価と最適化、およびこのカテゴリの問題に対する遺伝的アルゴリズムの利用に関する非常に興味深い記事を読んでいます。参照してくださいmkweb.bcgsc.ca/carpalx
コンラートMorawski

1
場合によっては、代替アプローチの限界利益が、それを採用するコストを正当化するのに十分なほど大きい場合があります。それ以外の場合は、すべてプログラミングアセンブラとFORTRANのままです。この答えは、実際には限界利益があるかどうかについての元の質問に実際に応答しません。ドヴォルザークの例では、確かにそのことが実証されていますが、ドヴォルザークの学習を正当化するのに十分なメリットはありません。
ジェレミー

@Jeremy「この答えは、実際には限界利益があるかどうかに関する元の質問に実際に答えていない」-OPはそのような研究の発見を直接求めず、彼は誰かがそのような研究を実施しようとしたかどうか尋ねた、より開かれた質問です。なぜ技術的に難しいのか、なぜそのような研究の結果はおそらく統計的ノイズによって著しく汚染されるのかについて、いくつかの論理的な理由を指摘して答えました。ですから、私の答えがあなたが与えた理由で役に立たないと判断された場合、私は不当に落とされたと思います。
コンラッド・モラウスキー

1
これらの採用コストの要点である@Jeremyは、より多くの練習をしている限り、劣ったツールを使用した方がパフォーマンスが向上するということです。そして、これは、被験者がさまざまなコーディングスタイルにどれだけうまく対処できるかを調べようとする研究で明らかになります。使用するコーディングスタイルに慣れているか、慣れていないために発生するノイズは、これらのスタイルの生来の品質の影響を小さくします。完全な初心者を取り上げて遊び場を平らにした場合を除きます。しかし、これは私の答えの最後の段落で指摘したように、実際的な困難をもたらします。
コンラッド・モラウスキー

4

答えは決定的なNOです!「ブレーク」と「継続」は悪いプログラミング慣行ですか?はこの質問のサブセットであるため、それに対するかろうじて修正された答えから始めます...

breakステートメント(または同じことをするループの途中から戻る)なしでプログラムを[再]作成できます。しかし、そうすることで、追加の変数やコードの重複を導入する必要があり、どちらも通常はプログラムを理解しにくくします。パスカル(1960年代後半のプログラミング言語)は、特に初心者プログラマーにとって非常に悪いものでした。

コサラジュの制御構造の階層と呼ばれるコンピューターサイエンスの結果があります。これは、1973年に遡り、1974年のKnuthの有名な論文Structured programming with go toステートメントに記載されています。深さnのマルチレベルブレークがあるすべてのプログラムを、追加の変数を導入せずに、ブレーク深度がn未満のプログラムに書き換えることができます。しかし、それは単なる理論上の結果だとしましょう。(追加の変数をいくつか追加するだけです!確かに、stackexchangeで3K以上のユーザーとグループ内であると感じることができます...)

ソフトウェアエンジニアリングの観点からはるかに重要なのは、1995年のEric S. Robertsによる最近の「ループ出口と構造化プログラミング:討論の再開(doi:10.1145 / 199688.199815)」という論文です。ロバーツは、彼の前に他の人によって行われたいくつかの実証研究を要約しています。たとえば、CS101タイプの学生のグループに、配列で順次検索を実装する関数のコードを書くように依頼した場合、調査の著者は、ブレークからの復帰を使用して順次から終了する学生について次のように述べました要素が見つかったときの検索ループ:

間違った解決策を生み出した[このスタイル]を使ってプログラムを試みた人をまだ見つけていません。

ロバーツは次のようにも言っています。

forループからの明示的な戻り値を使用せずに問題を解決しようとした学生の方がはるかにうまくいきませんでした。この戦略を試みた42人の学生のうち、正しいソリューションを生成できたのは7人だけでした。その数字は、20%未満の成功率を表しています。

はい、CS101の学生よりも経験が豊富かもしれませんが、breakステートメント(または同等にループの途中からreturn / goto)を使用しなければ、最終的には、名目上はうまく構造化されていても、追加のロジックに関しては十分に毛深いコードを書くことになります変数とコードの複製。誰かが、おそらく自分自身が、「正しい」コーディングスタイルという一般的なアイデアを追求しようとしているときに、その中に論理的なバグを入れます。

ここには、return / break-typeステートメントのほかに1つの大きな問題があるため、この質問はbreakの問題よりも少し広範です。例外処理メカニズムは、いくつかの方法に従って、単一出口ポイントのパラダイムに違反しています

そのため、基本的には、この最後のリンクで説明されている非常に厳密な方法で使用されない限り、単一出口の原則が今日でも有用であると上記の誰もが例外処理パラダイムに反対しています。これらのガイドラインは基本的に、関数からのすべての例外をthrow()に制限します。つまり、関数間の例外の伝播はまったく許可されません。C ++のような構文で新しいPascalをお楽しみください。

私から見るの概念「1・リターンのみ」どこから来ましたの?このサイトでの一般的な意見はここに投稿したものとは反対であるため、質問が求めたものを実際に提供する最初の回答であるにもかかわらず、私はなぜすでに投票されたのかを完全に理解しています:実際のユーザビリティテストに関するいくつかの情報は、単一出口の問題に焦点を当てています。特にゲーミフィケーションサイトでは、知識を先入観の邪魔にすべきではないと思います。これからもウィキペディアの編集に固執するつもりです。少なくとも、良い情報源からの情報は高く評価され、情報源に裏付けられたふりをした曖昧または誤った主張は最終的に禁止を獲得します。このサイトでは、まったく逆のことが起こります。事実に裏付けられていない意見が支配的です。私はMODがこの最後の部分を削除することを完全に期待していますが、少なくともその男はあなたがここで貢献者として永遠に私を失った理由を知っています。


私はこれを支持しませんでしたが、あなたの「しかし、そうすることで、追加の変数やコードの重複を導入する必要があるかもしれません。どちらも、通常、プログラムを理解するのを難しくします。」ポイント、それは主観的な主張です。変数またはコードの複製を追加すると理解が難しくなりますが、おそらくgotoを追加すると理解も難しくなることに同意します。また、複製による損傷は、複製されたコードを関数に分解することで軽減できます(IMOは移動しますが)コールグラフが複雑になっても自動的に削除されません)。
Steve314 14

1995年の論文についてのあなたの意見は、最後のコメントの後でしか見ていませんでした。あなたの投稿が長く、主観的なポイントから始まるため、あなたのダウン投票はもっと多いと思うので、ダウン投票者はすべてを読んでいないでしょう(最初は私と同じです)。基本的に、あなたの本当のポイントを早く紹介するのは良い考えです。
Steve314 14

とにかく、私は多くの人々が例外を代替の代替出口点の一種と考えていると思います-それらは実際には数えられないエラーケース(のようなもの)のためのものだからです。しかし、それは言語文化にやや敏感であることを理解しています。一部の言語では、「例外」は名前以上のものです-例外的な成功事例は有効です(IIRC StroustrupはC ++についてそのようなことを述べ、エラーが処理された場合、エラーかどうかについて哲学的なポイントを上げました)。例外は、必要な制御フローを提供する場合に使用する別の制御フローに過ぎないと言う人もいます。
Steve314 14

1
@ Steve314 " 間違いなく、複製による損傷は、複製されたコードを関数に分解することで軽減できます。関数のロジックを理解するのをさらに難しくします。
curiousguy

1
@curiousguy-はい、それは本当であり、おそらく「コールグラフへの複雑さの移行」ポイントの意図の一部です。私の宗教は、あなたが行うすべての選択はトレードオフであるため、すべての妥当なオプションとその利点と欠点を認識し、一般的な緩和策を知ることは重要ですが、治療法が病気より悪い場合には注意してください。もちろん、トレードオフのその部分は、物事に煩わしい時間を費やす(または無駄にする)ことです。
Steve314

1

http://dl.acm.org/citation.cfm?id=1241526

http://www.springerlink.com/content/n82qpt83n8735l7t/

http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=661092

[あなたの質問は、「はい」という一言で答えられるようです。しかし、短い答えを提供することは質問を「却下する」と言われました。却下されたと感じたら、回答にフラグを立てて、モデレーターが削除できるようにしてください。]


1
@ luis.espinal:終わりに向かって?テキストにはどのような情報が含まれますか?質問は少し動き回っています。質問のどの部分をテキストで対応する必要がありますか?
-S.Lott

1
スタイルの問題として、そしておそらくリンクのアブストラクトが提供できるより多くの情報を提供するために彼の質問。)たとえば、ACMの記事の要約では、コーディングスタイルについては言及していません。せいぜい、構造化プログラム定理の確証についてのみ語っています(それ自体は、単一または多重リターンの問題について語っていません)。したがって、そのリンクが関連する理由を説明できたでしょう。
luis.espinal

1
3番目の記事(ありがたいことにIEEE Xploreにアクセスできます)は、私が知る限り、OPが求めていることとは関係がないようです。これは素晴らしい記事です。後でもっと熱心に読むために印刷しています。だから、この記事がOPが彼の質問に答えるのにどのように役立つかを説明したかもしれない。全体として、あなたは単にたくさんのリンクを一緒に投げたようです。それは(それがあなたの意図でない限り)却下する方法ではありませんが、繰り返しますが、それがOPをどのように助けたかはわかりません。そして、これがポスターが彼のリンクに沿っていくつかのテキストを追加すべき理由です。だから今、あなたは私がそれを言った理由を知っています;)
luis.espinal

1
OPの口からIs a coding style principle - e.g. the single-exit principle - really a good thing?-これは、コーディングスタイルについて、彼が提起している質問にコンテキストを与えます。さらに、コーディングスタイルはプログラミング方法論とは異なり、特にIEEEの記事の焦点である高レベルの設計方法(著者によって明確に述べられています)。だから私は「いいえ」と言います。
luis.espinal

1
私はOPがどこから来たのか疑っています。彼は、コーディング方法(方法論ではない)、特にシングルリターンとマルチリターンを明確に述べています。私は、複数のreturnステートメントを使用して、単一のリターンを使用してより複雑なバージョンに書き換える、特に書かれた、本質的に自明のコードで特にそれに対処しなければなりませんでした(特に、大きなテープの大きな組織で) 「プロセス」ごと。そして、そのようなarbitrary意的な任務の有効性、使いやすさ、費用対効果について疑問に思います(そして証拠に挑戦します)。そのような義務を強制する人々は、まだ60年代に住んでいます:/
luis.espinal

1

コーディングスタイルの原則です。たとえば、単一出口の原則です。

1つの出口か複数の出口かを考えている人々は、まだ1960年代後半に立ち往生しています。当時、このような議論は構造化プログラマーの初期段階にあったため重要であり、Bohm-Jacopini構造化プログラム定理の背後にある発見はすべてのプログラミング構造に普遍的に適用できるわけではないことを宣言する多くのキャンプがありました。

それはずっと前に解決されるべきものでした。まあ、それは解決しました(アカデミアと業界の両方で、正確にはほぼ40年)が、人々(絶対に賛成か反対か)は注意を払っていません。

私の残りの答えに関しては、それはすべて相対的です(ソフトウェアにはないものは何ですか?):

  • 本当にいいこと?

はい。ほとんどの場合、一般的なケースでは、エッジケースおよび言語固有のプログラミング構成に固有の注意事項があります。

常にですか、それとも時々ですか?

ほとんどの時間。

それは実際にどのくらい違いますか?

依存します。

読み取り可能なコードと読み取り不可能なコード。複雑さの増加(これでエラーが発生する可能性が増加する)と単純な複雑さ(そしてエルゴ、エラーの可能性が小さくなる)コンパイラーが暗黙的な戻り値を追加しない言語(Pascal、Java、C#など)とデフォルトはint(CおよびC ++)。

結局、それはキーボードの後ろの人/時間で磨かれたスキルです。次のように、複数のreturnステートメントを使用しても問題ない場合があります(一部のPascal風の擬似コード)。

function foo() : someType
  begin
  if( test1 == true )
  then
    return x;
  end
  doSomethignElseThatShouldnHappenIfTest1IsTrue();
  return somethingElse();
end;

意図は明確であり、アルゴリズムは十分に小さく複雑ではないため、単一の戻り点で使用される最終的な戻り値を保持する「フラグ」変数の作成を保証しません。アルゴリズムにエラーがある可能性がありますが、その構造は非常に単純であるため、エラーを検出する労力は(ほとんどの場合)無視できます。

時々そうではありません(ここではCのような擬似コードを使用しています):

switch(someVal)
{
case v1 : return x1;
case v2 : return x2:
case v3 : doSomething(); // fall-through
case v4: // fall-through
case v5: // fall-through
case v6: return someXthingie;
...
...
default:
   doSomething(); // no return statement yet
}

ここで、アルゴリズムは単純な構造を持たず、switchステートメント(Cスタイルのステートメント)は、アルゴリズムの一部として意図的に実行される場合とされない場合のフォールスルーステップを許可します。

アルゴリズムは正しいかもしれませんが、不完全に書かれています。

あるいは、プログラマの能力を超えた外力によって、これは合法的に必要なアルゴリズムの実際の(そして正しい)表現です。

たぶんそれは間違っています。

これのいずれかの真実を明らかにするには、はるかに多くの努力が必要です、前の例よりもがです。そして、ここに私が強く信じるものがあります(これをバックアップする正式な研究がないことに注意してください):

正しいと想定されるコードスニペットを想定:

  1. 複数のreturnステートメントは、スニペットが本質的に単純なフロー構造を持つ単純なアルゴリズムを表す場合、そのようなコードスニペットの読みやすさと単純さを向上させます。簡単に言うと、私は小さいという意味ではありませんが、本質的に理解できるまたは自明であることを意味します。これは、不均衡な読書努力を必要としません(また、人々がそれを読む必要があるときに嘔吐させたり、誰かの母親を呪ったり、弾丸を飲み込んだりすることもありません)。 )

  2. 戻り値がアルゴリズムの実行中に計算される場合、または計算の責任を負うアルゴリズムのステップがアルゴリズムの構造内の1つの場所にグループ化できる場合、単一のreturnステートメントにより、そのようなコードの可読性と単純さが向上します。

  3. 単一のreturnステートメントは、1つまたは複数のフラグ変数への割り当てが必要で、そのような割り当ての場所がアルゴリズム全体に均一に配置されていない場合、そのようなコードの可読性と単純さを低下させます。

  4. 複数のreturnステートメントは、returnステートメントがアルゴリズム全体に均一に分散されておらず、サイズや構造が均一ではない相互に排他的なコードブロックを区別する場合、そのようなコードの可読性と単純さを低下させます。

これは、問題のコードスニペットの複雑さに密接に関連しています。そして、これは順番にサイクロマティックおよびハルステッド複雑度の測定に関連しています。これから、次のことを観察できます。

サブルーチンまたは関数のサイズが大きいほど、その内部制御フロー構造は大きく複雑になり、複数または単一のreturnステートメントを使用するかどうかという問題に直面する可能性が高くなります。

結論は次のとおりです。関数を1つだけ実行し、1つだけ実行する(および適切に実行する)ように小さくします。それらが名目上小さな循環的およびハルステッド複雑性メトリックを示す場合、それらはおそらく最も正確であり、理解可能なタスクの実装であることに縛られるだけでなく、その内部構造も比較的自明です。

その後、非常に簡単に、また多くの睡眠を失うことなく、どちらの選択でもエラーを引き起こすリスクをあまり冒さずに、単一のリターンと複数のリターンを使用するかどうかを決定できます。

また、このすべてを見て、単一のリターンまたは複数のリターンの問題に苦しんでいるとき、それは-経験不足、愚かさ、または労働倫理の欠如による-きれいなコードを書かず、書く傾向があることを示唆することができますサイクロマティックおよびハルステッド測定を完全に無視した巨大な関数。


1
C ++の戻り値の型はデフォルトではintではありません。デフォルトの戻り値の型はないため、すべての場合に指定する必要があります。
シェード

私がこの質問を書く前から-Programmers.stackexchange.com/questions/58237/…。基本的に、私は原則の認識を主張していますが、厳密にそれを守っていません-すべての出口点が明白であれば、私は幸せです。ここでの私のポイント-原則を例として挙げたからといって、その原則を主張しているわけではなく、厳密な形式ではありません。私の主観的な意見は、それだけです-私の意見に対するより強力な議論があるかもしれませんし、私が間違っているという強力な議論があるかもしれません。
Steve314

「intのデフォルト」とは何ですか?
curiousguy

つまり、コードに明示的な戻り値のない実行分岐がある場合、ほとんどのコンパイラは単にアキュムレータレジスタの値を戻り値として単純に「移動」するということです。実際には、最後の算術演算の結果(ガベージが何であれ)をint形式で返すことを意味します。そして、そもそも関数が何をしようとしていたかに関係なく、それは確かにゴミ(そしてエルゴ、未定義の動作)になります。CおよびC ++は警告を発しますが、コンパイルでは-Werrorなどを使用しない限りコンパイルできます。
luis.espinal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.