네 개의 영역 '표현', '응용', '도메인', '인프라스트럭쳐' 는 아키텍처를 설계할 때 출현하는 전형적인 네가지 영역이다. 표현 영역(또는 UI 영역)은 사용자의 요청을 받아 응용 영역에 전달하고 응용 영역의 처리 결과를 다시 보여주는 역할을 한다. 웹 애플리케이션을 개발할때 많이 사용하는 스프링 MVC 프레임워크가 표현 영역을 위한 기술에 해당한다. 웹 애플리케이션에서 표현 영역의 사용자는 웹 브라우저를 사용하는 사람일 수도 있고, REST API를 호출하는 외부 시스템일 수도 있다. 웹 애플리케이션의 표현 영역은 HTTP 요청을 응용 영역이 필요로 하는 형식으로 변환해서 응용 영역에 전달하고 응용 영역의 응답을 HTTP 응답으로 변환하여 전송한다. 표현 영역을 통해 사용자의 요청을 전달받는 응용 ..
엔티티와 밸류 도출한 모델은 크게 엔티티(Entity)와 밸류(Value)로 구분할 수 있다. 앞서 요구사항 분석 과정에서 만든 모델은 엔티티도 존재하고 밸류도 존재한다. 앤티티와 밸류를 제대로 구분해야 도메인을 올바르게 설계하고 구현할 수 있기 때문에 이 둘의 차이를 명확하게 이해하는 것은 도메인을 구현하는 데 있어 중요하다. 엔티티 엔티티는 식별자를 가진다. 식별자는 엔티티 객체마다 고유해서 각 엔티티는 서로 다른 식별자를 갖는다. 주문에서 배송지 주소가 바뀌거나 상태가 바뀌더라도 주문번호(식별자)가 바뀌지 않는 것처럼 엔티티의 식별자는 바뀌지 않는다. 엔티티를 생성하고 속성을 바꾸고 삭제할 떄까지 식별자는 유지된다. 엔티티의 식별자는 바뀌지 않고 고유하기 때문에 두 엔티티 객체의 식별자가 같으면 두..
도메인 모델 도메인 모델은 특정 도메인을 개념적으로 표현한 것이다. 예시로 '주문 도메인'을 보자. 주문을 하기위해 상품을 몇 개 살지 선택하고 배송지를 입력한다. 선택한 상품 가격을 이용해서 총 지불 금액을 계산하고, 금액 지불을 위한 결제 수단을 선택한다. 주문한 뒤에도 배송 전이면 배송지 주소를 변경하거나 주문을 취소할 수 있다. 위 그림은 객체를 이용한 도메인 모델이다. 도메인을 이해하려면 도메인이 제공하는 기능과 도메인의 주요 데이터 구성을 파악해야 하는데, 이런 면에서 기능과 데이터를 함께 보여주는 객체 모델은 도메인을 모델링하기에 적합하다. 도메인 모델을 객체로만 모델링할 수 있는 것은 아니다. 상태 다이어그램을 이용해서 주문의 상태 전이를 모델링하고 있다. 이 다이어그램을 보면 상품 준비 ..
도메인이란? '온라인 서점'을 예시로 들어보자. 온라인 서점에서 책에 관련된 많은 기능들을 제공한다. 개발자 입장에서 '온라인 서점'은 구현해야 할 소프트웨어의 대상이 된다. 온라인 서점 소프트웨어는 온라인으로 책을 판매하는 데 필요한 상품 조회, 구매, 결제, 배송 추적 등의 기능을 제공해야한다. 이때 '온라인 서점'은 소프트웨어로 해결하고자 하는 문제 영역에 해당한다. 한 도메인은 다시 하위 도메인으로 나눌 수 있다. 온라인 서점'의 하위 도메인 : 카탈로그, 회원, 결제, 배송, 정산 등 각 하위 도메인은 각자의 서비스에 맞는 기능을 제공한다. 카탈로그 하위 도메인은 고객에게 구매할 수 있는 상품 목록을 제공하고, 주문 하위 도메인은 고객의 주문을 처리한다. 한 하위 도메인은 다른 하위 도메인과 연..
SpringBoot + Maven 프로젝트 생성 초기 셋팅 - 의존성 ▶ pom.xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-devtools runtime true com.h2database h2 runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.restdocs spring-restdocs-mockmvc test 문서 작성을 위한 API 개발 ▶ UserController package com.maven.restapidocs.controll..
문제 대문자와 소문자가 같이 존재하는 문자열을 입력받는다. 문자열에서 대문자는 소문자로, 소문자는 대문자로 변환하여 결과를 출력한다. 풀이 1. String 객체를 for문 사용해서 변환하기 import java.util.Scanner; public class LC2_대소문자_변환 { static String target; public static void main(String[] args) { // write your code here LC2_대소문자_변환 main = new LC2_대소문자_변환(); main.solution(); } public void solution() { input(); StringBuilder result = new StringBuilder(); // CASE 1 for (..
들어가며 API를 개발할때 API별로 파라미터 validation 체크를 해야한다. validation 체크를 하는 방법은 여러가지로 많겠지만, Spring Boot Starter Validation을 사용해서 여러가지 방법을 적용해보자. 의존성 추가 https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation pom.xml org.springframework.boot spring-boot-starter-validation build.gradle implementation 'org.springframework.boot:spring-boot-starter-validation' // validation 예제..
직렬화 프록시 패턴(serialization proxy pattern) 바깥 클래스의 논리적 상태를 정밀하게 표현하는 중첩 클래스를 설계하여 private static으로 선언한다. 이 중첩 클래스가 바로 바깥 클래스의 직렬화 프록시다. 중첩 클래스의 생성자는 단 하나여야 하며, 바깥 클래스를 매개변수로 받아야한다. 이 생성자는 단순히 인수로 넘어온 인스턴스의 데이터를 복사한다. 일관성 검사나 방어적 복사도 필요없다. 설계상 직렬화 프록시의 기본 직렬화 형태는 바깥 클래스의 직렬화 형태로 쓰기에 이상적이다. 그리고 바깥 클래스와 직렬화 프록시 모두 Serializable을 구현한다고 선언해야한다. Period 클래스용 직렬화 프록시 package com.java.effective.item90; impor..
싱글턴 패턴의 직렬화 이 클래스는 바깥에서 생성자를 호출하지 못하게 막는 방식으로, 인스턴스가 오직 하나만 만들어짐을 보장했다. public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } public void leaveTheBuilding() { ... } } 이 클래스는 선언에 implements Serializable을 추가하는 순간 더이상 싱글턴이 아니게된다. 기본 직렬화를 쓰지 않더라도, 그리고 명시적인 readObject를 제공하더라도 이 클래스가 초기화될 때 만들어진 인스턴스와는 별개인 인스턴스를 반환하게된다. readResolve 기능 readResolve 기능을 이용하면 readObjec..
방어적 복사를 사용하는 불변 클래스 아이템 50에서 불변인 날짜 범위 클래스를 만드는데 가변인 Date 필드를 사용했었다. 그래서 불벼식을 지키고 불변을 유지하기 위해 생성자와 접근자에서 Date 객체를 방어적으로 복사하느라 코드가 길어졌다. https://devfunny.tistory.com/613?category=895441 [교재 EffectiveJava] 아이템 50. 적시에 방어적 복사본을 만들라 불변식 깨뜨리기 자바는 메모리 충돌 오류에서 안전한 언어다. 자바로 작성한 클래스는 시스템의 다른 부분에서 무슨 짓을 하든 그 불변식이 지켜진다. 하지만 아무리 자바라고 해도 다른 클래 devfunny.tistory.com 방어적 복사를 사용하는 불변 클래스 package com.java.effecti..
커스텀 직렬화 형태를 고려 Serializable을 구현하고 기본 직렬화 형태를 사용한다면 다음 릴리스 때 버리려한 현재의 구현에 영원히 발이 묶이게된다. 기본 직렬화 형태를 버릴 수 없게된다. 실제로도 BigInteger 같은 일부 자바 클래스가 이 문제에 시달리고있다. 먼저 고민해보고 괜찮다고 판단될 때만 기본 직렬화 형태를 사용하라. 기본 직렬화 형태는 유연성, 성능, 정확성 측면에서 신중히 고민한 후 합당할 때만 사용해야한다. 일반적으로 직접 설계하더라도 기본 직렬화 형태와 거의 같은 결과가 나올 경우에만 기본 형태를 써야한다. 기본 직렬화 형태 객체의 물리적 표현과 논리적 내용이 같다면 기본 직렬화 형태라도 무방하다. 기본 직렬화 형태에 적합한 후보 public class Name impleme..
Serializable 어떤 클래스의 인스턴스를 직렬화할 수 있게 하려면 클래스 선언에 implements Serializable만 덧붙히면 된다. 너무 쉽게 적용할 수 있는것에 비해, 직렬화는 아주 값비싼 일이다. Serializable을 구현하면 릴리스한 뒤에는 수정하기 어렵다. 클래스가 Serializable을 구현하면 직렬화된 바이트 스트림 인코딩(직렬화 형태)도 하나의 공개 API가 된다. 그래서 이 클래스가 널리 퍼진다면 그 직렬화 형태도 영원히 지원해야한다. 커스텀 직렬화 형태를 설계하지 않고 자바의 기본 방식을 사용하면 직렬화 형태는 최소 적용 당시 클래스의 내부 구현 방식에 영원히 묶여버린다. 기본 직렬화 형태에서는 클래스의 private, package-private 인스턴스 필드들마저..