見出し画像

クリーンコード / Clean Code (日本語 / English)

こんにちは、The DesigniumGeraldです。 今日はクリーンコードを紹介して、色々なアドバイスを示します。 コーディング例では、Unity / C#で作成されたコードを使用していますが、クリーンコード原則は他のプログラミング言語に適用されます。

The English version is below the Japanese Version.

「クリーンコード」って何?

「Clean Codeはシンプルで直接的なもの。
Clean Codeは散文のようなコードだ」   --Grady Booch

私の経験とクリーンコードを読んだ結果に基づいて、クリーンなコードは:

* 読みやすい
同僚は説明なしでコードをわかります
* 簡単
各クラスとメソッドには1つの責任があります
* 上品
コードをざっと見るだけで、コードを理解できます
* フォーマットうまくされている
奇妙な改行なし、正しい括弧など

独自の投稿に値するので、自動テスト(単体テスト、統合テスト、受け入れテスト)については書きません。

なぜクリーンコードが必要か?

クリーンコードを作成するのは品質測定だから時間が掛かります。 価値がある理由は次のとおりです:

* チームは作者なしで働くことができます
経験豊富なプログラマーは確かにコードに遭遇しましたが、彼らは理解できず、作者の助けを必要としました
* クリーンなコードは拡張が簡単です
理解しやすいコードは、面倒なコードよりも拡張して再利用する方が安全です。
* 簡単なバグ修正
特に「単一の責任原則」を維持する場合(詳細は後で説明します)、バグの理由をすばやく特定できます
* 簡単なパフォーマンスの向上
動作を壊さずに簡単なコードを操作する方が安全です
* 数年後のコードを理解
コードは遅かれ早かれ忘れられます

では、どのようにクリーンコードしますか?

意味のある名前

Yコードを作成するときは、常に名前が必要です。 クラス、メソッド、変数 、ファイル、ディレクトリ。 多くのプログラマーはネーミングの力を過小評価しています。
良い名前はコード内で多くのことを説明するため、コードがクリーンになります。

意図による名前

意図的に変数に名前を付けることにより、変数はその機能と使用方法を明らかにします。 クラスでこのような変数を簡単にたどることができます。

rb = GetComponent<Rigidbody>();					    // bad
d = Vector3.Distance(pointA, pointB);
rigidbody = GetComponent<Rigidbody>();				// good
distance = Vector3.Distance(pointA, pointB);

読みやすい名前

プログラミング言語はコミュニケーションについて理解する必要があります。 実生活では、誰も略語で話すことはありません。
変数characterControllerを読み取るだけで、それが何を実行するかが既にわかっているため、宣言にジャンプする必要はありません。

cc = GetComponent<CharacterController>();					    // bad
characterController = GetComponent<CharacterController>();		// good

クラス名

クラス名は、たとえばPlayer、Enemy、PlayerInventoryなどの名詞でなければなりません。
Manager、Info、Dataなどの一般的な名前は、単一責任の原則に違反し、すべてのコードを1つの単一クラスに配置するため、避けてください。

メソッド名

メソッド名は常にPlay、StopAudio、MovePositionのような動詞または動詞句である必要があります。

コンスタント

数値と文字列にコンスタントを使用して、意図を示します。

velocity.y -= 9.81f * Time.deltaTime;				// bad
ShowMessage(“Player left the match”);
velocity.y -= Gravity * Time.deltaTime;				// good
ShowMessage(PlayerLeftText);

単一の責任

メソッドとクラスが行うことは1つだけです。 より多くのメソッドは、簡潔さを向上させる小さなメソッドを意味します。
また、メソッドとクラスを増やすことで、コードに意図的な名前を付け、コマンドの巨大なブロックを置き換えます。

void Update()									// bad
{
  moveDirection = new Vector3(horizontalAxis, 0.0f, verticalAxis);
  characterController.Move(moveDirection * Time.deltaTime);
  if (Input.GetButtonDown("Fire1")) {
     Instantiate(ShootParticle);
  }
}

このメソッドを最初に見るとき、これが実際に何をするかを考える必要があります。 メソッド内のコードを抽出することにより、理解しやすく、読みやすくなります。
Update()メソッドは2つのことを行うので、いくつかのメソッドを作成しましょう。

void Update() {									// good
  MoveCharacter();
  Shoot();
}

private void MoveCharacter() {
  moveDirection = new Vector3(horizontal, 0.0f, verticalAxis);
  characterController.Move(moveDirection * Time.deltaTime);
}

private void Shoot() {
  if (Input.GetButtonDown("Fire1")) {
     Instantiate(ShootParticle);
  }
}

