Skip to content

Commit

Permalink
refactor: 패키지 구조, 파일명 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyeon9mak committed Jun 5, 2021
1 parent 3f4b1c7 commit f4fa0d3
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 138 deletions.
105 changes: 0 additions & 105 deletions 2021-05-14.md

This file was deleted.

File renamed without changes.
18 changes: 18 additions & 0 deletions javascript-tip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## JS에서 JSON의 키와 값이 일치하는 경우 생략 가능
JSON 자료구조에 사용되는 Key와 Value가 완전히 동일한 경우 아래와 같이 생략이 가능하다.
```javascript
JSON.stringify({
email: email,
age: age,
password: password
})
```
```javascript
JSON.stringify({
email,
age,
password
})
```

<br>
1 change: 0 additions & 1 deletion 2021-05-12.md → oop/mvc-layer-comment.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# 2021년 5월 12일
## @EnableWebMvc
```java
@Retention(RetentionPolicy.RUNTIME)
Expand Down
26 changes: 26 additions & 0 deletions oop/static-factory-method.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## 생성자에 인자가 많은 경우 정적 팩터리 메서드를 고려 할 것

특히나 DTO 등 어쩔 수 없이 필드 데이터가 한꺼번에 많이 오가는 경우 사용하기 편하다.
브라운이 수업 중에 말씀하셨던 '도메인이 풍부해질수록 서비스가 간결해진다.'의 확장선이라고 볼 수 있을거같다.
DTO 생성자를 풍부하게 만들수록 컨트롤러, 서비스, DAO 코드가 간결해진다!

그렇지만 꼭 장점만 있는것은 아니다.

- 일반적인 생성자처럼 API 설명에 명확히 드러나지 않는다.
- 인스턴스를 생성해주는 메서드를 직접 찾아내야 한다.
- 그렇기 때문에 널리 알려진 규약에 따라 메서드를 명명해야 한다.

### 널리, 많이 알려진 명명법

| 메서드명 | 내용 | 예시 |
| :-------------------: | :----------------------------------------------------------- | :---------------------------------------------------------- |
| from | 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드 | Date d = Date.from(instant); |
| of | 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드 | Set faceCards - EnumSet.of(JACK, QUEEN, KING); |
| valueOf | from과 of의 더 자세한 버전 | BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE); |
| instance, getInstance | (매개변수를 받는다면)명시한 인스턴스를 반환, 같은 인스턴스임을 보장하지는 않는다. | StackWalker luke = StackWalker.getInstance(options); |
| create, newInstance | instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장 | Object newArray = Array.newInstance(classObject, arrayLen); |
| getType | getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. Type은 팩터리 메서드가 반환할 객체의 타입이다. | FileStore fs = Files.getFileStore(path); |
| newType | newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다. Type은 팩터리 메서드가 반환할 객체의 타입이다. | BufferedReader br = Files.newBufferedReader(path); |
| type | getType과 newType 축소버전 | List litany = Collections.list(legacyLitany); |

https://hyeon9mak.github.io/Effective-Java-item1/
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions spring/exception-handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## @ControllerAdvice, @RestControllerAdvice vs @ResponseStatus

> Q. @RestControllerAdvice 어노테이션을 통해서 exception들을 핸들링 하곤 했는데, 대부분 ResponseEntity로 Http 상태코드만 반환하곤 했습니다. 그러다 오늘 @ResponseStatus 라는 어노테이션을 알게되었는데, exception 클래스 위에 붙여서 자동으로 Http 상태코드를 반환할 수 있는 것 같더라구요!
별도로 Advice 클래스를 만들지 않아도 자동으로 Http 상태코드 response를 반환해준다는게 굉장한 장점인 것 같은데, 현업에서는 어떤 방식이 더 선호되는지 궁금합니다!

> A. 당연한 얘기일 수 있지만 프로젝트 성격과 프로젝트 참여하는 사람 취향에 따라 달라질 것 같아요! 섞어서 쓰는 경우도 많을 것 같고요!
예시를 전달하기 위해 저희 서비스를 말씀드리면 예외에 따라 Body와 Header가 크게 변경되는 부분이 있고, 예외 상황에 따라 별도의 비즈니스 로직을 처리하는 경우가 있어 대부분은 ExceptionHandler를 사용하는 것 같습니다!
답변드리며 든 생각인데..! ExceptionHandler와 ResponseStatus를 섞어쓰는 경우는 있었어도, ResponseStatus 만으로 서비스를 했던 기억은 없네요 ㅎㅎ

@ControllerAdvice만 쓰거나 @ResponseStatus를 섞어쓰는 경우는 있어도, @ResponseStatus만 사용하는 경우는 없다.
14 changes: 14 additions & 0 deletions spring/spring-aop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Spring AOP
AOP(Aspect Oriented Programming)은 관점 지향 프로그래밍으로, 어떤 로직에 대해 핵심적인 관점, 부가적인 관점을 나누어 보고 그 관점들을 기준으로 각각 모듈화를 하겠다는 것이다.
(모듈화 - 공통된 로직이나 기능을 하나의 단위로 묶는 것)

예를 들어 핵심적인 관점을 우리가 적용하고자 하는 핵심 비즈니스 로직.
부가적인 관점은 그에 필요한 데이터베이스 커넥션, 로깅, 파일I/O 등이 있다.

![image-20210514171338061](/Users/hyeon9mak/Library/Application Support/typora-user-images/image-20210514171338061.png)

(이미지 출처 - https://engkimbs.tistory.com/746)

AOP 관점에서 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어 다른 부분에서 계속해서 반복되는 코드들을 발견하고 이것들을 모듈로 만들어 재사용하겠다는 것. "계속해서 반복되는 코드들"을 **흩어진 관심사(Crosscutting Concerns)** 라고 부른다.

<br>
31 changes: 31 additions & 0 deletions spring/transactional.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## @Transactional
트랜잭션은 ACID의 성질을 가진다

- Atomicity(원자성) : 한 트랜잭션 내에서 실행한 작업들은 하나로 간주한다. 모두 성공, 모두 실패만 존재하며 부분 성공 등은 존재하지 않는다.
- Consistency(일관성) : 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다.
예를 들자면 A통장에서 B통장으로 계좌이체를 한 후에도, A통장과 B통장 계좌 잔액의 합이 동일해야한다. 또, Key의 속성이 변화한다던지의 이벤트가 발생해선 안된다.
- Isolation(고립성, 독립성) : 트랜잭션이 동작하던 중에 또 다른 트랜잭션과 통신을 한다던지의 행동이 발생해서는 안된다. 동시에 2개 이상의 트랜잭션이 동작을 한다더라도, 동작 중에 서로간의 간섭이 절대 없어야 한다.
동작이 끝난 후의 간섭에 대해서는 상관없다.
- Durability(지속성) : 데이터 변화가 일어났을 때 변화된 내용이 유지(저장)가 되어야 한다.

스프링에서는 `@Transcational` 어노테이션을 사용해서 선언적 트랜잭션을 진행한다.
클래스나 메서드 위에 붙여서 사용할 수 있으며, 붙인 곳에 트랜잭션 기능이 적용된다.

### 트랜잭션 우선순위
클래스 메소드 > 클래스 > 인터페이스 메소드 > 인터페이스

### CRUD Transactional
Create/Update/Delete 는 테이블에 변화를 일으키기 때문에 트랜잭션을 거는 것이 추천된다.
그러나 Read는 트랜잭션을 거는 것에 신중해야한다. (거의 걸면 안된다.)

예를 들어 1개의 서비스에서 2개의 데이터베이스(A, B)를 조회하려고 할 때, B 데이터베이스에 문제가 발생했을 경우 서비스는 트랜잭션을 지키기 위해서 B 데이터베이스의 문제가 해결될 때 까지 기다리려고 한다. (트랜잭션을 걸지 않았을 경우 바로 예외를 던지며 실패할 수 있다.)

이 때문에 Read 쪽에는 트랜잭션을 거는 것에 신중해야한다.
(나중에 현업 단계에서는 더 많은 고려사항이 존재하지만, 현재는 이렇게 이해하고 넘어가자)

### 그렇다면 Controller 계층에는 @Transactional 어노테이션을 붙일 수 없나?
결론 : 붙여도 아무런 효과가 없다.
우선 Spring AOP에서 기본적으로 다이나믹 프록시 기법을 사용해 동작하는데, 다이나믹 프록시 기법에는 인터페이스가 필요하다. 그런데 Controller 클래스는 일반적으로 인터페이스를 가지고 있지 않기 때문에, @Transactional 어노테이션을 붙여도 동작을 하지 않는다.
그와 별개로, Controller는 통신을 주고 받기도 바쁜 계층이다. Controller 클래스에서는 단순히 HTTP 요청에 맞게 비지니스 로직을 호출하는 구조로 설계하자.

<br>
63 changes: 31 additions & 32 deletions 2021-05-16.md → spring/valid-annotation.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
# 2021-05-16 TIL
# valid annotation
## @NotNull, @NotEmpty, @NotBlank

`@NotNull` 은 말 그대로 Null만 허용하지 않는다. 이 때문에 `""`, `" "` 는 허용하게 된다.
Null이 들어오면 로직에 예상치 못한 오류가 발생하거나, 문제가 생길 경우에 사용된다.

`@NotEmpty` 는 Null과 `""` 를 허용하지 않는다. `@NotNull` 쪽에 `""` 검증이 추가된 것이다.

`@NotBlank` 는 Null과 `""`, `" "` 를 모두 허용하지 않는다.

즉, 3개 중 가장 검증 강도가 높다.



### validation 어노테이션을 꼭 사용해야만 하는가?

```java
public static LineServiceDto from(final Long id, final LineRequest lineRequest) {
if (Objects.isNull(id)) {
throw new SomeException();
}
return new LineServiceDto(id, lineRequest.getName(), lineRequest.getColor());
}
```

정적 팩터리 메서드를 통해서도 충분히 id Null에 대해서 예외처리를 해줄 수 있다.
validation 어노테이션이 편리함을 제공해주는건 맞지만, 맹목적으로 거기에 의존할 필요는 없다.
가장 중요한 것은 검증하는 방식이 아니라, 검증을 해야하는 이유(목적)과 검증 그 자체다.

<br>

## @Valid 어노테이션과 사용 가능한 종류
| Anotation | 제약조건 |
Expand All @@ -25,34 +54,4 @@
| @AssertTrue | true 인가? |


<br>

## JS에서 JSON의 키와 값이 일치하는 경우 생략 가능
JSON 자료구조에 사용되는 Key와 Value가 완전히 동일한 경우 아래와 같이 생략이 가능하다.
```javascript
JSON.stringify({
email: email,
age: age,
password: password
})
```
```javascript
JSON.stringify({
email,
age,
password
})
```

<br>

## @ControllerAdvice, @RestControllerAdvice vs @ResponseStatus

> Q. @RestControllerAdvice 어노테이션을 통해서 exception들을 핸들링 하곤 했는데, 대부분 ResponseEntity로 Http 상태코드만 반환하곤 했습니다. 그러다 오늘 @ResponseStatus 라는 어노테이션을 알게되었는데, exception 클래스 위에 붙여서 자동으로 Http 상태코드를 반환할 수 있는 것 같더라구요!
별도로 Advice 클래스를 만들지 않아도 자동으로 Http 상태코드 response를 반환해준다는게 굉장한 장점인 것 같은데, 현업에서는 어떤 방식이 더 선호되는지 궁금합니다!

> A. 당연한 얘기일 수 있지만 프로젝트 성격과 프로젝트 참여하는 사람 취향에 따라 달라질 것 같아요! 섞어서 쓰는 경우도 많을 것 같고요!
예시를 전달하기 위해 저희 서비스를 말씀드리면 예외에 따라 Body와 Header가 크게 변경되는 부분이 있고, 예외 상황에 따라 별도의 비즈니스 로직을 처리하는 경우가 있어 대부분은 ExceptionHandler를 사용하는 것 같습니다!
답변드리며 든 생각인데..! ExceptionHandler와 ResponseStatus를 섞어쓰는 경우는 있었어도, ResponseStatus 만으로 서비스를 했던 기억은 없네요 ㅎㅎ

@ControllerAdvice만 쓰거나 @ResponseStatus를 섞어쓰는 경우는 있어도, @ResponseStatus만 사용하는 경우는 없다.
<br>

0 comments on commit f4fa0d3

Please sign in to comment.