자료구조 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;
}