본문 바로가기

Back-End/토비의 스프링3

(17)
9.3. 스프링 웹 애플리케이션 아키텍처에 관하여 들어가기 전 스프링 프로젝트를 하면, 일단 기본적으로 생각없이 Controller, Service, Repository 3단계로 나누어 코딩을 한다. 어떤 역할로 나눈지는 이해하고 있었지만, 어떻게 서로 결합도를 낮추고, 어떠한 방식으로 아키텍처를 정하는지에 대한 이해도는 거의 없었다. 그래서 토비의 스프링에 있는 9.3. 애플리케이션 아키텍처를 읽게 되었다. 계층형 아키텍처 우리는 스프링을 공부하면서 관심, 책임, 성격, 변하는 이유와 방식이 서로 다른것들을 분리함으로써 결합도는 낮추고 응집도는 높이는 코드를 만들어 왔다. 웹 애플리케이션에서도 이처럼 성격이 다른 것은 아키텍처 레벨에서 분리해주는 것이 좋다. 만약, 분리하지 않고 JSP 처럼 HTML, JDBC 코드가 함께 존재한다면? 유지보수는 거의..
토비의 스프링 7장(1) - SQL과 DAO의 분리 4,5,6장을 살펴보면서 스프링의 3대 핵심 기술인 IoC/DI, 서비스 추상화, AOP에 대해 간단히 살펴봤다. 스프링이 자신의 핵심 기술을 다양한 분야에 적용했듯이, 스프링을 사용하는 개발자도 스프링이 제공하는 3가지 기술을 필요에 따라 스스로 응용할 수 있어야 한다. SQL과 DAO의 분리UerDao에서 반복적인 JDBC 작업 흐름을 템플릿을 이용해 제거했다. 그리고 다른 부분과의 연결을 인터페이스를 통해 DI 되기 때문에 다이나믹하게 관계를 설정할 수 있다. 즉, DAO에는 깔끔하게 다듬어진 순수한 데이터 액세스 코드만 남게 했다. 하지만, DB테이블과 필드정보를 고스란히 담고 있는 SQL 문장이 남아있다. DB의 테이블, 필드 이름과 SQL 문장의 변경으로 UserDAO를 수정하게 될 수도 있다..
토비의 스프링 6장(3) - 다이나믹 프록시와 팩토리 빈 프록시 패턴 / 데코레이터 패턴6-1장에서 트랜잭션 코드와 비즈니스 코드를 분리했었다.( http://happyer16.tistory.com/entry/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-6%EC%9E%A51-AOP-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EC%BD%94%EB%93%9C%EC%9D%98-%EB%B6%84%EB%A6%AC ) 위의 구조를 다시 그린 후에 프록시에 대한 개념을 살펴보면 이해하기 편하다. 프록시와 타킷아래 그림은 위의 구조와 같은 것이다. 프록시(Proxy) : 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 대리자 ( UserServiceTx )타..
토비의 스프링 6장(2) - 고립된 단위 테스트 고립된 단위 테스트단위 테스트는 당연히 작은 단위어야 한다. 쉽고, 빠르고, 명확하기 때문이다. 복잡한 의존관계 속의 테스트 UserService 테스트를 위해 필요한 구조DB와 데이터를 주고 받기 위한 UserDaoJdbc트랜잭션 처리를 위한 Transaction Manager메일 전송을 위한 MailSender문제점간단한 UserService 테스트를 위해서는 DB, Transaction 등 의존 관계를 명시해줘야 한다. 테스트하기 복잡하고, 환경에 영향을 받는다. 테스트 대상 오브젝트 고립시키기 단위테스트 vs 통합테스트둘 중에 어떤걸 써야할까?항상 단위 테스트를 먼저 고려한다외부 리스소를 사용해야 하는경우만 통합 테스트. 외부와의 의존관계는 모두 차단하고 필요에 따라 목 오브젝트 등의 테스트 대역..
토비의 스프링 6장(1) - AOP 트랜잭션 코드의 분리 지난 포스팅http://happyer16.tistory.com/entry/5%EC%9E%A52-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%B6%94%EC%83%81%ED%99%94?category=692836에서 UserService에서 트랜잭션이 필요했다. 스프링에서 제공해주는 인터페이스를 썼음에도 불구하고 비즈니스 로직에 길고 더러운 코드가 있어 찝찝함을 감출 수 없다. 개요등장배경스프링이 도입하려는 이유장점 ( 예제로 선언적 트랜잭션 기능을 살펴보자 )메소드 분리[ 리팩토링 전 - 서로 정보도 주고 받지 않고 관련이 없는 트랜잭션 코드 / 비즈니스 코드가 섞여 있다. ]..
토비의 스프링 - 4장. 예외 토비의 스프링 - 4장. 예외이번 포스팅에서는 스프링의 데이터 엑세스 기능에 담겨있는 예외처리와 관련된 접근 방법에 대해 알아본다. 예외의 종류와 특징Errorjava.lang.Error 클래스의 서브클래스이다. 주로 자바 VM에서 발생하는 에러이기 때문에 신경쓰지 않아도 되고 애플리케이션 코드에서 잡으려고 해서도 안된다. ( OutOfMemoryError, ThreadDeath ) Exception과 체크 예외java.lang.Exception은 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용한다. RuntimeException : catch, throw를 강제하지 않음 ( ex : NullPointerException )체크 예외 : RuntimeException을 상속받지 않은 나머지..
5-4장. 메일 서비스 추상화 메일 서비스 추상화고객으로부터 사용자 레벨 관리에 관한 새로운 요청사항이 들어온 경우라면?User에 email 추가upgradeLevel()에 메일 발송 기능 추가JavaMail이 포함된 코드의 테스트테스트 코드를 돌리면 SMTP host에 연결할 수 없다고 에러가 날 것이다. 그렇다면 아래 처럼 테스트 서버를 구축하는건 어떨까? UserService ---> JavaMail ---> 메일 서버 ---> 테스트용 메일 서버 매번 메일이 발송되는건 바람직하지 못하다. 메일 발송은 부하가 큰 작업일 뿐 아니라, JavaMail은 검증된 라이브러리이다. 따라서 JavaMail API를 통해 요청이 들어간다는 보장만 있다면 굳이 테스트할 때마다 JavaMail을 구동시킬 필요가 없다. UserService --..
5-3장. 서비스 추상화와 단일 책임 원칙 서비스 추상화스프링의 트랜잭션 서비스 추상화 기법을 이용해 다양한 트랜잭션 기술을 일관된 방식으로 제어할 수 있게 됐다. 수직, 수평 계층 구조와 의존관계추상화 기법을 통해 특정 기술환경에 종속되지 않는 코드르 만들었다. UserDao나 UserService는 각각 담당하는 코드의 기능적인 관심에 따라 분리되었다. 같은 애플리케이션 로직을 담은 코드지만 내용에 따라 분리했다. 같은 계층에서 수평적인 분리라고 할 수 잇다. 트랜잭션 추상화는 이와 좀 다르다. 애플리케이션 코드와 그 하위에서 동작하는 로우레벨의 트랜잭션 기술이라는 다른 계층의 특성을 갖는 코드를 분리한 것이다. UserService : 사용자 관리에 대한 비즈니스 로직UserDao : 데이터를 어떻게 가져오고 등록할 것인가에 대한 데이터 엑..
5-2장. 스프링 - 트랜잭션 서비스 추상화 사용자 레벨 업그레이드 코드를 완성했다. 하지만, 레벨 업그레이드 작업 중 에러가 발생하여 일부 유저만 수정되었다면 어떻게 처리해야할까? 고객들의 불만을 일으키지 않기 위해, 원상태로 돌려놓아야 한다. 즉, upgradeLevels()를 하나의 작업단위인 트랜잭션을 적용해야 한다. JDBC 트랜잭션의 트랜잭션 경계설정setAutoCommit(false)로 트랜잭션의 시작을 선언하고 commit() 또는 rollback()으로 트랜잭션을 종료하는 작업을 트랜잭션 경계설정이라 한다.Connection c = dataSource.getConnection(); c.setAutoCommit(false); // 트랜잭션 시작 try { // 트랜잭션 하나의 작업 PreparedStatement st1 = c.pre..
5장. 스프링 - 서비스 추상화(사용자 레벨 관리 기능 추가) 서비스 추상화예제를 살펴보면서 스프링이 어떻게 성격이 비슷한 여러 기술을 추상화하고 이를 일관된 방법으로 사용할 수 있도록 해주는지 살펴보자. ( 서비스 추상화 ) 예제 : 사용자의 활동내역을 참고해서 사용자 레벨 관리 기능 추가1. Level Enum 사용하기Level enum 만들기장점 1 : int 타입으로 레벨 상수를 사용하는 것보다 의미 있는 상수로 사용할 수 있음 ( int형 setLevel(10000)과 같은 버그 코드는 컴파일 에러가 나지 않음 ) 장점 2 : varchar 타입보다 DB 용량을 많이 차지하지 않는다. public enum Level { BASIC(1), SILVER(2), GOLD(3); private final int value; Level(int value) { thi..