ほとんどのIDEでは、コードを選択し、「抽出メソッド」のショートカットを使用して簡単にリファクタリングできます。

Image 1

リファクタリング

高品質のコードの場合、コードを確認して最適化することが重要です。 最初は完璧なコードを書くことはできませんが、後で改善することはできます。
特に、試行錯誤する必要がある場合は、不正なコードを記述してもかまいません。 しかし、後でそれをリファクタリングしてください!

 void Update() {							        // bad
  if (Input.GetKeyDown(KeyCode.F9)) {
     ScreenCapture.CaptureScreenshot(Application.dataPath + 
        "/screenshot.png", 4);
  }
}

これは問題なく機能しますが、シンプルさ、読みやすさ、拡張性を向上させることができます:

private const KeyCode ScreenShotKey = KeyCode.F9;
private const int QualityMultiplier = 4;
private const string FileName = "screenshot.png";

void Update() {                                    // good
  if (Input.GetKeyDown(ScreenShotKey)) {
     TakeScreenshot();
  }
}

private void TakeScreenshot() {
  ScreenCapture.CaptureScreenshot(GetScreenshotPath(), 
    QualityMultiplier);
}

private string GetScreenshotPath() {
  return Application.dataPath + "/" + FileName;
}

コメント使わないで

「不正なコードはコメントしないで。書き直して。」
Brian W. Kernighan and PJ Plaugher

コメントでコードを説明しないでください。 コメントは通常一度書かれますが、正しく維持されません。 作成されたコードの約50%は、書き換え、最適化、リファクタリング、変更、またはバグ修正されています。 しかし、誰もコメントを修正しません。

コメントを書く代わりに、時間をかけてコードを改善してください。
コードを説明する必要があると思われる場合は、コードをメソッドまたは変数に抽出します。

void Update() {										        // bad
  speedometer.Show(currentSpeed * 3.6f));	// convert to km/h
}
void Update() {										        // good		
  speedometer.Show(ConvertToKilometerPerHour(currentSpeed));
}

private float ConvertToKilometerPerHour(float meterPerSecond) {
  return meterPerSecond * 3.6f;
}

APIを作成するとき、または回避策を実行するときのみ、コメントを使用できます。

概要

* メソッド、変数、クラスに適切な名前を使用して
* コードは本のように読まれるべきです
* メソッドには1つのタスクしかありません
* クラスの責任は1つだけです
* 機能するときにコードを最適化して
* コメントを使用しない



ENGLISH VERSION

Hey, I am Gerald of The Designium. I am introducing clean coding and showing some tips and tricks today. For my coding examples, I am using code made in Unity / C#, but the clean coding principles apply for every other programming language.

“Clean code is simple and direct. Clean code reads like well-written prose.”
-- Grady Booch, author of Object Oriented Analysis

Based on my experience and reading clean code books, a clean code is:
* Easy to read
coworkers can read it without explanation
* Simple
each class and method has one responsibility
* Elegant
just by viewing the code briefly, you understand what the code does
* Formatted nicely
no weird line breaks, correct brackets, etc.

I will not go write about automated tests (unit tests, integration tests, acceptance tests), since it is worth a own post.

Why should I code clean?

Creating clean code takes more time to create, like any other quality measurements in life. Here are some reasons why it’s worth:

* Your team can work without you
Experienced coders surely encountered a code, which they didn’t understand and need help from the author
* Clean code is easier to extend
Understandable code is safer to extend and reuse again rather than a messy code
* Easier bug fixing
Especially when you keeping the Single Responsibility Principle (more on that later), you can fast pinpoint the reason of the bug
* Easier to do performance increases
It is just safer to manipulate a easy code, without breaking the behaviour
* Understand your code years later
We will forget our written code sooner or later. 

So, how do we code clean?

Meaningful Names

When we create code, we always need names. Classes, methods, variables, files, directories. Many programmers underestimate the power of naming.
Good names explain a lot in your code, which makes your code cleaner.

Names by intention

By naming a variable by your intention, the variable reveals what it does and how it is used. It makes it easy to follow such a variable in class.

rb = GetComponent<Rigidbody>();					    // bad
d = Vector3.Distance(pointA, pointB);
rigidbody = GetComponent<Rigidbody>();				// good
distance = Vector3.Distance(pointA, pointB);

Pronounceable names

Programming languages should be understood as to communicate. In real life nobody really talks in abbreviations.
Just by reading the variable characterController, you already know what it does and no need to jump to the declaration.

cc = GetComponent<CharacterController>();					    // bad
characterController = GetComponent<CharacterController>();		// good

Class names

