우아한테크코스 3기 백엔드 Lv3 모의면접 대상 Lv2 학습로그 모음 - 답변

김태희·2021년 6월 20일
0
post-thumbnail

체스 미션

[Spring] DI(의존성 주입) 적용 - 4

내용

  • 기존 코드는 객체들이 서로 강하게 결합되어 있었다.
  • Spring Bean 생성자 주입 방식으로, 객체들 간의 결합도를 낮췄다.

태그

Spring, DI, OOP


[Spring] Web MVC 적용 - 3

내용

  • Spark Java를 제거하고, Spring Web MVC를 적용했다.
  • 추상화가 잘 되어있어 Controller의 코드가 매우 간결하고 깔끔해졌다.

태그

Spring, MVC


[JDBC] JdbcTemplate 적용 - 4

내용

  • Mysql Jdbc Driver 만 사용해서 작성했던 DAO 클래스들에 JdbcTemplate 를 적용했다.
  • 한 단계 더 추상화 되어있어, 코드가 많이 줄어들고 깔끔해졌다.
  • queryForObject() 로 DB에서 값을 조회할 때, 결괏값의 개수가 0개이면 EmptyResultDataAccessException 가 발생해, try ~ catch 문으로 직접 예외를 처리해야 하는 부분이 아쉬웠다.

태그

JDBC


A.

jdbcTemplate을 이용해서 select쿼리를 날리는 경우 .query 메소드를 사용하게 된다.

그런데 .query 메소드의 경우 List형태로 리턴을 해주기 때문에 .queryForObject 메소드를 사용하는 경우도 있다.

다만 .queryForObject 메소드의 경우에는, row가 정상적으로 1개 나왔을 경우에는 문제가 없는데, row가 아예 나오지 않는 경우에 대해 exception을 떨구게 된다.

이곳 저곳 구글링을 해보면, try catch 문으로 exception을 캐치하여 null을 리턴하도록 하라고는 하는데, try catch 문의 경우 성능 저하의 원인이 될 수 있기 때문에 웬만해선 사용을 권장하지 않는다.

해결방안은 .query메소드를 사용하되, 단일 행이 나올 것이라고 예상되는 구문에서는 DataAccessUtils.singleResult나 DataAccessUtils.uniqueResult를 이용하여 List형태를 Object형태로 리턴하게끔 하면 된다.

메소드 구현체 내부를 들어가보면 알겠지만, .query 메소드의 결과로 나온 List의 사이즈를 체크하여, 사이즈가 0이면 null을 리턴하고, 사이즈가 0이 아니면 첫번재 element를 끄집어와서 리턴을 해주는 방식으로 되어 있다.

출처: https://hakurei.tistory.com/15 [Reimu's Development Blog]


[OOP] 도메인 분리 - 5

내용

  • 기존 코드는 도메인Spring과 관련된 Repository 들이 모두 얽혀있었다.
  • 모든 도메인이 Spring에 의존하고 있었다.
  • 테스트도 @SpringBootTest 를 사용해 Spring 자체를 실행시켜야 가능했다.
  • 코드 리뷰어 김고래 의 피드백을 적용하면서, 도메인은 순수 자바 객체로 유지되어야 함을 깨달았다.
  • 불가피하게 Spring을 띄워야 하는 Repository 관련 테스트를 제외하고, 도메인 관련 테스트들은 모두 순수 자바로만 실행할 수 있게 되었다. 테스트 실행 속도가 매우 빨라졌다.
  • 도메인 자체만 테스트하다보니, 각 객체별로 작은 단위의 테스트를 매우 간단하게 할 수 있었다. 이전에는 모든 의존성을 알맞게 주입해 놓아야 테스트가 가능했다.
  • 콘솔 게임은 Spring 없이 순수하게 자바로만 실행할 수 있게 되었다.

태그

OOP, Domain, Test, Spring


[Test] In-Memory DB 적용 - 3

내용

  • 이전에는 테스트를 실제 DB를 통해서 했었다.
  • 코드 리뷰어 김고래 의 피드백으로 Test들은 In-Memory DB인 H2 DB를 사용하게 했다.
  • 테스트가 훨씬 가벼워지고, 외부 DB에 의존하지 않게 되었다. 또한, 속도도 빨라졌다.

