My Favorite Things - Coding or die.

とある技術者の経験記録、的な。

リーダブルコード - The Art of Readable Code まとめ

良いコードを書くのは得意だという自負があったのでなんとなく読むのをスルーしていたが、改めて読んでみると勉強になる部分がとても多かった。特に「最短時間で理解できるコードが読みやすいコードだ」という一文にはとても感銘を受けた。あとは自分の中でも答えが出ていなかったものに対して、明確な回答が用意されていてよかった。
 
以下、自分が重要だと思ったことを少しずつまとめていく。
 
1章
  • コードは理解しやすくなければいけない
  • コードは他の人が最短時間で理解できるように書かなければいけない

 
第I部 表面上の改善
 
2章 名前に情報を詰め込む
  • 明確な単語を選ぶ(get → fetch / download、stop → pause / kill)
  • 抽象的な名前よりも具体的な名前を使う(--run_locally → —use_local_database)
  • 名前に情報を追加する(id → hex_id)
  • 値の単位(start → start_ms)
  • その他の重要な属性を追加する(plaintext_password、unescaped_comment、html_utf8)
  • スコープが小さければ短い名前でもいい
    // コードを理解するのに必要な情報がすぐそばにあるからだ。
  • 不要な単語を投げ捨てる(ConvertToString() → ToString())
  • 名前のフォーマットで情報を伝える(コーディング規約での命名規約とか)
 
3章 誤解されない名前
  • filter() → select() / exclude()
  • Clip(text, length) → remove(text, length) / truncate(text, length)
  • 限界値を含めるときはminとmaxを使う
  • 範囲を指定するときはfirstとlastを使う
  • 包含/排他的範囲にはbeginとendを使う
  • ユーザの期待に合わせる(getMean() → computeMean()、size() → countSize())
 
4章 美しさ
  • なぜ美しさが大切なのか?
    → 見た目が美しいコードのほうが使いやすいのは明らかだ。考えてみれば、プログラミングの時間のほとんどはコードを読む時間なのだッ!
  • 一貫性のある簡潔な改行位置
  • (ヘルパー)メソッドを使った整列
    // コードの「見た目をよく」すれば、表面上の改善だけではなく、コードの改善もできる
  • 縦の線をまっすぐにする
  • 整列すべきなのか?
    // ぼくたちの経験では、プログラマが心配するほどの手間にはならない
    // もし手間になるようだったら、そのときは止めればいい
  • 宣言をブロックにまとめる
    // 論理的なグループに分けてあげるといいだろう
  • コードを「段落」に分割する
    • 似ている考えをグループにまとめて、他の考えと分ける
    • 視覚的な「踏み石」を提供できる
    • 段落単位で移動できるようになる
  • 個人的な好みと一貫性
    → 一貫性のあるスタイルは「正しい」スタイルよりも大切だ。
 
5章 コメントすべきことを知る
  • コメントの目的は、書き手の意図を読み手に知らせることである。
  • コードからすぐにわかることをコメントに書かない。
    • 例:Accoutクラスの定義
  • ひどい名前はコメントをつけずに名前を変える
    • 優れたコード > ひどいコード + 優れたコメント
  • 自分の考えを記録する
    • コードが期待ない理由をコメントに書いてもいい
    • コードの欠陥にコメントをつける
      • その欠陥を文書化することを恥ずかしがってはいけない
  • 定数にコメントをつける
    • なぜその値を持っているのかという「背景」が存在する場合が多い
    • 頭のなかで考えていたことを記録するのが大切
  • 読み手の立場になって考える
    • 質問されそうなことを想像する
    • // ベクタのメモリを開放する(「STL swap技法」で検索してみよう)
    • 「このコードを見てビックリすることはなんだろう?」
    • 「どんなふうに間違えて使う可能性があるだろう?」
    • 要約コメント(全体像についてコメントする)
 
6章 コメントは正確で簡潔に
  • コメントは領域に対する情報の比率が高くなければいけない
  • コメントを簡潔にしておく
    • // CategoryType -> (score, weight)
      typedef hash_map<int, pair<float, float> > ScoreMap;
  • 曖昧な代名詞を避ける(それ)
  • 歯切れの悪い文章を磨く(によって優先度を変える → の優先度を高くする)
  • 関数の動作を正確に記述する
    • // このファイルに含まれる改行文字(’\n’)を数える。
      int CountLines(string filename) { … }
  • 入出力のコーナーケースに実例を使う
    • // 実例:Strip(“abba/a/ba”, “ab”)は”/a/“を返す
      String Strip(String src, String chars) { … }
  • コードの意図を書く(listを逆順にイテレートする → 値段の高い順に表示する)
  • 情報密度の高い言葉を使う(キャッシュ、正規化)
 

