나는 전공자가 아니기 때문에 CS 관련 기반 지식이 매우 부족하다. IT 지식 뿐만 아니라 면접이나 포트폴리오 등 지금껏 내가 준비하지 못한 내용들이 이 책에 잘 정리되어있다고 하여 기본기가 탄탄한 개발자가 되기 위해 이 책을 기반으로 CS 전공지식을 정리해보려 한다! 👩🏻💻
1장에서는 라이브러리나 프레임워크의 기본이 되는 디자인 패턴이나 어떠한 방식으로 로직을 구성해야 하는지에 대한 프로그래밍 패러다임을 배운다.
🪄 여기서 잠깐!
∙ 프레임워크 : 다른 사람이 만들어둔 코드의 정해진 틀(frame) 속에서만 수동적으로 작업 해야 함 (모든 도구가 갖춰진 주방)
∙ 라이브러리 : 개발자가 작업을 진행할 때 필요한 기능을 찾고 능동적으로 가져와서 사용할 수 있음 (🫕🥣🔪용도에 따라 가져다 쓰는 도구)
디자인 패턴이란?
프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 '규약' 형태로 만들어 놓은 것
디자인 패턴은 프로그램을 개발하는 과정에서 빈번하게 발생하는 디자인 문제를 정리해서 상황에 따라 간편하게 적용할 수 있게 정리한 것이다. 디자인 패턴을 활용하면 단지 코드만 ‘재사용’하는 것이 아니라, 더 큰 그림을 그리기 위한 디자인도 재사용할 수 있다. 잘 활용만 하면 적지 않은 시간과 노력, 시행착오를 줄일 수 있다.
그렇다면 디자인 패턴 종류에는 뭐가 있을까?
싱글톤 패턴이란?
(싱글톤 패턴은 소프트웨어 디자인 패턴 중 하나로,) 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
인스턴스란?
인스턴스 = 클래스를 기반으로 생성된 객체
예를 들어, "자동차"라는 클래스가 있다면, 실제로 존재하는 자동차는 클래스를 인스턴스화하여 만든 "인스턴스"
자바스크립트에서는 리터럴 {}
또는 new Object
로 객체를 생성하게 되면 다른 어떤 객체와도 같지 않기 때문에 이 자체만으로 싱글톤 패턴을 구현할 수 있다.
const obj1 = {
a: 27
}
const obj2 = {
a: 27
}
console.log(obj1 === obj2) // false
위 코드는 동일한 키와 값을 똑같이 지정했더라도 참조하는 주소값이 다르기 때문에 obj1과 obj2는 각각 유일하게 존재하는 서로 다른 객체이다.
var obj = {
a: 'hello',
b: function() {
alert(this.a);
}
};
이렇게 객체 리터럴을 사용한 것이 바로 싱글턴 패턴의 대표적인 예지만, 모든 속성이 다 공개되어 있다는 단점이 있기 때문에 비공개로 프로퍼티나 함수를 정의하는 게 제대로 된 싱글톤이다. 그 예시로 아래 코드를 보면,
var singleton = (function() {
var instance;
var a = 'hello';
function initiate() {
return {
a: a,
b: function() {
alert(a);
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = initiate();
}
return instance;
}
}
})();
var first = singleton.getInstance();
var second = singleton.getInstance();
console.log(first === second); // true
IIFE(즉시 실행 함수 표현)
로 비공개 변수를 가질 수 있게 만들어준다. 그리고 그 안에 instance변수와 initiate 함수를 만들어준다. initiate 함수 안의 내용이 실제 객체의 내용이다. 위의 obj 객체와 비교하면 a가 비공개 변수가 되었다.
IIFE로 즉시 반환되는 부분(return)을 보면, getInstance라는 메소드를 가진 객체를 반환하는데, getInstance 함수를 호출하는 순간 내부적으로 initiate 함수가 호출되고, instance에 아까 그 객체의 내용이 저장되고 동시에 반환된다. getInstance가 여러 번 호출됐을 경우에는 코드를 보시면 이미 instance 객체가 있는 경우에는 initiate를 거치지 않고 바로 반환하는 것을 알 수 있다.
first와 second 변수를 보면 두 번 다 getInstance 함수를 호출했는데, 결과적으로 두 변수는 같다. first 때 initiate된 객체를 second 때도 똑같이 반환받았기 때문이다. 즉, 아무리 호출해도 기존에 있던 객체는 복사되는 것도 아니고 그냥 그대로 반환된다. 싱글톤 패턴은 모듈 패턴을 변형한 디자인 패턴이다.
싱글톤을 언제 써야할 지 잘 모르겠다구요? 처음 네임스페이스를 만들 때 사용하면 된다! 예를 들어 게임을 만든다고 치면, 게임 객체를 싱글턴으로 만드는 것이다. 게임 내의 모든 것을 감싸고 있는 객체를 말이다. 게임을 실행했을 때 게임은 한 번만 켜져야하기 때문에 싱글톤이 적절하다.
앞서 설명한 싱글톤 패턴은 데이터베이스 연결 모듈에 많이 쓰인다.
여러 객체 생성으로 인해 다수의 클라이언트가 동시에 설정값이 변경되면 문제가 생기기 때문이다.
const URL = 'mongodb://localhost:####'
const createConnection = url => ({"url": url })
class DB {
constructor(url) {
if (!DB.instance) {
DB.instace = createConnection(url)
}
return DB.instance
}
connect(){
return this.instance
}
}
const a = new DB(URL)
const b = new DB(URL)
console.log(a===b) // true
이런식으로 데이터베이스를 연결하면 DB.instance
라는 하나의 인스턴스를 기반으로 a,b 를 만들기 때문에 인스턴스 생성 비용을 아낄 수 있다.
사실 싱글톤 패턴은 장점보다 단점이 훨씬 많다고 한다. 처음에는 단점이 매우 미묘하여 많은 개발자들이 싱글톤 패턴을 잘못 사용하게 된다고 하는데, 이 점을 주의깊게 읽어보자✨
가장 중요한 단점은 편의성 때문에 투명성을 희생한다는 것이다.
시간이 지날수록 싱글톤 객체에 접근하는 객체를 추적할 수 없게 된다. 그리고, 더 중요한 것은 싱글톤 객체의 프로퍼티를 수정하는 객체들도 추적할 수 없게 된다. 따라서 싱글톤 패턴이 한 번 프로젝트에 사용되기 시작하면, 더 많은 싱글톤 없이 프로젝트를 나아가는 것이 어려워진다고 한다.
그렇다면 싱글톤 패턴을 조금 더 투명하게 사용할 수는 없을까?
싱글톤 객체를 필요로 하는 객체에게 의존성 주입 방식으로 싱글톤 객체를 전달하면 좀 더 투명하게 사용할 수 있다.
클래스의 인터페이스가 자신의 의존성을 설명하게 되기 때문이다. 무슨 말이냐 하면, 클래스가 자신을 생성하기 위해 어떤 객체들을 필요로 하는지 명확하게 보여준다.
위의 그림처럼 메인 모듈이 '직접' 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자(dependency injector)가 이 부분을 가로채 메인 모듈이 '간접'적으로 의존성을 주입하는 방식이다.
이를 통해 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성이 떨어지게 된다.
단점이 더 많다고는 하지만, 싱글톤 패턴은 오직 유일한 객체를 통해서만 어떤 리소스에 접근해야 하는 제약이 있는 상황에서 유용하기 때문에 클래스를 사용하는 입장에서 실수로 여러 번 객체 생성을 시도하더라도 내부적으로 오직 하나의 객체만 생성되고 사용되어 동시성 문제를 해결해주는 측면에서 필요할 것이다.
📍 출처
https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS8616098823
https://www.zerocho.com/category/JavaScript/post/57541bef7dfff917002c4e86
https://cheershennah.tistory.com/223
https://bibi6666667.tistory.com/511
📍 참고하면 좋을 사이트
https://injae-kim.github.io/dev/2020/08/06/singleton-pattern-usage.html (예시가 좋음)
https://www.youtube.com/watch?v=lJES5TQTTWE (아무래도 영상이 최고!)