태그

Test, DB


[Spring MVC] @(Rest)ControllerAdvice - 3

내용

  • 모든 컨트롤러에서 발생하는 예외를 catch할 수 있다.
  • 패키지, Controller, Exception의 범위를 지정할 수도 있다.
  • try ~ catch 문을 없앨 수 있어, 비즈니스 로직이 매우 깔끔해진다.

태그

Spring, MVC, Exception


@ExceptionHandler

@ExceptionHandler를 등록한 Controller에만 적용된다. 다른 Controller에서 명시되어있는 예외가 발생하더라도 예외를 처리할 수 없다.

@ControllerAdvice

@ExceptionHandler가 하나의 클래스에 대한 것이라면, @ControllerAdvice는 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.

@RestControllerAdvice

@ControllerAdvice와 동일한 역할 즉, 모든 Controller에서 발생하는 예외를 잡아 핸들링 하는 기능을 수행하면서 @ResponseBody를 통해 객체를 리턴할 수도 있다는 얘기다.

ViewResolver를 통해서 예외 처리 페이지로 리다이렉트 시키려면 @ControllerAdvice만 써도 되고, API서버여서 에러 응답으로 객체를 리턴해야한다면 @ResponseBody 어노테이션이 추가된 @RestControllerAdvice를 적용하면 되는 것이다.

@RestController에서 예외가 발생하든 @Controller에서 예외가 발생하든 @ControllerAdvice + @ExceptionHandler 조합으로 다 캐치할 수 있고 @ResponseBody의 필요 여부에 따라 적용하면 된다는 것이다.

@ControllerAdvice + @ResponseBody = @RestControllerAdvice

출처: https://jeong-pro.tistory.com/195 [기본기를 쌓는 정아마추어 코딩블로그]


[HTTP] REST API - 2

내용

  • 삭제 요청을 POST "/delete" 로 했었다.
  • DELETE "games/${gameId}" 로 바꾸니, API가 더욱 명시적으로 되었다.

태그

HTTP, REST, API


내용

  • 클라이언트에 값을 저장하고, 이후 요청마다 해당 값을 포함시키는데 적합한 쿠키를 사용했다.
  • 한 번 쿠키를 발급해주면, 만료되기 전 까지 매 요청에 쿠키를 포함해 보내기 때문에 인증에 유용하다.

태그

HTTP, Cookie


[보안] Hash 암호화 - 4

내용

  • 프로그래밍 요구사항에서 비밀번호를 클라이언트에 저장하고, 매 요청에 같이 보내라는 부분이 있었다.
  • 이 방식은 보안에 매우 취약하기 때문에, Hash 암호화를 사용했다.
  • 쿠키나 요청 데이터가 탈취당하더라도 Hash 함수로 암호화 되어있기 때문에, 암호 본문은 알 수 없어 보안에 유리하다.

태그

보안, Hash


배포/운영 인프라

[운영] Bastion 서버 적용 - 3

내용

  • 일반 서비스 접속용 경로와 별도로 관리자용 접속 경로인 Bastion 서버를 구성함.
  • 서비스 접속 경로의 책임과 관리자 접속 경로의 책임을 분리함.
  • Bastion 서버가 피해를 보더라도 이 부분만 재구성하면 되므로, 서비스 피해를 최소화 할 수 있음.
  • DDos 공격을 받고 있다면 일반 서비스 접속용 경로로 접속할 수 없기 때문에, 관리자는 Bastion 서버를 통해 접속해야 함.

태그

운영, 보안


A.

일반 서비스 접속용 경로와 별도로 관리자용 접속 경로인 Bastion 서버를 구성했습니다.

이를 통해 서비스 접속 경로의 책임과, 관리자 접속 경로의 책임을 분리했습니다.

모든 서버에 동일한 수준의 보안을 설정하면, Auto-Scaling 등의 확장을 위한 관리 포인트가 늘어나, 일반적으로 보안의 일정 부분을 포기하는 결정을 하게 됩니다.

