SlideShare a Scribd company logo
1 of 20
可読性について Part5
優れたテストコード(2)
- 無関係の下位問題を抽出する
- メソッド名と違う処理をしていたら切り出そう
- 一度に1つのことを
- 単一責任の原則
- コードに思いをこめる
- コードの動作を子供でも分かるように言葉に置き換える
- 短いコードを書く
- 最も読みやすいコードは、何も書かれていないコード
前回のおさらい
- Part4では、テストコードについて
- カウンタを設計・実装する
- まとめ
- 最後に
優れたテストコード
1 カウンタを設計・実装する
1-1 問題点
- ウェブサーバの直近の1分間と直近の1時間の転送バイト数を把握したい。
1-2-1 クラスのインターフェースを定義する
- Count()の別候補
- Increment()
- Observer()
- Record()
- Add()
1-2-2 名前を改善する
1-2-3 コメントを改善する
- 冗長なコメントを削除し、正確な言葉を使って誤解のない明確なものにする
1-3-1 試案1:素朴な解決策
タイムスタンプのついた「イベント」のlistを保持 必要に応じて直近のイベントをカウントできる
1-3-2 読みやすいバージョン
1-3-3 パフォーマンスの問題
- これからも大きくなっていく
- 不要のイベントを自動的に削除すべき
- MinuteCount()とHourCount()が遅すぎる
- 対応する値を別々に保持すべき
1-4-1 試案2:ベルトコンベヤー設計
1. 不要なデータを削除する
2. 事前にminute_countとhour_countの値を最新のものにしておく
- 2段階ベルトコンベヤーが効率的
1-4-2 2段階ベルトコンベヤーの実装
1-4-3 これで終わり?
- この設計には柔軟性がない
- 直近24時間のカウントを保持したいとなると、多くのコードの修正が必要になる
- メモリの使用量が多い
- Add()が呼び出される頻度に関係なく、メモリは一定の方が良い
1-5-1 試案3:時間バケツの設計
- 60秒で60個のバケツを用意して直近1分間のイベントは、1秒ごとに60個のバケツに入れる
- 直近1時間のイベントは、1分ごとに60個のバケツに入れる
- メモリ使用量を固定化できて予測可能になる
1-5-2 時間バケツの実装
期間(直近1時間など)のカウントを追跡するクラスを作る これでMinuteHourCounterは簡単に実装できるように
1-5-3 TrailingBucketCounterを実装する
ConveyorQueueというデータ構造を作る
1-5-4 ConveyorQueueの実装
3つの解決策を比較
- テストと読みやすさ
- 安心してテストの追加や変更ができるようにする読みやすくする
- 最小のテストを複数作る
- テストの適切な入力値を選択する
- テストに優しい開発
- プロジェクトの阻害になるようであれば、やりすぎ
- 設計・実装
- 命名は明確に
- 設計は柔軟なものに
まとめ
3 最後に
- 実際にやる
- 他の人に読んでもらう
- 続けることが大事

More Related Content

Similar to 可読性について リーダブルコード Part5(優れたテストコード2)

使い捨て python コードの書き方
使い捨て python コードの書き方使い捨て python コードの書き方
使い捨て python コードの書き方Sho Shimauchi
 
20141224 titech lecture_ishizaki_public
20141224 titech lecture_ishizaki_public20141224 titech lecture_ishizaki_public
20141224 titech lecture_ishizaki_publicKazuaki Ishizaki
 
リーダブルコード 1.0'
リーダブルコード 1.0'リーダブルコード 1.0'
リーダブルコード 1.0'Yamamura Takashi
 
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010Tsukasa Oi
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPNSaitoNmiri
 
大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験について大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験についてRakuten Group, Inc.
 
テスト勉強会よしおか100311 1
テスト勉強会よしおか100311 1テスト勉強会よしおか100311 1
テスト勉強会よしおか100311 1Hiro Yoshioka
 
LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)Kazuko Kanai
 
20190625 OpenACC 講習会 第1部
20190625 OpenACC 講習会 第1部20190625 OpenACC 講習会 第1部
20190625 OpenACC 講習会 第1部NVIDIA Japan
 
MySQL Casual Talks Vol.3 LT
MySQL Casual Talks Vol.3 LTMySQL Casual Talks Vol.3 LT
MySQL Casual Talks Vol.3 LTTomohiro Ikeda
 
最近の単体テスト
最近の単体テスト最近の単体テスト
最近の単体テストKen Morishita
 
OpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクトOpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクトuchan_nos
 
Premier night3 devopsことはじめ
Premier night3 devopsことはじめPremier night3 devopsことはじめ
Premier night3 devopsことはじめ淳 千葉
 
LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)Kazuko Itoda
 
【学習メモ#4th】12ステップで作る組込みOS自作入門
【学習メモ#4th】12ステップで作る組込みOS自作入門【学習メモ#4th】12ステップで作る組込みOS自作入門
【学習メモ#4th】12ステップで作る組込みOS自作入門sandai
 

