프로그래밍

[클린코드] 6,7장 정리

Victory_HA 2023. 10. 18. 00:34

자료구조 vs 객체

  • 객체는 추상화 뒤로 자료를 숨기고, 자료를 다루는 함수만 공개한다.
  • 자료구조는 자료를 그대로 공개하고, 함수는 다루지 않는다.
  • 새로운 자료 타입이 필요한 경우, 객체가 적합하다.
  • 새로운 함수가 필요한 경우, 절차적인 코드와 자료 구조가 적합하다.

추상화

  • 변수를 private으로 선언하더라도 조회함수(get), 설정함수(set)을 제공한다면 구현을 외부로 노출시키는 셈이다.
  • 구현을 감추려면 추상화가 필요하다.
  • 사용자가 구현을 모르는 상태로 자료를 조작할 수 있어야한다.

  • 아래 코드는 개인적으로 추상화가 잘됐다고 생각한 코드 부분이다.
  • python 모델 판정을 위한 인터페이스와 구현체 클래스이다.
  • 아래와 같은 코드는 다른 모델과의 교체 및 확장이 쉬워지며 코드의 유지 보수가 용이해진다고 생각한다.

// 인스턴스 생성부분
private IInferencePythonWrapper CreatePythonWrapper(ModelRecipe modelRecipe)
{
    if (modelRecipe.Network == Network.Tensorflow2_S2Model_224)
        return new InferenceTensorflow2SpecificModel();
    else
        return new InferenceTensorflow2Wrapper();
}

...

// 인터페이스
public interface IInferencePythonWrapper
{
    bool Initialize(PythonModelInfo inferItem, ILoggingAdapter logger);
    (bool, dynamic) InferenceBatchImage(List<string> imagePaths, ILoggingAdapter logger);
    (bool, dynamic) InferenceImage(string imagePath, ILoggingAdapter logger);
    (bool, dynamic) InferenceUNetSegmentation(string imagePath, float threshold, ILoggingAdapter logger);
}

...

// 구현부
public class InferenceTensorflow2Wrapper : IInferencePythonWrapper
{
    private dynamic InferenceTensorflow2;

    public bool Initialize(PythonModelInfo modelInfo, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceBatchImage(List<string> imagePaths, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceImage(string imagePath, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceUNetSegmentation(string imagePath, float threshold, ILoggingAdapter logger)
    {
    ...
    }
}

public class InferenceTensorflow2SpecipicModelWrapper : IInferencePythonWrapper
{
    private dynamic InferenceTensorflow2;
    public bool Initialize(PythonModelInfo modelInfo, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceBatchImage(List<string> imagePaths, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceImage(string imagePath, ILoggingAdapter logger)
    {
    ...
    }

    public (bool, dynamic) InferenceUNetSegmentation(string imagePath, float threshold, ILoggingAdapter logger)
    {
    ...
    }
}

디미터법칙

  • "다른 객체의 내부 구조에 대해 알지 말고, 당신이 직접 상호 작용하는 객체와만 대화하라"
    • 객체 A는 객체 B와 직접 연관된 속성, 메서드, 객체에 대해서만 알아야 하며,
    • 객체 B의 내부 구조나 관련된 객체에 대해서는 알 필요가 없다.

오류 코드보다 예외처리

  • 함수를 호출한 즉시 오류를 확인하는 경우 코드가 복잡해진다.
  • 중복코드 제거 및 복잡한 조건문은 예외 처리하여 가독성을 높인다.

AS-IS

private List<TrainGpuDeviceInfo> CheckGpuDeviceInfo()
{
    List<TrainGpuDeviceInfo> gpuDatas = GetGpuDatas();
    if (GpuUseageDataList != null)
    {
        foreach (var item in gpuDatas)
        {
            var gpu = GpuUseageDataList.Where(x => x.GpuNo == item.GpuNo).FirstOrDefault();
            if (gpu == null)
                continue;

            item.UseGpu = gpu.UseGpu;
        }
    };

    return gpuDatas;
}

TO_BE

private List<TrainGpuDeviceInfo> CheckGpuDeviceInfo()
{
    try
    {
        List<TrainGpuDeviceInfo> gpuDatas = GetGpuDatas();
        foreach (var item in gpuDatas)
        {
            var gpu = GpuUseageDataList.Where(x => x.GpuNo == item.GpuNo).FirstOrDefault();
            item.UseGpu = gpu.UseGpu;
        }
    }
    catch (Exception e)
    {
        _logger.Error($"There is no gpu data", e);
        throw;
    }

    return gpuDatas;
}