Bastion 서버를 두면, 이러한 보안 문제와 확장성 문제를 모두 해결할 수 있습니다.

Bastion 서버가 공격을 받았을 때, 이 부분만 재구성하면 되므로 서비스 피해를 최소화 할 수 있습니다.

DDos 공격을 받고 있다면 일반 서비스 접속 경로로 접속 할 수 없습니다. 이때, 관리자용 접속 경로인 Bastion 서버를 구성해 두었다면 이를 통해 접속할 수 있습니다.


[운영] Thread Dump 모니터링 - 2

내용

  • Thread들의 실시간 상태를 모니터링 할 수 있다.
  • 에러가 발생했을 경우, 디버깅에 유리하다.

태그

운영, Thread

Thread Dump

A thread dump is a snapshot of the state of all the threads of a Java process.

Thread Dump 란, Java 프로세스의 모든 Thread들의 스냅샷(상태를 사진처럼 찍은 것)을 말한다.

Snapshot

In computer systems, a snapshot is the state of a system at a particular point in time.

Snapshot 이란, 특정 시점의 시스템 상태를 말한다.

Snapshot 이란, 특정 시점의 시스템 상태를 사진처럼 찍은 것을 말한다.

A.

Thread Dump란, Java 프로세스의 모든 Thread들의 스냅샷을 말합니다.

스냅샷이란, 특정 시점의 시스템 상태를 말합니다.

즉 Thread Dump란, Java 프로세스의 모든 Thread들의 특정 시점의 상태를 사진처럼 찍은 것을 말합니다.


[Log] LogBack 적용 - 4

내용

  • Logger의 이름별로 다른 파일에 로그가 쌓이도록 해, 로그 관리가 용이해짐.

태그

Log


[AWS] CloudWatch - 4

내용

  • EC2의 네트워크 상태, CPU, 메모리/디스크 사용률 등을 CloudWatch 대시보드에서 시각적으로 확인할 수 있음.
  • 로그 파일들을 CloudWatch에 연동시켜 EC2에 접속하지 않고도 AWS 홈페이지에서 파일별 로그들을 편리하게 확인할 수 있음.

태그

운영, AWS, CloudWatch

[Container] Docker 적용 - 5

내용

  • MySQL을 Docker로 띄웠다.
  • Docker만 설치되어 있다면, 배포 환경과 완전히 독립적으로 Container를 실행시킬 수 있었다.

태그

배포, Container, Docker




지하철 미션

[Test] ATDD - 5

내용

  • API 스펙 요구사항에 대해 ATDD를 진행했다.
  • 테스트가 모두 통과할 때 마다, API 스펙 요구사항을 충족하고 있음을 확신할 수 있었다.
  • 테스트가 추상적이어서, 리팩토링에 따른 테스트코드 수정이 거의 불필요했다.

태그

Test, ATDD


A.
ATDD는 인수 테스트를 먼저 작성한 다음, 기능 개발을 하는 방식입니다.

인수 테스트는 시스템의 인수 결정을 위해 사용자 입장에서 요구사항을 테스트하는 것을 말합니다.

블랙박스 테스트로, 시스템 내부 구현은 모르는 상태로 API 요청과 응답으로만 테스트합니다.

출처: 고객이 확인하는, 인수 테스트(Acceptance Test)


[인증] JWT - 5

내용

  • 로그인 인증에 JWT를 사용했다.
  • 상태 정보(세션 등)를 서버에 저장하지 않아도 돼, 서버 부담을 줄일 수 있었다.

태그

인증, JWT


A.

세션 인증 (Stateful)

세션을 사용하는 방식은 Stateful한 방식입니다.
인증 상태를 서버 메모리나 데이터베이스에 보관하고 유지합니다.

이 방식은, 로그인 중인 사용자가 많아질수록 서버에 과부하가 생깁니다.

서버 확장을 해야할 때, 인증 상태 유지와 호환을 고려해야 하기 때문에 Stateful한 세션 방식은 서버 확장에 불리합니다.

세션의 기반이 되는 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어있어, CORS 이슈를 관리해주어야 하는 번거로움이 있습니다.

토큰 기반 인증 시스템 (Stateless)

