질문 출처 : https://github.com/jjuyeon/Tech-Interview-Study/blob/main/spring/README.md [Spring]
CORS (Cross-origin resource sharing, 교차 출처 리소스 공유)
웹 브라우저에서 특정한 도메인 간(cross-domain) 요청(특히 Ajax 요청)은 같은 출처에서만 리소스를 공유할 수 있다는 규칙을 가진 동일-출처 보안 정책(Same-Origin Policy)에 의해 기본적으로 금지된다(ex. xss 공격 https://a3magic3pocket.github.io/posts/xss-cors-example/). 리소스의 출처를 비교하기 위해서는 세가지의 기준이 필요하다.
- 프로토콜 : http vs https
- 호스트 : naver.com vs google.com
- 포트 번호 : 8080 포트 vs 3000 포트
같은 프로토콜, 호스트, 포트를 사용한다면 같은 출처로 인정된다. 이중 한가지라도 다른 경우를 cross-origin이라고 한다. 이 때 브라우저는 교차 출차 요청을 실행한다.
CORS는 웹 페이지상의 제한된 리소스를 동일 출처가 아닌 다른 도메인으로부터 요청할 수 있게 허용해준다. 이때 교차 출처(cross-origin) 요청을 허용하는 것이 안전한지 아닌지를 판별하기 위해 HTTP 요청을 실행한다.
CORS 해결 방법
1. Chrome 확장 프로그램 이용
2. 서버에서 Access-Control-Allow-Origin 세팅
res.setHeader('Access-Control-Allow-origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true'); // 쿠키 주고받기 허용
// 출처: https://inpa.tistory.com/entry/WEB-📚-CORS-💯-정리-해결-방법-👏 [👨💻 Dev Scroll]
이때 *을 사용하면 모든 Origin에서 오는 요청을 허용한다는 의미이므로 당장은 편할 수 있겠지만, 바꿔서 생각하면 정체도 모르는 이상한 출처에서 오는 요청까지 모두 허용하기 때문에 보안은 더 허술해진다.
그러니 가급적이면 귀찮더라도 아래와 같이 출처를 명시해주어야 한다.
res.setHeader('Access-Control-Allow-origin', 'https://inpa.tistory.com');
// 출처: https://inpa.tistory.com/entry/WEB-📚-CORS-💯-정리-해결-방법-👏 [👨💻 Dev Scroll]
프레임워크와 라이브러리 차이점
프레임워크란?
프레임워크는 어플리케이션 표준 구조를 구현하는 클래스와 라이브러리의 모음이다. 프레임워크는 일반적인 작업을 수행하기 위해 작성된 재사용 가능한 코드 조각을 담고 있다.
라이브러리란?
라이브러리는 소프트웨어 개발 시 사용되는 프로그램의 구성 요소로, 작업을 단순화 하는데 사용할 수 있는 미리 작성된 코드의 모음이다.
차이점
프레임워크와 라이브러리는 제어 역행에 차이가 있다. 라이브러리를 사용할 경우에는 개발자가 프로그램의 흐름을 통제할 수 있다. 개발자가 원할 때 어디서든 라이브러리의 코드를 재사용할 수 있다. 하지만 프레임워크는 프로그램의 흐름이 정해져 있다. 프레임워크를 사용할 경우, 개발자는 프레임워크가 지정한 방식대로 특정한 장소에 특정한 코드를 넣어야한다.
요즘 스프링 개발 시 자바 대신 코틀린의 비중이 늘어나는 이유는?
구글이 안드로이드 공식 언어로 코틀린을 지정하였다. 자바에 비해 사용성이 편리하며 생산성이 증가되었음.
https://analyticsindiamag.com/5-reasons-why-developers-choose-kotlin-over-java/
코틀린의 장점
1. 문법이 간결하여 사용성이 좋다.
- Java (객체형 프로그래밍)
class Hello {
public static void main(String args[]) {
System.out.print("Hello World");
}
}
- Kotlin (함수형 프로그래밍)
System.out.print("Hello World");
동일한 문제에 대해 자바 코드보다 훨씬 간단하고 짧은 코드를 가지고 있다. 자바는 간결한 언어가 아니기 때문에 버그 가능성이 높지만 코틀린은 런타임, 컴파일 때 오류가 발생할 가능성이 더 적다.
2. null safe 언어이다.
코틀린은 Nullable과 Non-nullable이란 개념을 가지고 있어서 null이 발생하지 않도록 만들어준다. 그래서 코틀린으로만 개발할 때는 NullPointException 같은 예외 문제가 발생하지 않는다.
3. 기존 라이브러리와의 상호운용성이 좋다.
코틀린은 자바와 100% 호환된다. 한 프로젝트 안에 자바 파일과 코틀린 파일이 함께 들어있어도 작동에 문제가 없기 때문에 기존의 자바로 만들어진 프로젝트에 코틀린을 적용할 때에도 처음부터 코틀린으로 다시 개발할 필요 없이 새로운 코드에만 적용해도 된다는 장점이 있다.
4. 자바의 문제점을 보완할 수 있는 솔루션을 가진다.
코틀린은 기존의 자바를 보완하고 대체하기 위해 탄생하였기 때문에 자바의 문제점을 해결할 수 있다. 코틀린은 상용구 코드를 제거하여 가능한 오류를 삭제하였다. 코틀린은 delegations, late initializations 등의 특징을 가지고 있고 또한 (generic이 나오기 전)자바의 주요 문제였던 list의 타입 안정성을 해결하였다.
코틀린의 단점
1. 속도가 느리다.
컴파일 시 자바로 변환한 뒤에 바이트 코드로 변환하기 때문에 컴파일 속도가 상대적으로 느리다.
Builder 패턴
객체 생성 패턴
- 생성자 패턴
- 정적 메소드 패턴
- 수정자 패턴
- 빌더 패턴
인스턴스를 생성할 때 생성자 만을 통해서 생성하는 데는 어려움이 있다. 예를 들어 생성자 인자로 너무 많은 인자가 넘겨지는 경우 어떤 인자가 해당 값을 나타내는지 확인하기 힘들다.
public class Computer {
private String HDD;
private String RAM;
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public Computer(String HDD, String RAM, boolean isGraphicsCardEnabled, boolean isBluetoothEnabled) {
this.HDD = HDD;
this.RAM = RAM;
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
this.isBluetoothEnabled = isBluetoothEnabled;
}
}
public void main(String[] args) {
// 어떤 인자가 어떤 값을 나타내는지 파악하기 힘들다
// 인자 중 일부만 값을 넣는다면 그에 맞는 생성자가 각각 필요하다
new Computer("something1", "something2", true, null);
}
빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공한다.
빌더 패턴 사용시 이점
- 필요한 데이터만 설정할 수 있음 (불필요한 생성자를 만들지 않고 객체 생성 가능)
- 유연성을 확보할 수 있음 (데이터 순서에 상관 없이 객체 생성 가능)
- 가독성을 높일 수 있음
- 변경 가능성을 최소화할 수 있음
빌더 패턴 구현
- 빌더 클래스를 Static Nested Class로 생성
- 빌더 클래스의 생성자는 public으로, 필수 값들에 대해 생성자의 파라미터로 받는다
- 옵셔널한 값들에 대해서는 각각의 속성마다 메소드로 제공하며, 이때 메소드는 빌더 객체 자신을 리턴해야 한다
- 빌더 클래스 내에 build() 메소드를 정의하여 클라이언트 프로그램에게 최종 생성된 결과물을 제공한다
build()를 통해서만 객체 생성을 제공하기 때문에 생성 대상이 되는 클래스의 생성자는 private으로 정의해야 한다.
public class Computer {
//required parameters
private String HDD;
private String RAM;
//optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public String getHDD() {
return HDD;
}
public String getRAM() {
return RAM;
}
public boolean isGraphicsCardEnabled() {
return isGraphicsCardEnabled;
}
public boolean isBluetoothEnabled() {
return isBluetoothEnabled;
}
// 클래스의 생성자는 private
private Computer(ComputerBuilder builder) {
this.HDD=builder.HDD;
this.RAM=builder.RAM;
this.isGraphicsCardEnabled=builder.isGraphicsCardEnabled;
this.isBluetoothEnabled=builder.isBluetoothEnabled;
}
//Builder Class
// static이 포인트.
// 빌더 클래스 생성자는 public으로 한다.
public static class ComputerBuilder{
// required parameters
private String HDD;
private String RAM;
// optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
// 필수값들은 파라미터로 받는다
public ComputerBuilder(String hdd, String ram){
this.HDD=hdd;
this.RAM=ram;
}
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
// 옵션 값들은 속상마다 메소드로 제공한다.
// 리턴값이 빌더 객체 자신
public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
this.isBluetoothEnabled = isBluetoothEnabled;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
public class TestBuilderPattern {
public static void main(String[] args) {
// Computer 객체를 얻기 위해 ComputerBuilder를 이용한다.
Computer comp = new Computer.ComputerBuilder("500 GB", "2 GB") //필수값은 파라미터로 넣어줌.
.setBluetoothEnabled(true) //옵션값은 메서드로 제공.
.setGraphicsCardEnabled(true)
.build();
}
https://velog.io/@jaeyunn_15/Design-Pattern-%EB%B9%8C%EB%8D%94-%ED%8C%A8%ED%84%B4Builder-Pattern