OCMockのサンプルコード

APIリファレンスっぽいものが見つからなかったので、とりあえずテストコードを書いてみた。 YusukeHosonuma/OCMockSample · GitHub

気が向いたら追加していく予定。

//
//  OCMockSampleTests.m
//  OCMockSampleTests
//
//  Created by Yusuke on 6/23/15.
//  Copyright (c) 2015 Yusuke. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "Foo.h"

@interface OCMockSampleTests : XCTestCase

@property (nonatomic, assign) BOOL handleNotificationMockCalled;
@property (nonatomic, assign) BOOL andDoBlockCalled;

@end

@implementation OCMockSampleTests

- (void)setUp {
    [super setUp];
    self.handleNotificationMockCalled = NO;
    self.andDoBlockCalled = NO;
}

- (void)tearDown {
    [super tearDown];
}

/// --- create

- (void)test_makeForClass {
    
    // クラス定義からMockを生成する
    id mock = [OCMockObject mockForClass:[NSString class]];
    NSInteger returnValue = 100;
    [[[mock stub] andReturnValue:[NSValue valueWithBytes:&returnValue objCType:@encode(NSInteger)]] length];
    XCTAssertEqual([mock length], 100);
}

- (void)test_makeForClassWithMacro {
    
    // マクロ版
    id mock = OCMClassMock([NSString class]);
    OCMStub([mock length]).andReturn(100); // マクロを使うと参照型かプリミティブ型か区別しなくても良さそう
    XCTAssertEqual([mock length], 100);
}

- (void)test_partialMockObject {
    
    // 生成ずみのオブジェクトからMockを生成する
    Foo *foo = [[Foo alloc] init];
    id mock = [OCMockObject partialMockForObject:foo];
    [[[mock stub] andReturn:@"foo!"] bar];
    XCTAssertEqualObjects(@"foo!", [mock bar]);
}

- (void)test_partialMockObjectWithMacro {
    
    // マクロ版
    Foo *foo = [[Foo alloc] init];
    id mock = OCMPartialMock(foo);
    OCMStub([mock bar]).andReturn(@"foo!");
    XCTAssertEqualObjects(@"foo!", [mock bar]);
}

// --- andXxx

- (void)test_andReturn {
    
    // andReturn - 任意の値(id型)を返す
    id mock = [OCMockObject mockForClass:[NSString class]];
    [[[mock stub] andReturn:@"foo!"] stringByAppendingString:[OCMArg any]];      // 対象のメソッドが引数を取るときは[OCMArg any]を与える
    [[[mock stub] andReturn:@"bar!"] stringByAppendingPathExtension:OCMOCK_ANY]; // マクロで書くならOCMOCK_ANY
    XCTAssertEqualObjects(@"foo!", [mock stringByAppendingString:@"dummy"]);
    XCTAssertEqualObjects(@"bar!", [mock stringByAppendingPathExtension:@"dummy"]);
}

- (void)test_andReturnValue {

    // andReturnValue - andReturnのプリミティブ値バージョン
    id mock = OCMClassMock([NSString class]);
    NSInteger returnValue = 100;
    [[[mock stub] andReturnValue:[NSValue valueWithBytes:&returnValue objCType:@encode(NSInteger)]] length];
    XCTAssertEqual(100, [mock length]);
}

- (void)test_andThrow {
    
    // andThrow - 例外をスローするようにする
    id mock = OCMClassMock([NSString class]);
    id exception = [NSException exceptionWithName:@"dummy" reason:@"" userInfo:nil];
    [[[mock stub] andThrow:exception] length];
    XCTAssertThrows([mock length]);
}

- (void)test_andPost {

    // andPost - Notificationをpostするようにする
    id mock = OCMClassMock([NSString class]);
    id notification = [NSNotification notificationWithName:@"mock" object:self];
    [[[mock stub] andPost:notification] length];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationMock:)
                                                 name:@"mock"
                                               object:nil];
    
    [mock length];
    XCTAssertTrue(self.handleNotificationMockCalled);
}

