doc.dev1x.org

Composed Method

1. 背景

長いメソッドの可読性(保守性)を向上させたい

2. 課題

メソッドで行われる処理が具体的過ぎる

class Program:

    def __init__(self, user_db, item_db):
        self.user_db = user_db
        self.item_db = item_db

    def run(self, user_id):
        # データのチェック
        if user_id is None:
            raise ValueError()

        # データの取得1
        user_data = self.user_db.find_by_id(user_id)
        user_history_data = self.user_db.fetch_history(user_id)

        # データの加工
        item_id_list = []
        for i in user_history_data:
            item_id_list.append(i['item_id'])

        # データの取得2
        item_data = self.item_db.find_item_id(item_id_list)

        # データの加工2
        history = []
        for h in user_history_data:
            for item in item_data:
                if h['item_id'] == item['id']:
                    tmp = {}
                    tmp['購入日'] = h['購入日']
                    tmp['item'] = item
                    history.append(tmp)

        # データの合成
        result = {}
        result['user'] = user_data
        result['history'] = tmp

        return result

3. 解決策

処理のブロック単位でメソッドを分割する

class Program:

    def __init__(self, user_db, item_db):
        self.user_db = user_db
        self.item_db = item_db

    def run(self, user_id):
        # データのチェック
        self._validation(user_id)

        # データの取得1
        user_data = self._fetch_user_data(user_id)
        user_history_data = self._fetch_history_data(user_id)

        # データの加工
        item_id_list = self._extract_item_id(user_history_data)

        # データの取得2
        item_data = self._fetch_item_data(item_id_list)

        # データの加工2
        history_data = self._create_history_data(user_history_data, item_data)

        # データの合成
        result = self._create_result_data(user_data, history_data)

        # 処理結果を返却
        return result


    def _validation(user_id):
        if user_id is None:
            raise ValueError()

    def _fetch_user_data(user_id):
        return self.user_db.find_by_id(user_id)

    def _fetch_history_data(user_id):
        return self.user_db.fetch_history(user_id)

    def _fetch_item_data(item_id_list):
        return self.item_db.find_item_id(item_id_list)

    def _extract_item_id(user_history_data)
        result = []
        for i in user_history_data:
            result.append(i['item_id'])

        return result

    def _create_history_data(user_history_data, item_data)
        history = []
        for h in user_history_data:
            for item in item_data:
                if h['item_id'] == item['id']:
                    tmp = {}
                    tmp['購入日'] = h['購入日']
                    tmp['item'] = item
                    history.append(tmp)

        return history

    def _create_result_data(user_data, history_data)
        result = {}
        result['user'] = user_data
        result['history'] = history_data

        return result

4. メリット

コードが分かりやすくなる

5. デメリット

忌避感を抱く人もいる

6. 注意事項

小さなメソッドが増えることに対する懸念

脚注

参考資料