디자인 패턴이란 프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 '규약'형태로 만들어 놓은 것을 의미한다.
자바스크립트의 싱글톤 패턴
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴이다. 하나의 클래스를 기반으로 여러 개의 개별적인 인스턴스를 만들 수 있지만, 그렇게 하지 않고 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 이를 기반으로 로직을 만드는데 쓰이며, 보통 데이터베이스 연결 모듈에 많이 사용한다.
자바 스크립트에서는 리터럴{} 또는 new Object로 객체를 생성하게 되면 다른 어떤 객체와도 같지 않기 때문에 이자체만으로 싱글톤 패턴을 구현할 수 있다.
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this
}
return Singleton.instance
}
getInstance() {
return this
}
}
const a = new Singleton()
const b = new Singleton()
console.log(a === b) // true
앞의 코드는 하나의 인스턴스를 가지는 싱클톤 클래스를 구현한 모습이다.
데이터베이스 연결 모듈
앞서 설명한 싱글톤 패턴은 데이터베이스 연결 모듈에 많이 쓰인다.
const URL = ""
const createConnection = url =>({"url":ur;})
코드를 추가하여 DB.instance라는 하나의 인스턴스를 기반으로 a, b를 생성하는 것을 볼 수 있다.
이를 통해 테이터베이스 연결에 관한 인스턴스 생성 비용을 아낄 수 있다.
자바에서의 싱글톤 패턴
class Singleton {
private static class singleInstanceHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return singleInstanceHolder.INSTANCE;
}
}
public class HelloWorld{
public static void main(String []args){
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println(a.hashCode());
System.out.println(b.hashCode());
if (a == b){
System.out.println(true);
}
}
}
/*
705927765
705927765
true
싱글톤 패턴은 Node.js에서 MongoDB 데이터베이스를 연결할 때 쓰는 mongoose모듈에서 볼 수 있다.
MySQL의 싱글톤 패턴
메인 모듈에서 데이터베이스 연결에 관한 인스턴스를 정의하고 다른 모듈인 A 또는 B에서 해당 인스턴스를 기반으로 쿼리를 보내는 형식이다.
TDD(Test Driven Development)를 할 때 걸림돌이 된다. TDD를 할 때 단위 테스트를 주로 하는데, 단위 테스트는 테스트가 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할수 있어야 한다.
싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 독립적인 인스턴스를 만들기가 어렵다.
의존성 주입
싱글톤 패턴은 사용하기가 쉽고 굉장히 실용적이지만 모듈 간의 결합을 강하게 만들 수 있다는 단점이 있다. 이때 의존성 주입을 통해 모듈간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다.
의존성 주입의 장점과 단점, 주입 원칙
팩토리 패턴은 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴
자바스크립트의 팩토리 패턴
숫자를 전달하거나 문자열을 전달함에 따라 다른 타입의 객체를 생성하는 것을 볼 수 있습니다. 즉, 전달받은 값에 따라 다른 객체를 생성하며 인스턴스의 타입 등을 정합니다.
커피 팩토리를 기반으로 라떼 등을 생산하는 코드로 예를 들어보자.
class CoffeeFactory {
static createCoffee(type) {
const factory = factoryList[type]
return factory.createCoffee()
}
}
class Latte {
constructor() {
this.name = "latte"
}
}
class Espresso {
constructor() {
this.name = "Espresso"
}
}
class LatteFactory extends CoffeeFactory{
static createCoffee() {
return new Latte()
}
}
class EspressoFactory extends CoffeeFactory{
static createCoffee() {
return new Espresso()
}
}
const factoryList = { LatteFactory, EspressoFactory }
const main = () => {
// 라떼 커피를 주문한다.
const coffee = CoffeeFactory.createCoffee("LatteFactory")
// 커피 이름을 부른다.
console.log(coffee.name) // latte
}
main()
CoffeeFactory 라는 상위 클래스가 중요한 뼈대를 결정하고 하위 클래스인 LatteFactory가 구체적인 내용을 결정하고 있다. LatteFactory에서 생성한 인스턴스를 CoffeeFactory에 주입하고 있다. 또한, CoffeeFactory를 보면 static으로 createCoffee() 정적 메서드를 정의한 것을 알 수 있는데, 정적 메서드를 쓰면 클래스의 인스턴스 없이 호출이 가능하며 메모리를 절약할 수 있고 개별 인스턴스에 묶이지 않으며 클래스 내의 함수를 정의하는 장점이 있다.
객체의 행위를 바꾸고 싶은 경우 '작접'수정하지 않고 전략이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴.
우리가 어떤 것을 살 때 네이버페이, 카카오페이 등 다양한 방법으로 결제하듯이 어떤 아이템을 살 때 루나카드로 사는 것과 카카오 카드로 사는 것을 구현한 예제 입니다. 결제 방식의 전략만 바꿔서 두 가지 방식으로 결제하는 것을 구현했습니다.
passport의 전략 패턴
Passport는 Node.js에서 인증 모듈을 구현할 때 쓰는 미들웨어 라이브러리로, 여러 가지 '전략'을 기반으로 인증할 수 있게 합니다. 서비스 내의 회원가입된 아이디와 비밀번호를 기반으로 인증하는 LocalStrategy 전략과 페이스북, 네이버 등 다른 서비스를 기반으로 인증하는 OAuth 전략 등을 지원합니다.
주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려 주는 디자인 패턴
여기서 주체란 객체의 상태 변화를 보고 있는 관찰자이며, 옵저버들이란 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들을 의미한다.
트위터 처럼 어떤 사람인 주체를 팔로우 했다면 주체가 포스팅을 올리게 되면 알리밍 팔로워에게 가는 패턴. 또한, 옵저버 패턴은 이벤트 기반 시스템에 사용하며 MVC패턴에도 사용된다. 예를 들어 주체라고 볼 수 있는 모델에서 변경 사항이 생겨 update() 메서드로 옵저버인 뷰에 알려주고 이를 기반으로 컨트롤러 등이 작동.
자바스크립트에서의 옵저버 패턴
프록시 객체를 통해 구현할 수도 있다.
프록시 객체
어떠한 대상의 기본적인 동작(속성, 접근, 할당, 순회, 열거, 함수 호출 등)의 작업을 가로챌 수 있는 객체를 뜻하며, 자바스크립트에서 프록시 객체는 두 개의 매개변수를 가진다.
Vue.js 3.0의 옵저버 패턴
프런트엔드에서 많이 쓰는 프레임워크 Vue.js 3.0에서 ref나 reactive로 정의하면 해당 값이 변경되었을 때 자동으로 DOM에 있는 값이 변경되는데, 이것은 옵저터 팬턴을 이용하여 구현한 것이다.
프록시 패턴
대상 객체에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴
프록시 서버
서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 가르킨다.
프록시 서버로 쓰는 ngix
ngnix는 비동기 이벤트 기반의 구조와 다수의 연결을 효과적으로 처리 가능한 웹 서버이며, 주로 Node.js 서버 앞단의 프록시 서버로 활용된다.
Node.js의 창시자인 라이언 달은 이렇게 말했다
"Node.js의 버퍼 오버플로우 취약점을 예방하기 위해서는 nginx를 프록 ㅓ버로 앞단에 놓고 Node.js를 뒤쪽에 놓는 것이 좋다."라고 하였다.
프록시 서버로 쓰는 CloudFlare
CloudFlare는 전 세계적으로 분산된 서버가 있고 이를 통해 어떠한 시스템의 콘텐츠 전달을 빠르게 할 수 있는 CDN 서비스 입니다. 이 점으로는 DDOS 공격 방어, HTTPS 구축이 있다.
DDOS 공격 방어
짧은 시간 동안 네트워크에 많은 요청을 보내 네트워크를 마비시켜 웹 사이트의 가용성을 방해하는 사이버 공격 유형이다. 하지만 Cloudflare는 의심스러운 트래픽, 특히 사용자가 접속하는 것이 아닌 시스템을 통해 오는 트래픽을 자동으로 차단해서 보호한다.
HTTPS 구축
HTTPS를 구축할 때 인증서를 기반으로 구축할 수도 있다. 하지만 CloudFlare를 사용하면 별도의 인증서 없이 더 손쉽게 구축할 수 있다.
CORS와 프런트엔드의 프록시 서버
CORS(Cross-Origin Resource Sharing)는 서버가 웹 브라우저에서 리소스를 로드할 때 다른 오리진을 통해 로드하지 못하게 하는 HTTP 헤더 기반 메커니즘이다.
프런트엔드 개발 시 프런트엔드 서버를 만들어서 백엔드 서버와 통신할 때 주로CORS에러를 마주치는데, 이를 해결하기 위해 프론트 엔드에서 서버를 만들기도 합니다.
이터레이터를 사용하여 컬렉션의 요소들에 접근하는 디자인 패턴
이를 통해 순회할 수 있는 여러 가지 자료형의 구조와는 상관없이 이터레이터라는 하나의 인터페이스로 순회가 가능하다.
즉시 실행 함수를 통해 private, public 같은 접근 제어자를 만드는 패턴을 말한다.
자바스크립트는 접근 제어자가 존재하지 않고 전역 범위에서 스크립트가 실행된다. 그렇기 때문에 노출모듈 패턴을 통해 접근 제어자를 구현하기도 한다.
모델(Model), 뷰(View). 컨트롤러(Controller)로 이루어진 디자인 패턴. 애플리케이션의 구성 요소를 세 가지 역할로 구분하여 개발 프로세스에서 각각의 구성 요소에만 집중해서 개발할 수 있습니다. 재사용성과 확장성이 용이하지만 애플리케이션이 복잡해질수록 모델과 뷰의 관계가 복잡해지는 단점이 있다.
모델
모델은 애플리케이션의 데이터인 데이터베이스, 상수, 변수 등을 뜻한다.
뷰
inputbox, checkbox, textarea 등 사용자 인터페이스 요소를 나타낸다.즉 모델을 기반으로 사용자가 볼 수 있는 화면을 뜻한다.
컨트롤러
컨트롤러는 하나 이상의 뷰를 잇는 다리 역할을 하며 이벤트 등 메인 로직을 담당한다. 또한, 모델과 뷰의 생명주기도 관리하며, 모델이나 뷰의 변경 통지를 받으면 이를 해석하여 각각의 구성요소에 해당 내용에 대해 알려준다.
MVC 패턴으로부터 파생되었으며 MVC에서 C에 해당하는 컨트롤러가 프레젠터로 교체된 패턴
MVC의 C에 해당하는 컨트롤러가 뷰 모델로 바뀐 패턴. 여기서 뷰모델은 뷰를 더 추상화한 계층이며, MVC와 다르게 커맨드와 데이터 바인딩을 가지는 것이 특징. 양방향 데이터 바인들을 지원하며 UI를 별도의 코드 수정 없이 재사용할 수 있고 단위 테스팅하기 쉽다는 장점이 있다.
BMV, 구글, 루이비통 등에서 사용.
프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론
선언형 프로그래밍이란 무서을 풀어내는가에 집중하는 패러다임이며, "프로그램은 함수로 이루어진 것이다."라는 명제가 담겨 있는 패러다임이기도 하다.
함수형 프로그래밍은 선언형 패러다임의 일종이다.
순수 함수
출력이 입력에만 의존하는 것을 의미한다.
pure 함수는 들어오는 매개변수 a, b에만 영향을 받는다. 만약 a, b말고 다른 전역 변수 c 등이 이 출력에 영향을 주면 순수 함수가 아니다.
고차 함수
함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것을 말한다.
일급객체
고차 함수를 쓰기 위해서는 해당 언어가 일급 객체라는 특징을 가져야 함 그 특징은 다음과 같습니다.
객체들의 집합으로 프로그램의 상호 작용을 표현하며 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식을 말한다.
객체지향 프로그래밍의 특징
추상화, 캡슐화, 상속성, 다형성이라는 특징이 있다.
추상화
복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려내는 것을 의미한다.
캡슐화
객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것을 말한다.
상속성
상위 클래스의 특성을 하위 클래스가 이어받아서 재사용하거나 추가, 확장하는 것을 말한다. 코드의 재사용, 계층적인 관계 생성, 유지 보수에서 중요하다.
다형성
하나의 메서드나 클래스가 다양한 방법으로 동작하는 것을 말한다. (오버로딩, 오버라이딩)
오버로딩
같은 이름을 가진 메서드를 여러 개 두는 것을 말한다.
오버라이딩
주로 메서드 오버라이딩을 말하며 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의하는 것을 의미한다.
설계 원칙
객체지향 프로그래밍을 설계할 때는 SOLID 원칙을 지켜주어야 합니다. S는 단일 책임 원칙,O는 개방-폐쇄 원칙,L은 리스코프 치환 원칙,I는 인터페이스 분리 원칙,D는 의존역전 원칙을 의미한다.
단일 책임 원칙
모든 클래스는 각각 하나의 책임만 가져야 하는 원칙.
개방-폐쇄 원칙
유지 보수 사항이 생긴다면 코드를 쉽게 확장할 수 있도록 하고 수정할 때는 닫혀 있어야 하는 원칙.
리스코프 치환 원칙
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 하는 것을 의미
인터페이스 분리 원칙
하나의 일반적인 인터페이스보다 구체적인 여러 개의 인터페이스를 만들어야 하는 원칙을 말한다.
의존 역전 원칙
자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 둘어 변하기 쉬운 것의 변화에 영향받지 않게 하는 원칙
로직이 수행되어야 할 연속적인 계산 과정으로 이루어져 있다.
프로그래밍에서 정해진 답은 없다. 비즈니스 로직이나 서비스의 특징을 고려해서 패러다임을 정하는 것이 좋다. 상황과 맥락에 따라 패러다임 간의 장점만 취해 개발하는 것이 좋다.