Skip to content

Instantly share code, notes, and snippets.

@siritori
Last active November 10, 2020 13:59
Show Gist options
  • Save siritori/3601485823d8c5aab391f26c77b1415f to your computer and use it in GitHub Desktop.
Save siritori/3601485823d8c5aab391f26c77b1415f to your computer and use it in GitHub Desktop.

単一責任の原則 (SRP)

意味

1つのクラス・モジュール・関数を変更する理由は1つ以上存在してはならない。

なぜこの原則がある?

  • いろいろなものをモックしないといけないのでテストしづらくなる
  • 1つ修正したときに周辺確認がやたら多くなり工数が増える

反している例

とあるシステムで製品のリストをCSVファイルで管理しており、 そこからいま販売中の製品だけを出力する社内向けスクリプトを書いた。

// いま販売している製品のリストをTSVファイルで出力する
function generateAvailableProductList(companyName: string): void {
    // filePathからテキストデータを読み出す
    const text: string = file.readFileSync(`../products/${companyName}.csv`);
    // CSVとしてパース
    const header = ["no", "name", "available", "count"];
    const csv: CSV = CsvParse.parse(text, { header });
    let lines = "";
    // 読みだした結果を使ってTSVファイルを作る
    for (const row of csv.rows) {
        if (row["available"] === "1") continue;
        const line = row["name"] + "\t" + row["count"] + "\n";
        lines += line;
    }
    file.writeFileSync(`${companyName}.tsv`, lines);
}

いろいろな変更理由でこの関数を修正したくなる。

  • インフラチームから連絡: クラウド移行したのでファイルをローカルではなくサーバから取得して。
  • システムチームから連絡: CSVファイルの列の順序が変更されたよ or カラム名が変わったよ。
  • ユーザーから要望: UTF-8のTSVファイルじゃExcelで開けないからCSVで出力してよ。

適応している例

// 製品
class Product {
    no: number;
    name: string;
    available: boolean;
    count: number;
}

// 製品情報リストをCSVファイルから読み出す
function readProductListCsv(csvText: string): Product[] {
    const header = ["no", "name", "status", "count"];
    const csv: CSV = CsvParse.parse(csvText, { header });
    return csv.rows.map(row => {
        const no = row["no"];
        const name = row["name"];
        const available = row["available"] === "1";
        return { no, name, available };
    });
}

// 製品情報リストをロードする
function loadProductList(companyName: string): Product[] {
    const csvText = file.readFileSync(`products/${companyName}.csv`);
    return readProductListCsv(csvText);
}

// いま販売している製品のリストをTSVファイルで出力する
function generateAvailableProductList(companyName: string): void {
    const products = loadProductList(companyName);
    let lines = "";
    // 読みだした結果を使ってTSVファイルを作る
    for (const product of products) {
        if (!product.available) continue;
        const line = product.name + "\t" + product.count + "\n";
        lines += line;
    }
    // 書き込み
    file.writeFileSync(`${companyName}.tsv`, lines);
}
  • インフラチームから連絡: クラウド移行したのでファイルをローカルではなくAPIサーバから取得して。
    • loadProductListを修正
  • システムチームから連絡: CSVファイルの列の順序が変更されたよ or カラム名が変わったよ。
    • readProductListCsvを修正
  • ユーザーから要望: UTF-8のTSVファイルじゃExcelで開けないからCSVで出力してよ。
    • generateAvailableProductListを修正

クイズ

  • これで本当にSRPにしたがっているか?
  • これが最善か?

.

.

.

.

.

.

.

.

.

.

.

.

答え: 状況に依る。

  • 製品数が増えてメモリ上に乗り切らなくなったらloadProductListは単純な配列を返せなくなる。
  • システムの構成がもうFIXしているのを知っている場合、このコードはムダに長い。
    • 変更の理由が変更たるのは、実際に変更の理由が生じた場合だけである。
    • 変更の兆候がないのに単一責任の原則を適用するのは、やめたほうがいい。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment