티스토리 뷰

Etc.

객체 지향 설계 5원칙 [SOLID] - SRP란?

마로그래머 2022. 2. 18. 20:08
반응형

객체 지향 설계 5원칙 - SOLID

SOLID란?

SOLID란 용어는 로버트 C.마틴(aka Uncle Bob)가 객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙으로 제시한 원칙을 마이클 페더스가 앞글자만 따서 만들어진 용어이며. 다섯가지 원칙은 다음과 같다.

  • SRP(Single Reponsibility Principle) : 단일 책임 원칙
  • OCP(Open Closed Principle) : 개방 폐쇄 원칙
  • LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
  • ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
  • DIP(Dependency Inversion Principle) : 의존 역전 원칙

SOLID는 기존의 높은 응집도, 낮은 결합도를 위한 프로그래밍 원칙을 객체 지향의 관점에서 재정립한 것이다. 객체지향의 기본이라 할 수 있는 이 원칙은 어떤 것인지 알 수는 있어도 직접 체화하기에는 어마어마한 시간이 걸리는 원칙이며 독립적인 원칙이 아니라 다른 개념들과 이어져있는 원칙이다. 그렇기에 하나하나 곱씹어보기위해 정리해보려고 한다.



SRP(Single Responsiblity Principle) - 단일 책임 원칙

용어의 뜻

객체 지향 설계의 5원칙인 SOLID 중 S를 맡고 있는 것이 SRP(Single Responsiblity Principle)이다. 한글로 번역하면 단일 책임 원칙 이라고 한다. 이 원칙은 로버트 C.마틴(aka 엉클 밥)이 그의 저서 Principles of Object Oriented Design에서 처음 사용하였다. 그는 Tom Demarco’s의 아이디어인 응집력으로부터 이 개념을 떠올렸다고 한다.

SRP란?

"어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다." - 로버트 C. 마틴

SRP를 대표하는 로버트 C.마틴의 말이다.이 말을 좀 더 풀어서 생각해보면 클래스의 역할(책임)을 분리하고 하나의 클래스에 하나의 책임만 가지게 하여야 한다라고 생각 할 수도 있을 것 같다.

JAVA 코드로 예를 들어보자

public class Service{

    private DataSource dataSource;

    public void setDataSource(dataSource){
        this.dataSource = dataSource;
    }


    //연결한 데이터베이스의 내용을 가져와 어떤 작업을 수행하는 메소드
    public void doService{
        TransactionSynchronizationManager.initSynchronizer();
        Connection c = DataSourceUtiols.getConnection(dataSource);
        c.setAutoComit(false);
        //트랜잭션을 사용하기 위한 세팅

        try{
            //수행 해야 할 비즈니스 로직
        }catch{
            //예외
        }

        //대충 트랜잭션 정리 코드
    }
}

여기 이 Service라는 클래스의 doService메소드를 한 번 보자.

DB의 내용을 가지고 비즈니스로직을 처리하는 역할을 하고있다.(dataSource는 미리 주입받았다고 가정하자)

이 클래스는 얼핏보면 DB에 연결하고 연결한 데이터베이스의 내용을 가지고 작업을 하기 때문에 단일 책임 원칙을 잘 지킨 것 같이 보인다.

하지만 JDBC의 API인 현재 트랜잭션을 글로벌 트랜잭션인 JTX로 바꿔달라는 요청이 있을 경우에는 아래와 같이 코드를 바꿔야 한다.

public class Service{

    private DataSource dataSource;

    public void setDataSource(dataSource){
        this.dataSource = dataSource;
    }


    //연결한 데이터베이스의 내용을 가져와 어떤 작업을 수행하는 메소드
    public void doService{
        InitalContext ctx = new InitialContext();
        UserTransaction tx = (UserTransaction)ctx.lookup(USER_TX_JNDI_NAME);
        tx.begin();
        Connection conn = dataSource.getConnection();
        //트랜잭션을 사용하기 위한 세팅

        try{
            //수행 해야 할 비즈니스 로직
        }catch{
            //예외
        }

        //대충 트랜잭션 정리 코드
    }
}

간단하다. 다른 코드들은 다 내버려두고 트랜잭션을 사용하기 위한 세팅만 바꾸면 된다.

그런데 나중에는 하이버네이트를 이용해서 트랜잭션 관리를 해달라는 요청이 들어온다. 그럼 그 때는 Connection이 아닌 Session을 이용하여 독자적인 API를 사용해야 할 것이다.

이 과정에서 다시 한 번 상기해보자.


이 클래스는 비즈니스 로직을 수행해야 하는 클래스이다.



그런데 정작 트랜잭션 관리라는 다른 이유 때문에 원래의 코드는 전혀 변경하지 않은 채로 계속 클래스를 수정해야만 하는 것이다!!

자신의 책임이 아닌 다른 책임 때문에 클래스를 수정하는 이러한 경우는 SRP원칙에 위배되어버린다.

이럴 때는 추상화와 DI방식을 이용해서 트랜잭션 관리라는 책임을 외부에서 조종할 수 있도록 하여 한 클래스에서는 하나의 책임만 지도록 함으로써 SRP 원칙을 지킬 수 있을 것이다.

이렇게 SRP를 지켰을 때의 장점은 다음과 같다.

  • 어떤 변경이 필요할 때 수정 대상이 명확해진다.
  • 특정 기술에 종속되지 않을 수 있다.

이를 통해 작업량이 적어지게 되고 실수도 적어지면 유지보수가 훨씬 잘 될 것이다. 아주 기본적인 것 같으면서 대단한 원칙인 것 같다.




[ 참고도서 ]

<<스프링 입문을 위한 자바 객체 지향의 원리와 이해>> - 지은이 김종민

<<토비의 스프링 3.1>> - 지은이 이일민

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함