メモ
設計

そんな気がするメモ

はじめに

 経験則多めのそんな気がするだけのメモです。

エラーとログ

 エラーハンドリングとログの記録方法を最初に決定すべき。エラーハンドリングは言語の設計に従うのが良い気がする。Python3なら例外、Goなら戻り値。
 ログはUNIX系ならsyslogなど。

アーキテクチャー

 アーキテクチャーはプロジェクトの土台。最初に設計すべき。MVCなど実績のあるアーキテクチャーを選択する。
 MVCの適用風景。

$ mkdir project
$ touch project/models.py
$ touch project/views.py
$ touch project/ctrls.py

インターフェースとコンポジション

 インターフェースに依存し、継承よりもコンポジションを多用すると、設計に多少の柔軟性が生まれるらしい。使ってみると確かにそんな気はする。
 フレームワークの利用者の視点で見ると、継承は拡張の手間が少なく、コンポジションの場合は継承より拡張の手間が多くなる気がする。

拡張の手間 設計の柔軟性
継承 低 
コンポジション
/**
 * インターフェ―ス。
 */
interface Book {
    public String getTitle();
    public String getAuthor();
}

/**
 * Bookインターフェースを実装したクラス。
 */
class RedBook implements Book {
    public String getTitle() {
        return "The Red Book";
    }

    public String getAuthor() {
        return "Taro Tanaka";
    }
}

/**
 * インターフェース。
 */
interface Printer {
    public void print();
}

/**
 * Bookをコンポジションするクラス。
 */
class BookConsolePrinter implements Printer {
    private Book _book; // インターフェースに対する依存

    BookConsolePrinter(Book book) {
        // Book をコンポジション
        _book = book;
    }

    public void print() {
        System.out.println(_book.getTitle() + " by " + _book.getAuthor());
    }
}

class Main {
    public static void main(String args[]) {
        /* コンポジションを多用するとこのレイヤー(Main)の処理が増える傾向がある。
        このレイヤーはファクトリーなどで代替される。 */
        Book book = new RedBook();
        Printer printer = new BookConsolePrinter(book); // Bookをコンポジション
        printer.print();
    }
}

テスト

 実装がテスト可能かどうかを気にすると良い気がする。「テスト不可能≒設計が複雑」という指針は乱暴?関連にDIがある。

レイヤー

 処理がレイヤー可されているかどうか、似た物同士がないか気にすると良い気がする。ファイル名はレイヤー名を表している。身近な例でMVCがある。

mvc
$ ls
models.py # モデル・レイヤー
views.py # ビュー・レイヤー
ctrls.py # コントロール・レイヤー

 過去にマルチプロセスなアプリケーション(ChromeExtension)を作成したとき、バイト列とオブジェクトを相互変換するために変換レイヤーを設けたら上手く行ったことがある。

プロセス1から受け取ったバイト列を変換レイヤーでオブジェクトにする。
process1 -> bytes -> conv -> object

オブジェクトを変換レイヤーでバイト列にしてプロセス2に渡す。
process2 <- bytes <- conv <- object

 その時もやはりファイル名はconv.jsでレイヤー名を表していた。変換処理がこのファイル内で完結するため管理がしやすく実装が捗った。
 他にもSQLを使う場合、MVCを適用するとモデル・レイヤーにSQLが集約されたことがあった。モデル・レイヤーによってDBへのアクセスが集約され、管理がしやすくなった。
つまり似た物同士は同じ所に集めると管理がしやすい(レイヤー化)気がする。

共通化

 似たような処理を共通化すると大体うまく行くが、たまに失敗する気がする。メソッドAとメソッドBで同じような処理をしているのでメソッドCに切り出して共通化すると、大体うまく行くが、失敗することもある。不思議。

汎用性のある抽象化

 汎用性のある抽象化は正義。例えばcssなら、

my-nantoka-row {
  margin: 0 0 4px 0;
  font-size: 14px;
}

 などのオートクチュールなパーツではなく、

small-row {
  margin: 0 0 4px 0;
}
normal-font {
  font-size: 14px;
}

 のように汎用性のあるパーツにすると拡張性&保守性が上がる。