토큰 기반 인증 시스템은 Stateless한 방식입니다.

서버가 인증 상태를 저장하지 않습니다.

클라이언트 요청에 포함되어있는 인증 토큰만을 가지고 인증에 대한 정보를 얻고 처리합니다.

이렇게 상태가 없는 경우 클라이언트와 서버간의 연결고리가 없기 때문에 서버의 확장성(Scalability)이 높아집니다.

JWT(JSON Web Token)

JWT는 토큰 기반 인증 시스템의 구현체 이며, 웹 표준입니다.

JSON 데이터 포맷을 기반으로 한 웹 토큰입니다.

모든 정보를 자체적으로 지니고 있습니다.

  • Header : 토큰에 대한 기본정보
  • Payload : 전달할 정보
  • Signature : 토큰이 검증에 대한 정보

HTTP 헤더에 넣어서 전달할 수 있고, URL의 파라미터로 전달할 수도 있습니다.


참조 : [JWT] 토큰(Token) 기반 인증에 대한 소개

Base64란?

인코딩 : 데이터의 표준화, 보안, 처리속도 향상, 저장 공간 절약 등을 위해 다른 형태로 변환하는 방식을 말합니다.

이미지, 동영상, 오디오 전송에 많이 활용됩니다.

인코딩의 반대는 디코딩입니다.

Base64 : 8비트 이진 데이터(실행파일, ZIP파일 등)를 문자코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로 바꾸는 인코딩 방식을 말합니다.

6bit당 2bit의 오버헤드가 발생해, 전송 데이터의 크기가 약 33% 정도 늘어납니다.

일반 ASCII 문자로 인코딩하면 다음과 같은 시스템 비독립성의 문제들이 발생할 수 있습니다.

  • ASCII는 7 bits Encoding인데 나머지 1bit를 처리하는 방식이 시스템별로 다릅니다.
  • 일부 제어 문자(e.g. Line ending)의 경우 시스템 별로 다른 코드값을 가집니다.

위와 같은 문제로 일반 ASCII 문자는 다양한 시스템 간의 데이터를 전달하기에 안전하지 않습니다.

Base64는 이러한 시스템 비독립성 문제를 해결하기 위해 ASCII 문자들 중 제어 문자와 일부 특수문자를 제외한 64개의 안전한 출력 문자만을 사용합니다.
(*안전한 출력 문자란, 문자 코드에 영향을 받지 않는 공통 ASCII를 의미)

즉, Base64는 HTML 또는 Email과 같이 문자를 위한 Media에 Binary Data를 포함해야 될 필요가 있을 때, 포함된 Binary Data가 시스템 독립적으로 동일하게 전송 또는 저장되는 걸 보장하기 위해 사용합니다.

출처: [Base 64] Base64이란 무엇일까? / Base64 사용 이유와 인코딩과 디코딩

URL Safe Base64

Base64에서 62, 63번의 인코딩 문자값을 보면 각각 +, / 입니다. 이는 연산자이기 때문에 데이터를 다룰 때 오류를 일으킬 수 있습니다. 또한, =는 padding 문자에 해당하는데, 이는 URL에서 기존에 사용되고 있는 문자입니다. 따라서 URL Safe 한 base64의 62, 63번은 -, _로 대체되었고, =는 생략하거나 특정 라이브러리는 .로 대체합니다.

출처:
base64 vs base64url safe 차이
base64url.com


[Spring] Interceptor - 3

내용

  • 로그인 인증이 필요한 URI 요청에 Interceptor를 걸고, JWT 유효성 검사 로직을 추가했다.
  • JWT 검사 책임을 Interceptor로 분리할 수 있었다.

태그

Spring, Interceptor


Filter vs Interceptor

A.
Filter는 Spring Context의 외부, DispatcherServlet 앞에 존재합니다. 요청이나 응답 내용의 체크, 변경(인코딩 변환 등)등을 할 수 있습니다.

Interceptor는 Spring Context의 내부에 존재합니다.
DispatcherServlet이 Controller(Handler)를 호출하는 시점의 전, 후에 끼어들어 Controller(Handler)의 요청과 응답을 가로채서(Intercept) 처리합니다.

