はじめてのIT勉強会 #3 Readable Code Part 3

はじめてのIT勉強会 #3 Readable Code Part 3

仙台で開催した「はじめてのIT勉強会」第三回のセッションスライドです。
リーダブルコードの紹介と入門的な解説内容になっています。

24c8a3c481718ce8631ed38ae4bfb104?s=128

Ruku Tanaka

June 29, 2017
Tweet

Transcript

  1. Readable Code Part 3: 美しさ はじめてのIT勉強会 in 仙台

  2. 自己紹介 (リーダブルな名前に憧れる31歳)

  3. 美しさ?

  4. どちらが見やすいですか? いろいろな図形 三角形 ◆頂点が3つある ◆内角の和が180度になる 四角形 ◆頂点が4つある ◆内角の和が360度になる いろいろな図形 三角形

    ◆ 頂点が3つある ◆ 内角の和が180度になる 四角形 ◆ 頂点が4つある ◆ 内角の和が360度になる A B
  5. プログラミングでも同じように 美しいレイアウトで書こう!

  6. POINT コードは読み飛ばしたり、 類似や相違をパッと見て解るような 快適で読みやすいものであるべき

  7. 基本原則 • 読み手が慣れているパターンと 一貫性のあるレイアウトを使う • 似ているコードは似ているように見せる • 関連するコードをまとめてブロックにする

  8. 1.一貫性のある簡潔な改行

  9. public class PerformanceTester { public static final TcpConnectionSimulator wifi =

    new TcpConnectionSimulator( 500, /* Kbps */ 80, /* millisecs latency */ 200, /* jitter */ 1 /* packet loss % */); public static final TcpConnectionSimulator t3_fiber = new TcpConnectionSimulator( 45000, /* Kbps */ 10, /* millisecs latency */ 0, /* jitter */ 0 /* packet loss % */); public static final TcpConnectionSimulator cell = new TcpConnectionSimulator( 100, /* Kbps */ 400, /* millisecs latency */ 250, /* jitter */ 5 /* packet loss % */); } 不用意に目立っている
  10. public class PerformanceTester { public static final TcpConnectionSimulator wifi =

    new TcpConnectionSimulator( 500, /* Kbps */ 80, /* millisecs latency */ 200, /* jitter */ 1 /* packet loss % */); public static final TcpConnectionSimulator t3_fiber = new TcpConnectionSimulator( 45000, /* Kbps */ 10, /* millisecs latency */ 0, /* jitter */ 0 /* packet loss % */); public static final TcpConnectionSimulator cell = new TcpConnectionSimulator( 100, /* Kbps */ 400, /* millisecs latency */ 250, /* jitter */ 5 /* packet loss % */); }
  11. public class PerformanceTester { // new TcpConnectionSimulator(throughput, latency, jitter, packet_loss);

    // [Kbps] [ms] [ms] [percent] public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator( 500, 80, 200, 1); public static final TcpConnectionSimulator t3_fiber = new TcpConnectionSimulator( 45000, 10, 0, 0); public static final TcpConnectionSimulator cell = new TcpConnectionSimulator( 100, 400, 250, 5); }
  12. 2.メソッドを使った整列

  13. assert(expandFullName($databaseConnection, "Doug Adams", $error) === "Mr. Douglas Adams"); assert($error ===

    ""); assert(expandFullName($databaseConnection, " Jake Brown ", $error) === "Mr. Jacob Brown III"); assert($error === ""); assert(expandFullName($databaseConnection, "No Such Guy", $error) === ""); assert($error === "No match found."); assert(expandFullName($databaseConnection, "John", $error) === ""); assert($error === "More than one result.");
  14. $expandNameTest->checkFullName("Doug Adams", "Mr. Douglas Adams", ""); $expandNameTest->checkFullName(" Jake Brown ",

    "Mr. Jacob Brown III", ""); $expandNameTest->checkFullName("No Such Guy", "", "No match found."); $expandNameTest->checkFullName("John", "", "More than one result."); function checkFullName(string $partialName, string $expectedFullName, string $expectedError) { $error = ''; $fullName = expandFullName($this->dbConn, $partialName, $error); assert($fullName === $expectedFullName); assert($error === $expectedError)); }
  15. 3.縦の線をまっすぐにする

  16. // partialName , expectedFullName , expectedError checkFullName("Doug Adams" , "Mr.

    Douglas Adams" , ""); checkFullName("Jake Brown" , "Mr. Jacob Brown III" , ""); checkFullName("No Such Guy", "" , "No match found."); checkFullName("John" , "" , "More than one result."); checkFullName("Doug Adams", "Mr. Douglas Adams", ""); checkFullName(" Jake Brown ", "Mr. Jacob Brown III", ""); checkFullName("No Such Guy", "", "No match found."); checkFullName("John", "", "More than one result.");
  17. // POSTのパラメータをローカル変数に割り当てる $details = $request->getPost("details"); $location = $request->getPost("location"); $phone =

    $equest->getPost("phone"); $email = $request->getPost("email"); $url = $request->getPost("url"); バグを見つけてください
  18. // POSTのパラメータをローカル変数に割り当てる $details = $request->getPost("details"); $location = $request->getPost("location"); $phone =

    $equest->getPost("phone"); $email = $request->getPost("email"); $url = $request->getPost("url");
  19. // POSTのパラメータをローカル変数に割り当てる $details = $request->getPost("details"); $location = $request->getPost("location"); $phone =

    $request->getPost("phone"); $email = $request->getPost("email"); $url = $request->getPost("url");
  20. 4.一貫性と意味のある並び

  21. // POSTのパラメータをローカル変数に割り当てる $details = $request->getPost("details"); $location = $request->getPost("location"); $phone =

    $request->getPost("phone"); $email = $request->getPost("email"); $url = $request->getPost("url");
  22. // パラメータがnullの場合、空文字列で初期化する $details $phone $email $url $location = $details =

    $phone = $email = $url = $location === null ? "" : $details; === null ? "" : $phone; === null ? "" : $email; === null ? "" : $url; === null ? "" : $location; locationはどこ? なんで下にあるの?
  23. POINT ランダムに並べずに 意味のある順番に並べよう

  24. 並び順の例 • 入力フォームと同じ並び順にする • テーブルのカラムと同じ順にする • 「最重要」なものから重要度順に並べる • アルファベット順に並べる

  25. 5.宣言をブロックにまとめる

  26. interface FrontendServer { public function viewProfile(HttpRequest $request); public function openDatabase(string

    $location, string $user); public function saveProfile(HttpRequest $request); public function extractQueryParam(HttpRequest $request, string $param); public function replyOK(HttpRequest $request, string $html); public function findFriends(HttpRequest $request); public function replyNotFound(HttpRequest $request, string $error); public function closeDatabase(string $location); }
  27. interface FrontendServer { // ハンドラ public function viewProfile(HttpRequest $request); public

    function saveProfile(HttpRequest $request); public function findFriends(HttpRequest $request); // リクエストとリプライのユーティリティ public function extractQueryParam(HttpRequest $request, string $param); public function replyOK(HttpRequest $request, string $html); public function replyNotFound(HttpRequest $request, string $error); // データベースのヘルパー public function openDatabase(string $location, string $user); public function closeDatabase(string $location); }
  28. 6.コードを「段落」に分割する

  29. // ユーザのメール帳をインポートして、システムのユーザと照合する。 // そして、まだ友達になっていないユーザのメールアドレスを取得する。 function suggestNewFriendEmails(User $user, string $emailPassword) {

    $friends = $user->getFriends(); $friendsEmails = array(); foreach ($friends as $friend) { $friendsEmails[] = $friend->getEmail(); } $contacts = importContacts($user->getEmail(), $emailPassword); $contactEmails = array(); foreach ($contacts as $contact) { $contactEmails[] = $contact->getEmail(); } $nonFriendEmails = array_diff($contactEmails, $friendsEmails); return $nonFriendEmails; }
  30. // ユーザのメール帳をインポートして、システムのユーザと照合する。 // そして、まだ友達になっていないユーザのメールアドレスを取得する。 function suggestNewFriendEmails(User $user, string $emailPassword) {

    $friends = $user->getFriends(); $friendsEmails = array(); foreach ($friends as $friend) { $friendsEmails[] = $friend->getEmail(); } $contacts = importContacts($user->getEmail(), $emailPassword); $contactEmails = array(); foreach ($contacts as $contact) { $contactEmails[] = $contact->getEmail(); } $nonFriendEmails = array_diff($contactEmails, $friendsEmails); return $nonFriendEmails; }
  31. // ユーザのメール帳をインポートして、システムのユーザと照合する。 // そして、まだ友達になっていないユーザのメールアドレスを取得する。 function suggestNewFriendEmails(User $user, string $emailPassword) {

    // ユーザの友達のメールアドレスを取得する。 $friends = $user->getFriends(); $friendsEmails = array(); foreach ($friends as $friend) { $friendsEmails[] = $friend->getEmail(); } // ユーザの連絡先からすべてのメールアドレスをインポートする。 $contacts = importContacts($user->getEmail(), $emailPassword); $contactEmails = array(); foreach ($contacts as $contact) { $contactEmails[] = $contact->getEmail(); } // まだ友達になっていないメールアドレスを探して返す。 $nonFriendEmails = array_diff($contactEmails, $friendsEmails); return $nonFriendEmails; }
  32. 7.個人的な好みと一貫性

  33. if ($eventEnded === true) { removeEvent($currentEvent); } else { echo("CurrentEvent:

    " + $currentEvent); } Java(K&R)スタイル C#(オールマン)スタイル
  34. POINT 一貫性 > 正しさ

  35. この章のまとめ

  36. 美しく整ったコードを書くには ・同じような繰り返しは、同じシルエットにする *要素の開始や改行の位置を揃えることで、視覚的な手すりを付ける ・メソッドを使用して、重要な情報にフォーカスを当てる *DBへの接続など、その処理の本質でない部分を隠す ・意味のある並びを一貫して使用する *一方で「A, B, C」と並んでるものを「B,A, C」のように並べない

    ・空行やコメントで段落に分ける *読む必要のあるところだけをすぐに見つけることができるようになる ・個人的な好みより、チームでの一貫性を守る *コーディングスタイルが入り乱れると読みにくくなるので統一する
  37. ご清聴、ありがとうございました