Class names should be a noun for example Player, Enemy, PlayerInventory.
Try to avoid common names like Manager, Info, Data, etc., since it violates the Single Responsibility Principle and leads to put all code in one single class.

Method names

Method names should always be a verb or verb phrase like Play, StopAudio, MovePosition.

Constants

Use constants for numbers and strings to show your intentions.

velocity.y -= 9.81f * Time.deltaTime;					// bad
ShowMessage(“Player left the match”);
velocity.y -= Gravity * Time.deltaTime;				// good
ShowMessage(PlayerLeftText);

Single Responsibility

Functions and classes should only do one thing. More Methods mean smaller methods which improve simplicity.
Also by making more methods and classes, we bring more intentional names into our code and replacing giant blocks of commands.

void Update()									// bad
{
  moveDirection = new Vector3(horizontalAxis, 0.0f, verticalAxis);
  characterController.Move(moveDirection * Time.deltaTime);
  if (Input.GetButtonDown("Fire1")) {
     Instantiate(ShootParticle);
  }
}

When we first take a look at this method, we need to think about what this actually does. By extracting code in methods, it gets more understandable and easier to read.
The Update() method does two things, so let's create some methods.

void Update() {									// good
  MoveCharacter();
  Shoot();
}

private void MoveCharacter() {
  moveDirection = new Vector3(horizontal, 0.0f, verticalAxis);
  characterController.Move(moveDirection * Time.deltaTime);
}

private void Shoot() {
  if (Input.GetButtonDown("Fire1")) {
     Instantiate(ShootParticle);
  }
}

In most IDEs, you can select your code and use a “Extract Method” shortcut for easy refactoring.

画像2

Refactoring

For high quality codes, it is important to review and optimise your code. Nobody can write perfect code at first, but we can improve it later.
Especially when we have to try-and-error, it is ok to write bad code. But refactor it later!

void Update() {							    // bad
  if (Input.GetKeyDown(KeyCode.F9)) {
     ScreenCapture.CaptureScreenshot(Application.dataPath + 
        "/screenshot.png", 4);
  }
}

This works fine, but we can improve simplicity, readability and extendibility:

private const KeyCode ScreenShotKey = KeyCode.F9;
private const int QualityMultiplier = 4;
private const string FileName = "screenshot.png";

void Update() {                            // good
  if (Input.GetKeyDown(ScreenShotKey)) {
     TakeScreenshot();
  }
}

private void TakeScreenshot() {
  ScreenCapture.CaptureScreenshot(GetScreenshotPath(), QualityMultiplier);
}

private string GetScreenshotPath() {
  return Application.dataPath + "/" + FileName;
}

Do not Comment!

“Don’t comment bad code — rewrite it.”
  -- Brian W. Kernighan and P. J. Plaugher

Comments shouldn’t explain your code. Comments are normally written once, but not maintained correctly. About 50% of our written code is rewritten, optimised, refactored, changed or bug-fixed. But nobody fixes the comments.

Use your time to improve the code instead of writing a comment.
If you think you need to explain your code, extract it to methods or variables.

void Update() {										    // bad
  speedometer.Show(currentSpeed * 3.6f));	// convert to km/h
}
void Update() {										    // good		
  speedometer.Show(ConvertToKilometerPerHour(currentSpeed));
}

private float ConvertToKilometerPerHour(float meterPerSecond) {
  return meterPerSecond * 3.6f;
}

Only when writing APIs or doing workarounds, comments can be used.

Summary

* Use good names for methods, variables and classes
* Your code should be read like a book
* A method has only one task
* A class has only one responsibility
* Optimise your code when it works
* Don’t use comments


出典 / Sources
https://medium.com/@george.seif94/these-5-clean-code-tips-will-dramatically-improve-your-productivity-b20c152783b
https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
https://hackernoon.com/how-to-write-clean-code-d557d998bb08

Editorial Note 編集後記

こんにちは、広報のマリコです!最近デザイニウムにジョインしたGeraldさんは、会津オフィス所属のエンジニアです✨今回はWebエンジニアに加えてゲームプログラマーの経験もある彼に自由に書いてもらいました。いくつか候補があった中でも特に「クリーンコード」は社内エンジニアからのリクエストが多数(笑)しかも!日本語も堪能なので今回は本人自ら英語版日本語版ともに書いてもらいました❗しかも母国語はドイツ語なハズ…。す、凄すぎるー❗そしてありがたい✨というわけで、今後もGeraldさんの投稿をお楽しみに😊

The Designium.inc
Interactive website
Twitter
Facebook



この記事が気に入ったらサポートをしてみませんか?