토비의 스프링 - 3장
이번 장에서는 템플릿에 대해 알아보도록 하겠습니다.
이번에는 변하지 않는 코드와 변하는 코드가 같이 섞여 있는 코드 묶음이 자주 반복 되는 상황에서 쓸 수 있는 템플릿 / 콜백 기법에 대한 이야기를 위주로 진행하려고 합니다.
코드를 작성하다 보면 자주 생기는 상황 중에 특정 코드 영역은 변경이 되지 않고 특정 영역은 기능마다 다른 코드 묶음이 생길 수 있습니다.
책에서는 주로 DB 연결 후 쿼리를 날리고 DB 연결을 종료하는 코드 묶음에 대해서 이야기를 합니다.
그런데 이 이야기를 하기전에 제일 먼저 중요하게 봐야 하는 부분은 코드 묶음에서 변경이 일어나는 부분과 변경이 일어나지 않는 영역 을 구분 할 수 있는 시각과 판단이 필요합니다.
책에서 설명하는 DB 를 예시로 들면 이 코드 묶음은 DB에 쿼리를 날린다. 라는 로직이 주를 이루게 됩니다. 그리고 이런 코드가 굉장히 많이 있다고 했을 때 변경이 일어나는 부분과 변경이 일어나지 않는 부분을 구분한다면 DB에 연결하는 코드와 쿼리를 날리고 난 뒤 DB의 연결을 끊는 코드가 변하지 않는 영역의 코드라고 할 수 있습니다. 왜냐하면 쿼리 자체는 매번 바뀔 수 있지만 DB에 연결하고 끊는 코드는 동일합니다. 그게 DB에 쿼리를 날리기 위한 전제에 해당하는 코드이기 떄문입니다.
다른 예시를 생각 해보면 [파일에 적힌 정수 값을 모두 더하는 기능]과 [파일에 적힌 텍스트의 갯수를 알아보는 기능]을 만든다고 하겠습니다.
여기서는 파일을 불러오고 그 파일의 내용을 읽은 뒤 파일을 닫아주는 (파일에 대한 커넥션을 끊어주는) 코드가 전제에 해당하게 됩니다.
이제 어떤 코드 영역이 변하는 부분이고 변하지 않는 부분인지 파악이 되었다면 그 방법에 대해서 고민해볼 시간입니다.
먼저 변하는 부분에 대한 코드만 분리해 변하지 않는 코드에서 이를 호출 하는 방식으로 진행합니다.
여기서는 전략 패턴을 사용하도록 하겠습니다.
전략 패턴이란 디자인 패턴에도 나와있는 패턴으로 OCP (개방 패쇄의 원칙) 을 위반하지 않으면서 사용 가능한 패턴입니다.
아래는 예시 입니다. (원본, 코드 있어요!)
이동 수단, 버스와 기차가 있습니다. 그런데 이 버스와 기차에 대한 이동 방법에는 선로를 따라 움직이는 방식과 도로를 따라 움직이는 방식이 있고, 원래라면 버스는 도로를 통해서만 이동하고 기차는 선로를 따라서만 이동하지만 세상의 발전은 무궁무진해서 버스가 선로를 통해서도 이동할 수 있게 되었습니다.
이런 상황에서 기존의 원래 방식인 버스의 이동 방식에 대한 코드만 변경한다면 이는 확장에 대해 열려 있으면서 수정에는 닫혀야 하는 OCP 에 위배됩니다.
전략 패턴을 사용할 때는 다음과 같습니다.
- 전략(이동 수단)을 생성 합니다.
- 전략(이동 수단)을 사용할 대상(버스와 기차)을 생성합니다.
- 전략(이동 수단)을 사용하는 대상(버스와 기차을 Client 를 구현합니다.
전략은 인터페이스로 만들어 이를 구현한 클래스를 만듭니다.
전략을 사용할 대상은 이러한 전략을 주입받아 호출하는 코드를 작성합니다.
마지막으로 클라이언트에서는 전략을 사용할 대상을 생성해 전략을 주입해줍니다.
이렇게 코드를 작성해 사용하다보면 또 문제점이 생기게 됩니다.
하지만 바로 문제에 대해서 바로 해결하지 말고 이런 상황이 2~3번이 반복된다면 그때가 코드를 개선할 시점이라고 생각하고 있습니다. 저희는 결국 프로그램을 만든다는 최종적인 목적이 있기 때문에 가장 최우선 해야 하는 프로그램을 만든다는 목적보다 코드의 개선만 하고 있으면 그 목적이 흐려지기 때문입니다. 그럼에도 지금 코드를 개선 하는 작업이 내일, 혹은 런칭 전의 마감 시간에 여유를 만들어 줄 수 있다면 개선하는게 좋다고는 생각합니다 ㅎㅎ
그런 의미에서 지금 생기는 문제는 전체적으로 시간적 여유를 만들어 주는 방법이기 때문에 설명하겠습니다.
이런 전략 패턴의 문제점 중 하나는 전략에 따라 클래스 파일의 개수가 늘어난다는 문제점이 있습니다. 상황에 따라서는 파일로 만드는 것이 더 나을 수도 있지만 위의 DB 예시를 들면 유저를 DB에 저장하는 전략, 유저를 삭제하는 전략, 유저를 조회하는 전략 등 유저와 관련된 전략이기 때문에 파일로 만들기 보단 로컬 클래스로 독립적인 파일이 아닌 전략을 실행하는 UserDao 클래스 안에 클래스를 만드는 방식도 사용할 수 있습니다.
이런 내부 클래스도 사용되는 목적에 따라 나뉘고 사용되는 범위에 따라 또 나뉘게 됩니다.
- static class (외부에서도 사용 할 수 있는 클래스)
- inner class (내부에서만 사용 할 수 있는 클래스)
- 멤버 변수처럼 객체 내에서 사용 할 수 있는 member inner class
- 메서드 레벨에서 정의되는 local inner class
- 이름을 갖지 않는 anonymous inner class
더 자세한 내용은 검색을 해보시기 바랍니다.
저희는 이름을 갖지 않는 익명 내부 클래스를 사용하도록 하겠습니다.
여기서 템플릿과 패턴이라는 기법이 나옵니다. 하지만 이는 지금까지 알게 된 내용에서 이름만 정의해준겁니다.
템플릿은 위의 내용 중 변하지 않는 부분이고 콜백은 전략 패턴의 전략 부분을 inner class 로 구현한 부분입니다.
마지막으로 이런 내용을 잘 활용해 만들어진 스프링의 JdbcTemplate 이 있습니다.
사용 방법에 대해서는 자세히 기술하지 않습니다.