クリーンコード–フォーマット
1. 序章
私たちがプロの開発者であるか、コードの最初の行を書き始めたばかりであるかにかかわらず、 camelCase 、 PascalCase 、などの変数や関数のさまざまなフォーマットスタイルにすでに直面している可能性があります。 ] snake_case 、およびkebab-case。
これは、プログラミング時に定義する必要のあるスタイルの側面の1つにすぎませんが、他にもあります。ファイル内の行数、インデントスタイル、メソッド、クラス、スコープのルールが異なります。 その上、各プログラミング言語には構文要件と特異性があります。
この記事では、すべてのプログラマーに同じスタイルを期待することは不可能であるため、コードに組み込むための優れたプラクティスについて説明します。 その上、チームで作業する場合、コードはメンバー間のコミュニケーションツールであるため、保守性が大幅に低下した場合、プログラムを機能させるだけでは不十分です。
私たちのコードが優れた可読性を持ち、他の人が私たちの論理プログラミングとソフトウェアアーキテクチャの理解をあきらめないようにすることに焦点が当てられます。 例はJavaで書かれていますが、概念は他のプログラミング言語にも当てはまります。
2. 垂直フォーマット
クリーンなコードを書くことに関して最も有名なアナロジーの1つは、新聞のメタファーです。これは、コードを読むプロセスは新聞を読むプロセスと似ている必要があると述べています。
見出しだけを読むことから始めます。 次のステップでは、要約を含む段落を読みます。 次に、そのトピックについて学習することに関心があるので、記事の下部にある詳細をさらに深く掘り下げることにします。
同様に、ファイルのタイトルと主要な概念およびアルゴリズムは、ソースコードの上部に簡単に見つけることができます。小さくてより具体的なタスクに使用される関数と変数は、読者は、私たちのコードが何のために作られたのかをすでに一瞥しています。
2.1. 垂直密度
ブロックが完全な概念または考えを表す場合(たとえば、HTMLファイルで文字列をレンダリングするための数行)、このブロックとその隣接ブロックの間に空白行を配置する必要があります。 これは、概念間の垂直開放性と呼ばれます。
この考え方は垂直密度と密接に関連しており、目的が密接に関連している場合は、句または操作を表すコード行を次のコード行から分離してはならないことを示しています。
すべきでないことの例を見てみましょう。
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''", Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
/**
* Adds the HTML closing tag
*/
html.append(childHtml()).append("</b>");
return html.toString();
}
}
このコードは、前に説明した概念を適用していないことが簡単にわかります。
まず、コード全体が1つのブロックとしてグループ化されているため、垂直方向の開放性はありません。 それに加えて、本質的に接続されているコードの行を区切る役に立たないコメントがあります。
ここで、優れたスタイリング手法を適用した後、同じコードを見てみましょう。
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));
}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
適切にフォーマットされたコードを数秒見てみると、各コードブロックがプログラムで何をしているのかを理解できます。
それでは、最初のコードをもう一度見てみましょう。 オープン性や密度の問題なしに何千行も書かれたファイルを想像してみてください。 おそらく、このタイプのコードの作成者でさえ、数か月後にはその作業を理解できなくなります。
2.2. 垂直距離
読者がすべてのファイルと行を読み飛ばさないようにするには、相関する概念を常に互いに垂直に近づける必要があります。 これと併せて、すべての変数をできるだけ使用法に近いものとして宣言する必要があります。特に、1つのスコープにのみ存在することが予想されるループで使用される変数はそうです。
会社の従業員を処理するクラスを、クラスコンストラクターと年齢、給与、および職位の割り当てで定義したと想像してみてください。 次の手順では、ランダムな値を生成し、要素に対していくつかのテストを実行するための新しいクラスを作成しました。
2つのクラスがそのようにリンクされていることを考えると、読者が別のファイルで500行またはさらに悪いことにコンストラクタークラスを検索するのはどれほど苛立たしいことでしょうか。
2.3. 垂直方向の順序
コードの順序は、プログラムの依存関係を本能的に表す必要があります。 各行を読むときは自然な流れがあるはずです。
高レベルの関数が低レベルと見なされる関数を呼び出す場合、前者をソースファイルの最初に配置する必要があります。
これにより、関数が新しい関数を呼び出すときに心配する必要がないという正しい印象が読者に与えられます。これは、次の数行で、呼び出された関数ができるだけ早く詳細に説明されるためです。
3. 水平フォーマット
コードの行はどのくらいの長さにする必要がありますか? 良い習慣として何年も残っていた経験則は、1890年の米国国勢調査のためのホレリスのパンチカードを検討することでした:1行あたり80文字。
主に、プログラミングしているフレームワークによっては、iOSのように関数名が元々長くなる可能性があるため、この数値を厳密な規則と見なすべきではありません。
リーナス・トーバルズ自身は、この限られた見解に反対し、長い線は基本的に有用で自然であると主張しました。
では、コンセンサスがない場合、私たちは何に取り組むべきでしょうか?
3.1. 水平方向の開放性と密度
以前よりもはるかに高い解像度のモニターを見つけることができることを考慮し、ボブおじさんの提案に従って、このための優れたガイドラインを作成できます。
コードを読み取れるように右にスクロールする必要をできるだけ避けて、行を100〜120文字にするようにしてください。
垂直方向の書式設定と同様に、水平方向の空白を使用して、強く接続されているものを識別し、無関係なものを分離する必要があります。
通常、空白は代入演算子を囲みます。
public class CountCharsInString {
public static void main(String[] args) {
String exampleString = "This is just a sample string";
long totalCharacters = exampleString.chars().filter(ch -> ch != ' ').count();
System.out.println("There are total " + totalCharacters + " characters in exampleString");
}
}
スペースが左右の演算子の分離をどのように明らかにしているかに気付くことができます。 ただし、関数は強く関連しているため、関数の名前と引数の間にスペースはありません。
3.2. 水平方向の配置とインデント
水平方向の観点から分析する場合、完全な位置合わせを目指すべきではありません。 代わりに、読者が変数の型または代入演算子を簡単に確認できるようにする限り、整列の欠如が望まれます。
各演算子と宣言を揃えようとすると、読者が間違った順序で物事を読んだり、割り当てではなく変数を読んだりするようになります。
public FitNesseExpediter(Socket s,
FitNesseContext context) throws Exception
{
this.context = context;
socket = s;
input = s.getInputStream();
output = s.getOutputStream();
requestParsingTimeLimit = 10000;
}
最後に、フレームワークに関係なく、コードを作成するときに注意する必要がある最も重要な側面の1つは、インデントです。
ソースファイルは基本的に階層を表します。このため、読者はコードを初めて見るときに簡単にレベルを見つける必要があります。
数行のコードでのみ使用される変数は、メイン関数またはクラス宣言と同じレベルに配置しないでください。
インデントは、コードの依存関係とスコープに気付く視覚的な方法です。 正しく使用しない場合、基本的な機能を理解するためにコードを大幅に調べる必要があります。
public class Factorial{ public static void main(String[] args){ final int NUM_FACTS = 100; for(int i = 0; i < NUM_FACTS; i++) System.out.println( i + "! is " + factorial(i));}
public static int factorial(int n){ int result = 1;for(int i = 2; i <= n; i++) result *= i; return result;}}
インデントを適用すると、読みやすさが大幅に向上します:
public class Factorial{
public static void main(String[] args){
final int NUM_FACTS = 100;
for(int i = 0; i < NUM_FACTS; i++)
System.out.println( i + "! is " + factorial(i));
}
public static int factorial(int n) {
int result = 1;
for(int i = 2; i <= n; i++)
result *= i;
return result;
}
}
4. 結論
コードのフォーマット方法は自由に選択できますが、将来、他の人がコードを読む可能性があることを常に念頭に置いておく必要があります。 チームで作業するときは、プロジェクトがプロフェッショナルで更新や理解が容易になるように、大規模なプロジェクトのすべてのファイルで一貫したスタイルを維持するために、グループの全員がルールに同意する必要があります。
ロバートCとして。 マーティンはそれを彼の著書CleanCode に書いています。「コーディングスタイルと読みやすさは、元のコードが認識できないほど変更された後も、保守性と拡張性に影響を与え続ける先例を設定しました。 コードがしなくても、あなたのスタイルと規律は存続します。」