Golang Cafe #19 まとめ 「Twelve Go Best Practices」を読む(要約編)

前回Twelve Go Best Practices」についてソースコードを中心にまとめておいたが、続きを進めたところ要約編(?)も必要を感じたのでまとめておきます。

最初にエラー処理を行うことでネストを避ける

関数またはメソッドの戻り値としてerrorが返される場合、関数またはメソッド呼び出し後すぐにエラーチェックを行い、エラーが発生した場合はその時点で処理を中断します。

可能な場合は繰り返しを避ける

「関数またはメソッドの呼び出し、エラーチェック・処理、後処理」などのエラーチェックを含む同じ処理が繰り返される場合は、1つの構造体のメソッドにまとめます。メソッド内で行なったエラーチェックの結果は構造体のフィールドに保持しておき、またメソッドの先頭では以前にエラーが発生したかどうか確認し(フィールドを確認)、エラーが発生していた場合はメソッド中の処理を中断します。
すべてのメソッド呼び出しを行なった後、エラーチェックの結果を保持しているフィールドを確認し、エラーが発生していた場合は、処理を中断します。
メソッド呼び出し側はエラーを意識する必要がないが、1回のメソッド呼び出しにコストがかかる場合は考慮する必要があります。

特定の場合を処理するために type switch を使用する

ある処理を行うために変数の方によって関数またはメソッドの呼び出し回数が異なる場合ば、呼び出された関数またはメソッド内で変数の型ごとに処理を分けます。こうすることで呼び出し側はいずれの場合は関数またはメソッドの呼び出しは1回のみになります。
呼び出された関数またはメソッド内では type switch を用いて処理を振り分けます。

v := interface{}
switch v.(type) {
...

のように記述することでcase文で変数の型ごとに処理を行うことができます。

ブロック内スコープの変数宣言を用いて type switch を使用する

先の例ではcase文で変数の型ごとに処理を行なっていましたが、case文ごとに type assertion を用いて型の変換を行なっていました。type switch ではブロックスコープの変数を宣言することができます。

v := interface{}
switch x := v.(type) {
...

xにはvの型に応じて type assertion された値が格納されます。これでcase文ごとに type assertion する必要がなくなります。

全部を書くか全く何もしないか

Writerに対して書き出しを行う場合、メソッド呼び出しごとに実際に書きだすのではなく、bytes.Bufferのようなメモリ中に一旦書き出し、Flushなどのメソッドを用意し、すべてのメソッド呼び出しが正常に完了した場合にのみ、最後に一気に書き出します。
ただし、書き出すデータ用が膨大な場合はメモリを圧迫する可能せがあるので考慮する必要があります。

関数アダプタ

「可能な場合は繰り返しを避ける」では同じ処理の繰り返しを1つの関数またはメソッドにまとめることを行ないました。しかし同じような処理だが1箇所だけ処理が異なるような場合は適用できません。

処理1→処理A→処理2→処理3
処理1→処理B→処理2→処理3

このような場合は処理1→処理X→処理2→処理3のような関数またはメソッドを作成し、処理Xは外部から引数で指定するようにします。

func method(processX func(int, string) error) {
    // 処理1
    processX(1, "some string")
    // 処理2
    // 処理3
}

func main() {
    method(func(i int, s string) error {
        // 処理A
    })
    method(func(i int, s string) error {
        // 処理B
    })
}

いわゆるAdapterパターンです。

読んでおいたほうがよい書籍

Twelve Go Best Practices」を読み進める上でGo言語の知識はもちろん必要ですが、以下の書籍にも目を通しておくほうが良いかもしれません。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

レガシーコード改善ガイド (Object Oriented SELECTION)

レガシーコード改善ガイド (Object Oriented SELECTION)

いずれもJavaを対象に書かれていますが、考え方は適用できます。