ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] 자바스크립트 디자인 패턴 1편 - 모듈 그리고 싱글톤
    frontend/javascript&web 2023. 9. 11. 21:15

     오늘은 자바스크립트 디자인 패턴에 대해서 이야기를 한번 해보려고 합니다. 우리는 때때로 개발을 진행할 수록 소스코드가 점점 더러워지고 가독성이 떨어지는 경우를 겪게 됩니다. 일을 하다보면 이러한 소스코드를 어떻게 깔끔하게 작성할 수 있을지 내 코드를 남이 보고 유지보수를 할때 어떻게 한눈에 알아볼 수 있을지에 대한 많은 고민을 하게 되었습니다.

     

     이때 저는 디자인 패턴을 다시 한번 전체적으로 공부를 하였고, 이를 통해 실제 업무 속에서 더 나은 가독성과 유지보수성을 가진 소스코드를 작성할 수 있게 되었습니다. 제가 실제로 자주 사용하는 디자인 패턴들을 왜? 어떻게? 언제? 라는 내용으로 얘기해보겠습니다.

     

    1. 모듈 패턴

     모듈 패턴은 전역 네임스페이스를 오염시키지 않고, 변수와 함수를 캡슐화 하기 위해 자주 사용합니다. 특히, 이 패턴을 통해 private처리를 할 부분과 public처리를 할 부분을 분기 할 수 있습니다.

    var Module = (function () {
    
        var privateVar = "";
    
        function privateMethod() {
            privateVar = "hello"
            console.log(privateVar);
        }
    
        return {
            publicMethod: function () {
                privateMethod()
            }
        }
    
    })();

     

     저는 모듈 패턴을 레거시 시스템을 개발할 때 혹은 특정 기능을 하는 라이브러리를 작성할 때 사용하곤 합니다. 특히, 레거시 시스템에서 가장 많이 사용합니다. 컴포넌트화가 안되는 상황에서 한 화면에 너무 많은 기능들이 붙어 있을때 이러한 기능들을 각각의 모듈 단위로 작성합니다. 이를 통해, 전역 네임스페이스를 오염시키지 않고, 변수를 외부로 노출 하지 않아 외부에서 임의로 값을 부여하는 것을 막을 수 있습니다.(클로저 개념) 또한, 유지보수시에도 해당 모듈만 수정하면 되기 때문에 상당히 효율적이라고 생각합니다.

     

    실제 Module을 콘솔에 찍어 보았을 때

    위와 같이 실제로 찍어보면 publicMethod만 외부로 노출 되는 것을 볼 수 있습니다. 아래는 publicMethod의 내부 모습입니다.

     

    privateMethod를 private하게 사용한 모습

    위와 같은 모듈 패턴을 사용하면 확장성도 충분히 보장할 수 있습니다.

    모듈 패턴 확장
    var MainModule = (function () {
      return {
        publicMethod: function () {
          return "accessed publicly!";
        },
      };
    })();
    
    var ExtendModule = (function (parentModule) {
      parentModule.newPublicMethod = function () {
        return "accessed from the extended module!";
      };
    
      return parentModule;
    })(MainModule || {});
    
    console.log(ExtendModule.newPublicMethod());

     위와 같이 상위 모듈을 전달받아 위와 같이 상위 모듈(MainModule)을 확장하여 확장된 모듈(EtxendModule)을 반환할 수 있습니다. 이처럼 모듈 패턴을 잘 활용한다면 소스코드를 구조화 하는데 많은 도움이 될 것이라고 생각합니다. 특히, 레거시 시스템에서는 더욱 더 큰 효과를 볼 수 있습니다.

     

    2. 싱글톤 패턴

     싱글톤 패턴은 특정 클래스의 인스턴스가 하나만 존재해야 될때 사용하는 패턴입니다. 주로, 다양한 상태관리를 하는데 있어서 사용되곤 합니다. 특히, 데이터베이스 연결에서 자주 사용하곤 합니다. 전역상태관리 혹은 스타일컴포넌트와 같은 라이브러리도 이러한 싱글톤패턴의 개념이 적용되어 있을거라고 생각합니다. 기본 구조는 아래와 같습니다.

    var Singleton = (function () {
      var instance;
    
      function createInstance() {
        return { name: "Singleton Instance" };
      }
    
      return {
        getInstance: function () {
          if (!instance) {
            instance = createInstance();
          }
          return instance;
        },
      };
    })();
    
    
    var instance1 = Singleton.getInstance();
    var instance2 = Singleton.getInstance();
    console.log(instance1 === instance2);

     위와 같이 여러번 호출해도 동일한 인스턴스를 반환하는 결과를 얻으실 수 있으실 겁니다. 이러한 싱글톤 패턴은 어플리케이션의 설정을 관리하는 객체 혹은 데이터베이션 연결을 관리하는 객체 만들 때 주로 사용합니다. 

    앱 설정 예시
    var AppSettings = (function () {
      var _instance;
    
      function createInstance() {
        var defaultSettings = {
          appName: "My App",
          version: "1.0",
        };
    
        return {
          get: function (name) {
            return defaultSettings[name];
          },
          set: function (name, value) {
            defaultSettings[name] = value;
          },
        };
      }
    
      return {
        getInstance: function () {
          if (!_instance) {
            _instance = createInstance();
          }
          return _instance;
        },
      };
    })();
    
    var settings1 = AppSettings.getInstance();
    var settings2 = AppSettings.getInstance();
    
    console.log(settings1 === settings2); // true
    settings1.set("version", "1.1");
    console.log(settings2.get("version")); // "1.1"
    DB커넥션 예시
    const mysql = require("mysql");
    
    class Database {
      constructor() {
        if (Database.instance) {
          return Database.instance;
        }
        Database.instance = this;
    
        this.connection = mysql.createConnection({
          host: "localhost",
          user: "root",
          password: "password",
          database: "testdb",
        });
    
        this.connection.connect((error) => {
          if (error) {
            console.error("Error connecting to the database:", error);
            return;
          }
          console.log("Connected to the database");
        });
      }
    
      query(sql, args) {
        return new Promise((resolve, reject) => {
          this.connection.query(sql, args, (error, rows) => {
            if (error) {
              reject(error);
              return;
            }
            resolve(rows);
          });
        });
      }
    
      close() {
        return new Promise((resolve, reject) => {
          this.connection.end((error) => {
            if (error) {
              reject(error);
              return;
            }
            resolve();
          });
        });
      }
    }
    
    module.exports = new Database();

     위와 같이 하나의 인스턴스만 유지해서 여러번의 연결 등을 방지하여 불필요한 리소스를 절약하는데 도움이 되는 패턴이 싱글톤 패턴입니다.

     

     오늘은 제가 실제 업무 개발을 할때 자주 사용하는 디자인 패턴 중 두 가지 모듈과 싱글톤에 대해서 알아보았습니다. 많은 여러분에게 도움이 되었으면 좋겠습니다. 특히, 가장 근본이라고 생각하는 html과 js만으로 개발을 해나가고 있는 누군가에게 많은 도움이 되었으면 좋겠습니다.

     

     

     

     개인적으로 생각하는 것들을 좀 해보자면, 최근에는 다양한 프레임워크 아래에서 어느정도 정형화된 개발들을 많이 해오고 있는 것 같습니다. 물론 이러한 프레임워크 속에서도 올바른 정답을 찾기 위해 수많은 방법들이 다양한 방법으로 사람들에게 소개 되고 있습니다. 또한, 프론트엔드 패러다임은 생각보다 더 빠르게 변화하는것 같습니다. 우리는 이러한 프론트엔드 시장에서 살아남기 위해서는 최신 프레임워크를 끊임없이 쫓는것도 중요하지만, 이와 더불어 오히려 기초로 돌아가 어느 프레임워크에도 유연하게 대응할 수 있는 기초를 다지는 것도 중요하다고 생각합니다.

     

      개인적으로 프레임워크들이 너무 빠르게 변화하고 있고 주류를 이루고 있는 리액트 또한 이전에 비해 많이 비대해진 느낌도 많이 받습니다. 이러한 영향으로 새로운 프레임워크들도 주목받고 있는거 같습니다. 물론 메타가 현재 메인테이너로 있기 때문에 리액트가 끊임없이 유지보수가 되고 있지만 언젠간 리액트도 고전이 되는 날이 있겠죠. 이미 고전일수도 있다고 생각합니다. 그렇기 때문에 저는 요즘 더욱더 기초가 더 중요하다고 생각 됩니다.

    반응형

    댓글

Designed by Tistory.