Spring Context의 내부에 존재하기 때문에, Spring의 모든 Bean 객체에 접근할 수 있습니다.

Interceptor는 여러 개를 사용할 수 있습니다. 로그인 체크, 권한 체크, 프로그램 실행시간 계산 작업, 로그 확인 등에 쓰입니다.

Interceptor methods

  • preHandle() - 컨트롤러 메서드 실행 전
  • postHanle() - 컨트롤러 메서드 실행 후, view페이지 렌더링 전
  • afterCompletion() - view 페이지가 렌더링 되고 난 후

출처 : [Spring] Filter, Interceptor, AOP 차이 및 정리


[Spring] Custom Annotation, ArgumentResolver - 3

내용

  • Custom Annotation을 ArgumentResolver에 등록해, 해당 Annotation이 메소드의 매개변수 앞에 붙어있다면 매개변수에 현재 로그인 되어있는 Member객체를 넣어주도록 했다.
  • 로그인 사용자 사전 조회 책임을 Custom Annotation + ArgumentResolver로 분리할 수 있었다.

태그

Spring, Annotation, ArgumentResolver


[OOP] Layer와 Domain의 책임 분리 - 4

내용

  • Service 레이어에 모든 비즈니스 로직을 작성하다보니 Service 클래스가 매우 커지고, 도메인과 Service 레이어의 책임 분할이 되지 않았다.
  • 비즈니스 로직은 모두 도메인 내부로 옮기고, Service 레이어에서는 도메인의 비즈니스 로직 실행 순서만 보장하도록 해, 각각의 책임을 분리했다.

태그

OOP, Domain, Service


[JDBC] NamedParameterJDBCTemplate 적용 - 3

내용

  • 파라미터를 순서 숫자가 아닌 컬럼명 문자열로 표기해 더욱 직관적이다. 유지보수에 유리하다.

태그

JDBC


[암호화] BCrypt - 5

내용

  • 리뷰어 미립이 Hash 암호화에 대한 학습 키워드를 제공해줬다.
  • 같은 원본 데이터에 대해 암호화를 할 때마다 매번 다른 Hash 결과값이 나오는 BCrypt에 대해 학습했다.

태그

암호화


A.
BCrypt는 동일한 원본 데이터에 대해 암호화를 할 때 마다 매번 다른 Hash 결과값이 나오는 암호 해시 함수입니다.

일반적인 Hash 함수는 원본 데이터가 동일하면, Hash 결과값도 동일합니다.

이럴 경우, Rainbow table 공격에 취약합니다.

Rainbow table은 원본 데이터와 Hash 결과값의 짝을 미리 저장해놓은 것을 말합니다.

이를 사용해 Hash 암호화 된 비밀번호로부터 원본 비밀번호를 추출합니다.

이를 Rainbow table 공격이라고 합니다.

BCrpyt 알고리즘은 동일한 원본 데이터라도 Hash 결과값이 매번 다르기 때문에, Rainbow table 공격을 방지할 수 있습니다.

BCrypt의 이러한 작동 방식이 가능한 이유는, Salt를 사용하기 때문입니다.

말 뜻 그대로 소금처럼 암호화를 할 때 추가적인 데이터를 첨가해, 매 번 결과값이 다르게 합니다.

BCrpyt 알고리즘은 Spring Security의 PasswordEncoder의 비밀번호 암호화 기본 전략입니다.

비밀번호 일치 검사를 할 때, 로그인 요청으로 들어온 비밀번호를 BCrpyt 알고리즘으로 암호화 합니다. 이 때, DB에 저장되어있는 암호화된 비밀번호를 Salt로 사용합니다. 이 결과가 DB에 저장되어있던 암호화된 비밀번호와 일치하면, 로그인 요청으로 들어온 비밀번호는 맞는 비밀번호임이 확인됩니다.


[DB] Transaction 격리 수준 - 5

내용

  • Transaction 격리 수준에 대해 공부하고, 지하철 구간 수정 작업 단위에는 얼만큼의 격리 수준으로 Transaction을 걸어야 하는지 리뷰어 재연링과 함께 토론하며 고민했다.