Similar to 可読性について リーダブルコード Part5(優れたテストコード2) (20)

使い捨て python コードの書き方
使い捨て python コードの書き方使い捨て python コードの書き方
使い捨て python コードの書き方
 
20141224 titech lecture_ishizaki_public
20141224 titech lecture_ishizaki_public20141224 titech lecture_ishizaki_public
20141224 titech lecture_ishizaki_public
 
リーダブルコード 1.0'
リーダブルコード 1.0'リーダブルコード 1.0'
リーダブルコード 1.0'
 
良いコードとは
良いコードとは良いコードとは
良いコードとは
 
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSP
 
大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験について大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験について
 
テスト勉強会よしおか100311 1
テスト勉強会よしおか100311 1テスト勉強会よしおか100311 1
テスト勉強会よしおか100311 1
 
Tdd
TddTdd
Tdd
 
LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)
 
20190625 OpenACC 講習会 第1部
20190625 OpenACC 講習会 第1部20190625 OpenACC 講習会 第1部
20190625 OpenACC 講習会 第1部
 
AWS Black Belt Techシリーズ AWS Lambda
AWS Black Belt Techシリーズ AWS LambdaAWS Black Belt Techシリーズ AWS Lambda
AWS Black Belt Techシリーズ AWS Lambda
 
Zabbix study5lt
Zabbix study5ltZabbix study5lt
Zabbix study5lt
 
MySQL Casual Talks Vol.3 LT
MySQL Casual Talks Vol.3 LTMySQL Casual Talks Vol.3 LT
MySQL Casual Talks Vol.3 LT
 
最近の単体テスト
最近の単体テスト最近の単体テスト
最近の単体テスト
 
OpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクトOpeLa: セルフホストなOSと言語処理系を作るプロジェクト
OpeLa: セルフホストなOSと言語処理系を作るプロジェクト
 
Premier night3 devopsことはじめ
Premier night3 devopsことはじめPremier night3 devopsことはじめ
Premier night3 devopsことはじめ
 
LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)LPICレベル1技術解説セミナー(2012/11/11)
LPICレベル1技術解説セミナー(2012/11/11)
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
【学習メモ#4th】12ステップで作る組込みOS自作入門
【学習メモ#4th】12ステップで作る組込みOS自作入門【学習メモ#4th】12ステップで作る組込みOS自作入門
【学習メモ#4th】12ステップで作る組込みOS自作入門
 

More from tak

DiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみたDiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみたtak
 
TypeScriptのdecoratorについて
TypeScriptのdecoratorについてTypeScriptのdecoratorについて
TypeScriptのdecoratorについてtak
 
Rust + web assemblyやってみた
Rust + web assemblyやってみたRust + web assemblyやってみた
Rust + web assemblyやってみたtak
 
第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8tak
 
第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7tak
 
第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6tak
 
第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5tak
 
第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4tak
 
第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3tak
 
第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2tak
 
第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1tak
 
第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則tak
 
第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則tak
 
第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよtak
 
第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクションtak
 

More from tak (15)

DiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみたDiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみた
 
TypeScriptのdecoratorについて
TypeScriptのdecoratorについてTypeScriptのdecoratorについて
TypeScriptのdecoratorについて
 
Rust + web assemblyやってみた
Rust + web assemblyやってみたRust + web assemblyやってみた
Rust + web assemblyやってみた
 
第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8
 
第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7
 
第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6
 
第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5
 
第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4
 
第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3
 
第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2
 
第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1
 
第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則
 
第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則
 
第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ
 
第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション
 

可読性について リーダブルコード Part5(優れたテストコード2)

