요청(파라미터)는 DTO의 필요성을 명확히 알겠음. 그러면 반환해줄때의 객체의 형태는 DTO여야 하는가 아니면 VO여야 하는가…
DTO, VO, Domain 객체 구분해서 사용하기를 원함.
DTO가 비지니스 종속적여야 하는 이유. -> 공통된 기능을 가졌다고 해서 다른 비즈니스를 공통된 DTO 사용했을 경우에 추후 다른 속성을 사용하는 비즈니스가 들어왔을경우 이 DTO를 분리시켜야함. 단순히 DTO를 분리시킨다는 관점에서는 큰 문제는 아니지만. 그 기능이 인터페이스로 규격화 되어있을 경우 DTO가 특정항공사는 다른 이슈가 생기기 때문에 이는 인터페이스화 시킬수 없는 문제가 발생.
DTO와 Domain이 구분되어져야 하는 이유. -> 해당 객체가 생성되는 근본적인 이유가 다르기 때문이다. DTO가 가져야할 특성이 있는데 그 중 주된것들은.fS 첫번째 validation 체크이다. DTO는 데이터를 주고받을 때 사용하는 목적으로 만들어진 객체이기 때문에. validation 체크가 기본적으로 통상 들어간다. Domain 객체와 이러한 DTO를 같이 사용하게 되면 validation 체크를 DTO 자체적으로 구현하지 못하고 별도 서비스단 등에서 제어해야하는 문제가 발생한다.
두번째. 마샬링, 파싱 등의 작업을 할때 조건을 걸어야 하기때문. 조건은 결국 비지니스 종속적일 수밖에 없고 이를 domain 객체에 넣어둘수는 없다. domain은 모두 공통적으로 사용해야하는 객체이기 때문에 어떤 한 특정 비지스에 종속적인 객체를 만드는 것은 좋지 않은 패턴이다.
세번쨰. DTO 를 디자인하는 것과 도메인 객체를 디자인하는 근본적인 목적이 다르다. DTO 는 딱 주고 받아야할 데이터만 최대한 간단하게 주고받고록 만들어야하지만 도메인 개체는 객체 모델링 관점에서 실세상을 투영되도록 각 도메인 객체들끼리 관계를 맺어주며 구현해야하기 때문에 설계되는 모양이 근본적으로 다를수 밖에 없다.
Map<> 은 언제 사용되어야 할까. -> Map은 type safe 하지 않기 때문에 일반적으로는 DTO를 생성하고 해당 객체를 Map을 대신 사용하는 것을 추천한다. 그러나 만약 Map을 사용하는 곳의 Scope가 한 함수의 내부적으로만 사용하고 해당 함수를 사용하는 다른 클라이언트들에게 이 Map 객체를 전달할 일이 없다면 해당 타입을 다른 클라이언트가 지속 사용하는 현상이 일어나지 않음으로 구조가 심플하고, 스코프가 한 함수 내부라면 사용하는것이 좋을듯 하다. Java POJO 객체를 계속 만들어 나가는것도 결국에는 양이 엄청나기 때문 이정도로 사이즈가 작고 클라이언트에게 큰 영향이 없다면 그냥 Collection Framework를 사용하는 것도 좋을 것 같다.
innerClass 를 활용한 DTO, Domain 구분 무엇이 DTO이고 무엇이 Domain 일까
다른패키지에서 같은 이름으로 만들수는있어도 이를 한 클래스에서 같이 사용할 수는 없다.
Domain.DTO -> 이미 장점을 알고있는 구조. 각 비지니스에 맞추어서 POJO 객체를 쓸 수 있다. Spring Validation 가능 위에서도 이미 언급되고 있음. Flat Design
Boundary.DTO, Package.DTO -> innerClass 로 구현 -> 영역의 구분에 대한 장점 패키지로 하는것 보다 더 제한적 -> 이름이 중복될수 없음. -> 특정 비지니스에 종속되어 있는 DTO 임을 명시 가능.
DTO.Domain -> 불가능한 구조 Domain 이라함은 공용으로 사용하는 POJO 객체 인데. 이것이 특정 비지니스에 맞추어져 있는 DTO 안에 들어갈 수 없음.
Domain.DTO.DTO -> 가능은 함 그러나 권장하지 않는 구조, Domain.DTO 에 들어가는 조건 중 하나는 Domain과 관련된 DTO가 들어가야함.
Domain.DTO 구조로 설계했는데 Domain에 마땅히 들어갈 데이터가 없다면 Boundary.DTO 형태로 변경을 고려해야함.
Domain이 될수있는 조건은 프로젝트 모든 곳에서 사용할 수 있는 구조인가를 고려해야함. 그리고 그런 데이터인지. 그렇기때문에 일반적으로 데이터베이스 엔티티 구조를 따른다
DAO는 결국 DB와 DOMAIN을 연결하는 DTO의 일종이다. 보통 DTO는 뷰와 DOMAIN을 연결하는 요소로 언급함. 내가볼때는 둘다 DTO로 봐도되지 않나.. 용어의 정의를 내가 내리지 않았으니 이 둘을 구분은 해야할듯 DTO는 View - Domain, DAO는 Domain - DB
jpa를 활용하지 않고 최대한 의존성이 적은 쿼리를 짜는 방법 -> 결국 동적쿼리를 써야함으로 DB 캐싱은 사용할 수 없다 성능은 떨어짐 이슈. 그리고 쿼리가 최대한 의존적이지 않ㄱ ㅔ짜기 때문에 대부분 분리된 방식으로 짬 -> 트랜잭션 관리 가 더커짐.
테이블이 3개를 기준으로 쿼리를 가져와야 한다면. 해당 테이블 기준으로 Domain 객체 3개를 우선 만들고 이들을 합쳐 DAO를 만든다 그래서 파라미터로 들어가야할 부분에는 이 값들을 넣어준다. 쿼리는 가능한 한도 내에서 동적쿼리로 작성
내가아까 푸쉬를 했나??
set하는 코드보다 builder 하는 코드가 좋은이유 가독성 측면에서
10000줄짜리 한 스코프의 코드가 있다고 하자. 이거 자체가 굉장히 억지스러운 일이지만. 만약 1번째 줄에 선언된 변수가 10000째에서 사용된다고 하면. 그 사이의 작업이 어떤것이 있었는지 다 확인해야한다. 그런데 만약 10000번째에 반환시키는 변수를 빌더로 사용한다면. 거기안에 들어가있는 변수들만 쫓아가면 된다 변수를 좀더 사용하기 때문에 공간복잡도는 조금더 올라가겠지만. 가독성은 향상된다. 그러나 변수명을 모두 지정해줘야하는 문제가 있다.
주제 . 인터페이스 설계의 이점
주제. null 체크 (with optional)
한 함수 스코프로 잡고 그 안에서의 null 처리를 하라. 무의미한 null 처리라면 로깅의 목적으로로 쓸수 있다. 객체에서 객체를 계속 참조하는 구조가 nullpointerexception의 취약점이다. set 할때보다 get 할때를 유의하라.
/** Get 혹은 Post */ HttpGethttpGet=newHttpGet(uri); httpGet.setHeader("Content-Type", "application/json"); HttpResponseresponse= httpClient.execute(httpGet); HttpEntityentity= response.getEntity();
return EntityUtils.toString(entity); }
주제. async, await, promise, then
주제 React에서 Component 와 Data
Component 설계할때 데이터에 영향이 있는것은 주입받도록 만들고 나머지는 해당 컨테이너에서 처리하면된다. 추상화 기법은 Component 작업할때 별로 좋지 않은것 같다. styled 와 관련된 Component 를 두고 예를 추상화 시켜서 쓰려고 했는데. 결국 css 문법을 계속 한번씩 확인하게 되고.
width, height 등과 관련된 Layout Component 하나 두고 이걸로 저런 값들을 조절하고
button, label 등의 글자나 특색이있는 UI 요소들은 다른 component로 둬서 둘을 결합해서 사용하는게 좋은듯.
이런식으로 기본적으로 내가 만든 모든 컴포넌트는 레이아웃에 특별함이 필요하다하면 저걸로 감싸는거지.
레이아웃적인 요소와 특정 컴포넌트만 가지는 요소를 구분시키고 이 레이아웃적인 요소를 감싸게끔 만드는게 진짜 조은듯
Data는 State를 기준으로 Store, Action, Reducer를 설계한다. State를 표현하기 위한 Store, State를 조작하기 위한 Action 들 인것이다.
@Inherited @Documented @Retention(RetentionPolicy.RUNTIME)// 컴파일 이후에도 JVM에 의해서 참조가 가능합니다. //@Retention(RetentionPolicy.CLASS) // 컴파일러가 클래스를 참조할 때까지 유효합니다. //@Retention(RetentionPolicy.SOURCE) // 어노테이션 정보는 컴파일 이후 없어집니다. @Target({ ElementType.PACKAGE, // 패키지 선언시 ElementType.TYPE, // 타입 선언시 ElementType.CONSTRUCTOR, // 생성자 선언시 ElementType.FIELD, // 멤버 변수 선언시 ElementType.METHOD, // 메소드 선언시 ElementType.ANNOTATION_TYPE, // 어노테이션 타입 선언시 ElementType.LOCAL_VARIABLE, // 지역 변수 선언시 ElementType.PARAMETER, // 매개 변수 선언시 ElementType.TYPE_PARAMETER, // 매개 변수 타입 선언시 ElementType.TYPE_USE // 타입 사용시 }) public@interface MyAnnotation { /* enum 타입을 선언할 수 있습니다. */ publicenumQuality {BAD, GOOD, VERYGOOD} /* String은 기본 자료형은 아니지만 사용 가능합니다. */ String value(); /* 배열 형태로도 사용할 수 있습니다. */ int[] values(); /* enum 형태를 사용하는 방법입니다. */ Quality quality()default Quality.GOOD; }
public Builder<T> data(T val) { this.treeNode.data = val; returnthis; }
public Builder<T> parent(TreeNode<T> val) { this.treeNode.parent = val; returnthis; }
public Builder<T> children(List<TreeNode<T>> val) { this.treeNode.children = val; returnthis; }
public TreeNode<T> build() { returnthis.treeNode; } } }
lombok
@Builder.Default
@Builder
@SuperBuilder
@ToString(callSuper)
주제
Jackson 의존성 주입시 스프링 부트에서 버전관리를 해주끼 때문에 굳이 버저닝 하지 말자. 했다가 스프링이랑 버전안맞아서 골치 아프다.
예외처리
컨트롤러쪽과 서비스쪽의 예외처리 방식이 조금은 달라야할 것 같다. 둘다 모두 paramter, response 강경하게 예외 처리를 했더니. 서비스쪽에서 이 예외처리한 코드 때문에 컨트롤러가 유연하게 해당 서비스를 사용하지 못하는 케이스가 발생한다.
그래서 다시 정리한 내용은 우선 parameter, response 이 들이 예외처리를 해야하는 포인트인 것은 맞다. 다만 그렇다면 이것을 모두 한 함수 범위 내에서 검증을 해야하는가 에 대한 질문은 아니다로 바뀌었다.
컨트롤러는 스프링에서 엔드포인트이기 때문에 모두 검증을 하는것이 맞지만. 서비스쪽에서는 유연성을 보다 가지게 하기 위해서. paramter 검증을 하되 예외가 발생했을시 exception을 던지지말고 null 객체가 반환되게끔 return 하는 구조를 가지도록 하고
response 검증은 컨트롤러쪽에서 할수 있도록 null을 포함한 객체로 내려주자.
1 2 3 4 5 6 7 8 9 10 11 12 13
컨트롤러 parameter 검증 : 강경하게 모두 해야함 response 검증 : 강경하게 모두 해야함
서비스 parameter 검증 : 검증을 하지만 문제가 있을경우 null을 반환 response 검증 : 검증하지 않고 컨트롤러에게 넘김
null을 반환하는 종류 (1) 단일 객체를 반환하는 함수 : Optional 을 사용하여 Optional.empty() 반환 (2) Collection 객체를 반환하는 함수 : 해당 컬렉션의 빈 객체를 반환 ex) Set.of(); (3) void 인 함수 : Exception을 던진다.
Maven 프로젝트 임포트시 Class 객체를 인지를 못하고 Java 파일로 머물러 있을 때
maven 프로젝트의 소스는 기본적으로 src > main > java 폴더 안 부터 패키지로 인정이 된다. 해당 디렉토리를 생성해주고 그다음에 java 폴더를 src 디렉토리로 마킹해주자.
Jwt DatatypeConverter 관련 오류가 발생시 아래 의존성이 있는지 확인
Spring Security 프레임워크와 JsonWebToken 을 이용해 웹인증을 구현하는 도중, 로그인을 시도해서 서버로부터 토큰을 얻으려고 할때, 웹서버 로그에 다음과 같은 에러가 발생했습니다
java.lang.NoClassDefFoundError: Could not initialize class javax.xml.bind.DatatypeConverterImpl
오류 로그를 자세하게 읽어보고, 관련하여 코딩한 컨트롤러와 클래스들을 살펴보아도 문제가 없는 것 같아서 구글링했습니다. (stackoverflow.com/questions/55606519/getting-exception-java-lang-noclassdeffounderror-could-not-initialize-class-jav)
위 링크에서 답변한 솔루션을 참고하여 저같은 경우는 다음과 같은 종속성을 pom.xml 에 추가하여 해결하였습니다.