이론/설계

클린코드 7장 - 오류 처리

tsyang 2021. 5. 21. 03:35

깔끔한 오류 처리는 중요하다 여기 저기 흩어진 오류 처리 코드 때문에 코드의 가독성이 떨어질 수 있기 때문이다.

 

오류 코드보다 예외

예외처리가 아닌 오류 처리는 기본적으로 if,else 분기를 타며 Debug.Log(...)를 하는 코드이다. 그러나 이런식으로 쓰면 논리가 오류 처리 코드와 뒤섞여 알아보기 힘들다. 그러나 예외를 사용하면 이를 구분할 수 있다. 단, 앞 장에서 말했듯, 오류 처리도 '한 가지 일'이다. 오류를 처리하는 알고리즘은 분리해야 한다.

public void DoSomething()
{
    try
    {
        TryDoSomething();
    }
    catch (Exception e)
    { }
}

 

Try-Catch-Finally 부터 작성해라

별 이유는 아니고 이렇게 하면 자연스럽게 try 블록의 트랜잭션 범위부터 구현하게 됨.

 

 

예외에 충분한 정보를 담아라.

로그 잘 쓰자.

 

 

호출 코드를 고려하여 예외 클래스를 정의하라

외부 API인 SomePort를 호출한다고 가정하자, SomePort는 해당 API만의 여러 예외들을 던질 수 있다.

Someport port = new Someport();

try
{
    port.Open();
}
catch (SomePortException_A e)
{
    Console.WriteLine("A");
}
catch (SomePortException_B e)
{
    Console.WriteLine("B");
}
catch (SomePortException_C e)
{
    Console.WriteLine("C");
}

 

그러면 위 코드처럼 될 것이다. 보면 예외 클래스와 무관하게 예외 처리 방법이 거의 유사하다. 이런 경우 Wrapper 클래스를 이용하여 예외를 묶어줄 수 있다.

public class WrapperPort
{
    private SomePort innerPort;

    public void Open()
    {
        try
        {
            innerPort.Open();
        }
        catch (SomePortException_A e)
        {
            throw new CommonPortExeption(e);
        }
        catch (SomePortException_B e)
        {
            throw new CommonPortExeption(e);
        }
        catch (SomePortException_C e)
        {
            throw new CommonPortExeption(e);
        }
    }
}
WrapperPort port = new WrapperPort`();

try
{
    port.Open();
}
catch (CommonPortException e)
{
    Console.WriteLine(e);
}

이렇게 되면 코드가 깨끗해질 뿐 아니라 앞서 말했던 것 처럼 외부 API를 감싸면서 의존성도 좋아진다.

 

 

특수 사례 및 null

try
{
    var curFrameAttackInfo = GetCurFrameAttackInfo();
    hp -= curFrameAttackInfo.damage;
}
catch (NoAttackInfoException e)
{
    hp -= defaultDamage;
}

위의 코드에서, GetCurFrameAttackInfo에 공격이 없는 경우 기본 데미지를 반환하게 한다면 예외처리 블록이 필요 없어진다. (특수 사례 패턴)

 

이는 null을 반환하는 함수의 경우에도 쓰일 수 있다. null 대신 empty 콜렉션이나 특수 사례 객체를 반환하자. 그러면 호출자가 null을 확인할 필요가 없어지고 nullexception위험부담도 없어진다. 

 

그리고 null은 매개변수로 주지 마라. null 넘기는건 호출되는 함수 입장에서도 처리하기 어렵다. 애초에 인수에 null을 주는게 정상인가 고민해봐야 하며 그냥 넘기지 말라면 넘기지 마셈.