본문 바로가기

.Net Technology/.NET TDD

(11) TDD를 위한 객체지향 - 하나의 기능 (Single Responsibility)

첫번째 디자인 규칙은 객체에서 수많은 기능이 아닌 단, 하나의 기능만 포함시키는 것이다. 쉽게 그림으로 이해해보도록 하자. 만약 클래스가 [그림1]처럼 만들어졌다면 어떨까? 
 
[그림1] 맥가이버 칼
 
이 도구를 사용하는데 있어서 큰 문제는 먼저 어디에 어떤 도구(기능)가 있는지 찾기 어렵다는 것이다. 필자 또한 필자의 클래스를 돌아보면 수많은 기능들이 포함되어지는 경우가 많다. 예를 들어 게시판의 글을 가져옴과 동시에 사용자의 정보들도 가져온다고 생각해보자. 이때 만약 게시글의 리파지토리와 사용자 리파지토리에서 각각의 정보를 가지고 올 수 있다면 위의 역할을 충족시키지만 하나의 클래스에서 작성되어진다면 이 원칙을 벗어나게 된다. TDD에서 유닛의 개념과 이 원칙의 개념은 상당히 비슷하다.
 
아주 심플한 예제로 아래 코드에서 잘못된 예를 찾아보자. 
 
class Customer
{
    public void Add()
    {
        try
        {
            //DB 접근코드
        }
        catch (Exception ex)
        {
            System.IO.File.WriteAllText(@"c:\Error.txt", ex.ToString());
        }
    }
}
 
 
위의 클래스에서 잘못된 부분은 명확하다. 이 클래스의 이름은 Customer이므로 고객과 관련된 정보들에 대한 기능만 가지고 있어야 한다. 하지만 만약 에러가 있을 경우에 catch 구문에서 로그를 작성하는 기능을 포함하게 된다. 아래 코드는 제대로 구분한 예를 보여준다. 
 
class FileLogger
{
    public void Handle(string error)
    {
        System.IO.File.WriteAllText(@"c:\Error.txt", error);
    }
}

class Customer
{
    private FileLogger obj = new FileLogger();
    public void Add()
    {
        try
        {
            // DB 접근코드
        }
        catch (Exception ex)
        {
            obj.Handle(ex.ToString());
        }
    }
}
 
위의 코드에서 예제를 위해서 try catch를 사용하였지만 좀 더 엄격하게 말하면 이 기능 또한 Customer 클래스에 있어야 하는 기능이 아니다. 뿐만 아니라 FileLogger를 직접 참조함으로써 의존성에 있어서도 여전히 강한 커플링을 유지하고 있다. 이런 내용들은 아래에서 다른 원칙을 소개하면서 다시 다루어 보겠다.