doc.dev1x.org

合成関数を用いたSLA原則の実現

1. 目的

SLA原則に準拠したコードを書きたい

2. 課題

3. 解決策

処理のステップを関数化し、関数の羅列で処理のステップを表現する

def step1(dto):
    dto.value = dto.value + 10
    return dto

def step2(dto):
    dto.value = dto.value + 40
    return dto

def step3(dto):
    dto.value = dto.value * 2
    return dto

関数間で共有されるデータはDTOを引き回す

class Dto:
    def __init__(value, is_stop = False):
        self.value = value
        self.is_stop = is_stop

関数合成でパイプラインを構築する

def exec(dto, *fns):
    for f in fns:
        dto = f(dto)
        if dto.is_stop: break
    return dto
if __name__=="__main__":
    dto = dto(0, False)
    result = exec(
        dto,
        step1,
        step2,
        step3
    )
    print(result.value)

4. メリット

制御構造とビジネスロジックを分解できる

def exec(dto, *fns):
    for f in fns:
        dto = f(dto)
        if dto.is_stop:
            break
    return dto
def step1(dto):
    dto.value = dto.value + 10
    return dto

def step2(dto):
    dto.value = dto.value + 40
    return dto

def step3(dto):
    dto.value = dto.value * 2
    return dto

処理の追加/削除が容易になる

ステップ毎のテストが容易になる

5. デメリット

ロジックが分散するのでプログラムの理解が困難になる

プログラマに一定の抽象化能力が要求される

DTOの状態を意識する必要がある

6. 注意事項

参考資料

Appendix-1 ソースコード全体

class Dto:
    def __init__(value, is_stop=False):
        self.value = value
        self.is_stop = is_stop

def exec(dto, *fns):
    for f in fns:
        dto = f(dto)
        if dto.is_stop: break
    return dto

def step1(dto):
    dto.value = dto.value + 10
    return dto

def step2(dto):
    dto.value = dto.value + 40
    return dto

def step3(dto):
    dto.value = dto.value * 2
    return dto


if __name__=="__main__":
    dto = dto(0, False)
    result = exec(
        dto,
        step1,
        step2,
        step3
    )
    print(result.value)     # => 100