태그

DB, Transaction


A. 지하철 구간 업데이트를 서로 다른 사용자가 동시에 할 때 일어날 수 있는 동시성 문제에 대해 고민하면서 트랜잭션 격리수준에 대해 공부하고 리뷰어와 이야기를 나눴습니다.

노선의 모든 구간들을 SELECT 한 뒤에, 구간 변경 요청의 유효성을 검사하고, DB를 업데이트 합니다.

여러 사용자가 이와 같은 요청을 동시에 하면 DB에 저장되는 지하철 구간이 꼬일 수 있습니다.

이를 해결하기 위해 DB 트랜잭션 격리수준을 어떻게 설정해야 할지 고민했습니다.

트랜잭션 격리수준은, 동시에 여러 트랜잭션들이 처리될 때, 각 트랜잭션끼리 얼마나 서로 격리되어 있는지를 나타내는 것입니다.

구체적으로 말해서, 특정 트랜잭션이 다른 트랜잭션이 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것입니다.

READ UNCOMMITTED

다른 트랜잭션은 아직 Commit되지 않은 변경내용도 조회할 수 있다.

  1. A 트랜잭션이 1번 크루의 나이를 10살에서 100살로 변경했다. 아직 커밋은 하지 않았다.
  2. B 트랜잭션이 1번 크루의 나이를 조회했다. 100살로 조회됐다. 이를 Dirty Read라고 한다.
  3. 만약 A 트랜잭션에 문제가 발생해 Rollback이 됐다고 하자.
  4. B 트랜잭션은 1번 크루가 여전히 100살이라고 생각하고 로직을 수행한다.

이런식으로 데이터 정합성에 문제가 많으므로, RDBMS 표준에서는 격리수준으로 인정하지도 않는다.

READ COMMITTED (Oracle 기본 설정)

다른 트랜잭션은 Commit된 변경내용만 조회할 수 있다.

위의 경우를 다시 해보면,

B 트랜잭션이 1번 크루의 나이를 조회한 결과는 10살이다.
A 트랜잭션에서 Commit을 한 후에 B 트랜잭션에서 1번 크루의 나이를 조회해야 100살로 조회된다.

이 경우 NON-REPEATABLE READ 부정합 문제가 발생할 수 있다.

  1. A 트랜잭션이 1번 크루의 나이를 10살에서 100살로 변경했다. 아직 커밋은 하지 않았다.
  2. B 트랜잭션이 1번 크루의 나이를 조회했다. 10살로 조회됐다.
  3. A 트랜잭션이 Commit 됐다.
  4. B 트랜잭션이 1번 크루의 나이를 다시 조회했다. 100살이 조회됐다.

이는 하나의 트랜잭션 내에서 SELECT를 여러 번 했을 경우, 항상 같은 결과가 조회되어야 한다는 REPEATABLE READ 정합성에 어긋난다.

REPEATABLE READ (MySQL 기본 설정)

트랜잭션이 시작되기 전에 Commit된 내용만 조회할 수 있다.

위에서 언급한 NON-REPEATABLE READ 부정합 문제가 발생하지 않는다.

이 격리 수준 이하에서는 Phantom Read 문제가 발생한다.

SERIALIZABLE

가장 단순하고 가장 엄격한 격리수준이다.
격리수준이 SERIALIZABLE일 경우 읽기 작업에도 공유 잠금을 설정하게 되고, 이렇게 되면 동시에 다른 트랜잭션에서 이 레코드를 변경하지 못하게 된다.
이러한 특성 때문에 동시처리 능력이 다른 격리수준보다 떨어지고, 성능저하가 발생한다.


[OOP] 원시값 객체 포장 - 2

내용

  • 지하철 요금 원시값을 Fare 값 객체로 포장했다.
  • 생성자에서 값 자체의 유효성 검증을 할 수 있었다.
  • 비즈니스 로직을 객체 내부에서 처리할 수 있었다.

태그

OOP


[배포] 배포 자동화 - 4