Editor's Notes

  1. Part4では、テストコードに的を絞った内容になります。ちなみに原文ではC++で記述されていたのでそのまま抜粋しています。そしてリーダブルコード発行当初に比べると、機能が豊富なテスティングフレームワークが多数あるので、時代にそぐわない箇所も多々あるかと思いますが、本書の意図を理解して行くという意味で記載通りの内容を学んで行きたいと思います。
  2. 続いて、第二章は「時間のカウンタ」を設計・実装する、です。同じく問題点を解決しながら、機能を追加していきます。ただし、一番大切なことは、リーダブルコードで一貫して言われている、原則を使ってコードを読みやすくすることです。
  3. 仮にウェブサーバの直近の1分間と直近の1時間の転送バイト数を把握したいと言う課題があったとします。課題としては一般的ですが、これを効率的に解決するのは難しく、まずはクラスのインターフェースを定義するところから始めてみます。
  4. こちらはC++で書かれたクラスのインターフェースの最初の状態です。このクラスを実装する前に名前とコメントに着目してください。変更の余地があると思いますので名前を改善していきます。
  5. Count()は何をするのかが分からないので、ほかの名前を考えていきます。候補としては4つあります。 - Increment() : 値が増加する一方だと思われてしまうのでNGです。 - Observe() : 問題ないが少しあいまいなのでNGです。 - Record() : 名詞と動詞の問題があるのでダメ。 - Add() : 「この数値を追加する」と「データのリストに追加する」というどちらの意味もあり、今回はこのメソッドの名前をAdd(int num_bytes)とする。
  6. より正確で詳細な言葉を使って、誤解のないない明確なものにします。外部の視点を得るために、同僚に素直な第一印象を聞くのが良い手段です。
  7. では、実装する準備が整ったので課題に対してのコードを記述していきます。まずは簡単な方法で、タイムスタンプのついた「イベント」のlistを保持する形にしてみます。必要に応じて直近のイベントをカウントでき、正しくカウントできますが読みにくい点があります。それはforループが少しうるさい点と、メソッドがほとんど同じ点です。
  8. CounSince()の仮引数の名前をsec_agoという相対値ではなく、cutoffという絶対値に設定している。 イテレータの名前をiからritに変えている。 forループからrit->time <= cutoffという条件を抽出して、新しくif文を作っている。
  9. これからも大きくなっていく。このクラスはメモリを無限に使用してしまうため、MinuteHourCounterは、1時間よりも古い不要のイベントを自動的に削除すべきだ。MinuteCount()とHourCount()が遅すぎる。それぞれのメソッドの処理時間はO(n)である。Add()が呼び出された時点で対応する値をminute_countとhour_countとで別々に保持すべきだ。
  10. 先程の問題を両方解決する設計が必要になります。ベルトコンベヤー設計とは、一方の端に新しいデータが到着したら合計に加算すして、データが古すぎたらもう一方の端から「落下」させて合計から減算する設計になります。ベルトコンベヤー設計には2種類あります。1つめは図左のように、2つのlistを管理して、1つは直近1分間のイベントに、もう1つは直近1時間のイベントに使い、新しいイベントが到着したら、両方にコピーを追加します。こちらは単純ですが、非効率です。一方2つめの方法は、2つのlistを管理するには変わりませんが、1番目のlistにイベントが到着してから、2番目のlistに流れ込むようになっています。
  11. イベントは、minute_eventからhour_eventへ移動する。そのあとで、minute_countとhour_countを更新する。汚い仕事はShiftOldEvents()に押し付ける。
  12. この設計には柔軟性が無い。例えば、直近24時間のカウントを保存したいとすると、多くのコードの修正が必要になる。 メモリの使用量が多い。こうトラフィックのサーバが1秒間に100回もAdd()を呼び出すと、直近1時間のデータを全て保持しているので、約5MBのメモリが必要となる。 Add()が呼び出される頻度に関係なく、MinuteHourCounterの使用するメモリは一定の方がよい。
  13. 60秒で60個のバケツを用意して、直近1分間のイベントは、1秒ごとに60個のバケツに入れる。 直近1時間のイベントは、1分ごとに60個のバケツに入れる。 これにより、メモリ使用量を固定化できて予測可能になるということである。
  14. まず、単一責任の原則に従って、複数のクラスで異なる部分を処理するために、期間(直近1時間など)のカウントを追跡するクラスを作ります。これは、1種類の期間した扱えないクラスを汎用化したものです。インターフェイスは図左になります。実装コードは右側になります。
  15. TrailingBucketCounter クラスの実装だけだ。問題をさらに分割するため に、もう一度ヘルパークラスを作ろう。 これから ConveyorQueue というデータ構造を作る。潜在的なカウントと合計を扱う データ構造だ。TrailingBucketCounter クラスは、時間経過に伴って ConveyorQueue を移動させるタスクに集中できる。図右がTrailingBucketCounterを実装したコードになります。
  16. 右側の画像コードで完成になります。これで高速でメモリ効率もよく、簡単に再利用できる柔軟性の高いコードになりました。3つの解決策を比較してみると、時間バケツのコード行数は、他の 2 つのコード行 数よりもずっと多い。でも、パフォーマンスは高いし、設計に柔軟性がある。それ に、クラスに分割しているので読みやすくなりました。
  17. 今回リーダブルコードを題材に、読みやすいコードについてLTを行って来ましたが、今回で終了になります。リーダブルコードの最後に、自然に読みやすいコードを書けるようになるための方法が書かれていたので、紹介させて頂きます。1つ目は当たり前ですが実践することです。実践することで気づくことがたくさんあります。2つめは他の人に読んでもらう、レビューしてもらうです。読みやすいとは「他の人の読む時間を短くする」と言うことなので、実際のFBをもらい精度を高めていきます。最後の3つめは続けることです。基本的にリーダブルコードで書かれていることは基本的なことばかりです。読みやすいコードを当たり前にして続けていきましょう。