- (void)handleNotificationMock:(NSNotification *)notification {
    self.handleNotificationMockCalled = YES;
}

- (void)test_andCall {
    
    // andCall - 代わりのメソッドを呼び出すようにする
    Foo *foo = [[Foo alloc] init];
    id mockStr = OCMPartialMock(foo);
    [[[mockStr stub] andCall:@selector(mockBar) onObject:self] bar]; // SELでかわりに呼び出すメソッドを指定する
    XCTAssertEqualObjects(@"mockBar!", [mockStr bar]);
}

- (NSString *)mockBar {
    return @"mockBar!";
}

- (void)test_andDo {
    
    // andDo - 特定のBlocksを呼び出すようにする
    id mock = OCMClassMock([NSString class]);
    [[[mock stub] andDo:^(NSInvocation *invocation) {
        self.andDoBlockCalled = YES;
    }] length];
    [mock length];
    
    XCTAssertTrue(self.andDoBlockCalled);
}

- (void)test_andForwardToRealObject {
    
    // andForwardToRealObject - Mockが保持している実際のオブジェクトへ呼び出しを転送するようにする
    Foo *foo = [[Foo alloc] init];
    id mock = OCMPartialMock(foo); // PartialMockでないとNG
    [[[mock stub] andForwardToRealObject] bar];
    XCTAssertEqualObjects(@"bar!", [mock bar]);
}

// --- expect / verify

- (void)test_expect_verify {
    
    // expect - そのメソッドが呼び出されることを期待し、
    // verify - で検証する
    Foo *foo = [[Foo alloc] init];
    id mock = OCMPartialMock(foo);
    [[mock expect] hoge]; // hogeメソッドが呼び出されていること(を期待)
    [mock foo];
    [mock verify]; // 検証
}

- (void)test_expect_verifyWithDelay {
    
    // verifyWithDelay - n秒後に検証する
    Foo *foo = [[Foo alloc] init];
    id mock = OCMPartialMock(foo);
    [[mock expect] hoge];
    [mock fooDelay];
    [mock verifyWithDelay:0.2]; // 0.2秒後に検証
}

@end

Java8でFizzBuzz

StreamAPIとかJava8の機能を使ったらどうかけるだろう、と思って書いてみた。
gist.github.com

無駄に無限数列を定義してるけれど、こういう書き方が出来るようになっとことを考えるとJavaも変わったよな、と思う。
とりあえずStreamAPIバンザイ!

Node.jsメモ

ドットインストールで勉強してみたので簡単にメモっておく。 dotinstall.com

基本的なこと

  • シングルスレッドモデル(イベントループ)
  • JavaScriptで動く
  • コールバックを用いた非同期処理

モジュール?の読み込み

var http = require('http'),
    settings = require('./setting.js'); // 自分で作ったものはパスを指定

モジュールのインストール

npm(node package manager)を使う

$ sudo npm install xxx

JS(サーバ)の実行

$ node server.js

Hello, world

// bind request event.
server.on('request', function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'}); // response-header
    res.write('Hello, world'); // response-body
    res.end(); // finish response
}

// start listen
server.listen(1337, 'localhost');

テンプレートエンジン

ejs(Embedded JavaScript templates)とかが使える。

<html>
<h1><%= title %></h1> <!-- escape -->
<p><%- content %></p> <!-- non-escape -->
<p><%= n %> views</p>
</html>

クエリ処理

querystringというパッケージが便利。

    if (req.method === 'POST') {
        req.data = ""; // init
        req.on('readable', function() { // while-reading
            req.data += req.read();
        });
        req.on('end', function() { // read-finish.
            console.log(req.data);
            var query = qs.parse(req.data); // parse
        });
    }

「7つの言語 7つの世界」を読み始めた

www.amazon.co.jp


随分前に買ったけれど読んでなかったので、今更ながら読み始めた。
第一章のRubyを読み書きしながら学習中。

久しぶりにインタプリタ言語を書いたけれども、やっぱり手軽に実行できるのはすごく便利だと思った。その代わりに、やっぱりコンパイル時に発見できないことが多くてそこはデメリットだとも改めて思った。

しかし、Rubyのコードブロックは素敵である。
テキストファイルの読み込みとか簡単すぎてびっくりする。

f =open('sample.txt')
f.each {|line| print line}
f.close