내용

  • 배포 자동화가 적용되지 않은 상태에서는 github에서 최신 코드 가져오기 -> 빌드 -> 기존에 실행중인 애플리케이션 종료 -> 새로운 버전의 애플리케이션 실행 의 과정을 일일이 명령어를 쳐서 실행해야 했다.
  • 이 과정 전체를 shell 스크립트로 작성했다.
  • 해당 shell 스크립트를 실행시키기만 하면 새로운 버전의 애플리케이션이 자동으로 배포되어 배포가 매우 편리해졌다.

태그

배포


[Web] CORS 정책 - 3

내용

  • 프론트 서버와 백엔드 서버가 따로 운영되면서, CORS 정책 위반 에러가 발생했다.
  • Access-Control-Allow-Origin 헤더 설정을 통해 해당 에러를 해결했다.

태그

Web, CORS


A.
브라우저의 보안 정책입니다.
브라우저에 랜더링 된 특정 페이지는 자신의 출처의 리소스만 불러올 수 있습니다.
다른 출처의 리소스를 불러오려면 해당 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 합니다.

Simple Request

브라우저는 서버에 본 요청을 일단 즉시 보냅니다.
응답 헤더에 CORS 허가 내용이 있다면 정상으로 받아들이고, 그렇지 않다면 브라우저에서 CORS 에러를 발생시킵니다.

이 방식은 본 요청이 무조건 서버에 가기 때문에, 보안상 취약합니다.

따라서 이 방식은 특정 조건을 만족하는 요청만 보낼 수 있습니다.

Preflighted Request

Simple Request에 해당하지 않는 요청은 브라우저가 Preflighted Request 요청을 본 요청보다 먼저 서버에 보내봅니다. OPTIONS 메소드 요청을 통해 이런 요청을 할 건데, CORS허가가 되는지 서버에 미리 물어봅니다. 서버가 허가된다고 응답하면, 그 때 본 요청을 보냅니다.

허가된 CORS 요청만 보낼 수 있으므로, 보안상 더욱 유리합니다.


[Docs] Spring REST Docs - 5

내용

  • 프론트 크루들과 협업하기 위해 API 문서화가 필요했다.
  • 테스트를 통과해야 문서화가 되고, 이에 따라 프로덕션 코드가 실시간으로 반영되는 Spring REST Docs를 적용했다.

태그

Docs, REST


A.
프로덕션 코드와 문서의 동기화를 가장 중요하게 생각해 Spring Rest Docs를 적용했습니다.

Swagger는 문서와 프로덕션 코드가 동기화 되지 않을 수 있다는 단점이 있습니다.

반면에 Spring Rest Docs는 테스트가 성공해야 문서화가 되기 때문에 프로덕션 코드와 문서가 항상 동기화됩니다.

이러한 이유로 저는 Spring Rest Docs를 선택했습니다.


[OOP] 다형성을 통한 if문 제거 - 5

내용

  • 지하철 요금 정책이 추가될 때 마다 if문이 생겼다.
  • Enum과 함수형 인터페이스의 다형성을 사용해 if문을 제거했다.

태그

OOP, Java


A.
요금 정책 각각을 Enum 상수로 정의했습니다.

각 Enum 상수에, 해당 정책의 조건을 나타내는 람다식과 정책 객체를 반환하는 함수를 함수형 인터페이스 타입의 인스턴스 변수로 지정했습니다.

이를 통해 정책마다 추가되는 if문을 제거할 수 있었습니다.

람다식이란 메서드를 하나의 식으로 표현한 것입니다.

람다식은 사실 메서드가 하나만 존재하는 익명 클래스의 객체입니다.

메서드가 하나만 존재하는 익명 클래스의 객체를 최대한 간소화시켜 식의 형태로 표현한 것이 람다식 입니다.

람다식을 사용하려면 이를 참조할 타입이 있어야 합니다.

람다식은 메서드가 하나만 존재하는 익명 클래스의 객체이기 때문에, 오직 하나의 추상메서드만 정의되어 있는 인터페이스 타입으로 참조하기로 했고, 이를 함수형 인터페이스라고 합니다.

static 메서드와 default 메서드의 개수에는 제약이 없습니다.


profile
Web Back-End (Spring, JPA, AWS)

0개의 댓글