Jun4928 / wanted-pre-onboarding-challenge-BE-task-JAN.2023

JAN.2023 wanted 프리온보딩 챌린지 BE 사전과제
29 stars 36 forks source link

사전과제 제출 #13

Open ekek54 opened 1 year ago

ekek54 commented 1 year ago
  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요

    import { Request, Response, NextFunction } from "express";
    import BadRequestException from "../Common/Exceptions/BadRequest.Exception";
    import ResultService from "./Result.Service";
    
    class ResultController {
      resultService: ResultService;
    
      constructor(resultService: ResultService) {
        this.resultService = resultService;
        this.formResult = this.formResult.bind(this);
      }
    
      async formResult(req: Request, res: Response, next: NextFunction) {
        const { formId } = req.params;
        if (!formId || typeof formId !== "string") {
          next(new BadRequestException());
          return;
        }
    
        try {
          await this.resultService.init(formId);
          const result = this.resultService.formResult();
          res.status(200).json(result);
        } catch (error) {
          next(error);
        }
      }
    }
    
    export default new ResultController(new ResultService());
    • 최근 진행한 Express를 이용한 프로젝트에서의 Controller 코드입니다. 이외의 대부분의 코드를 OOP로 작성하였는데, 함수형 프로그래밍에 대해 학습하고 나면 위의 코드들을 어떻게 개선해 나갈 수 있을지 또한 어떤 이점을 챙길 수 있을지 궁금하고 기대가되어 공유하였습니다.
  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

    정의

    • 간단한 구조로 개발자에게 많은 경험을 요구하지 않기에, 백엔드 아키텍처로 가장 널리 사용된다.
    • 일반적으로 Presentaion, Business, Persistence 순서의 계층들로 구성되며 프로젝트 규모에따라 계층이 병합되거나 늘어날 수 있다.

    계층별 역할

    • Presentation: 유저 인풋에 대한 처리와 유저에게 정보를 보여주는 역할
    • Business: Presentation으로 부터 넘어온 인풋에 비즈니스 로직을 처리하고 이를 Persistence로 넘긴다.
    • Persistence: 데이터베이스와 상호작용

    계층간 격리

    • 각 계층은 기본적으로 닫혀있으며 이는 다른 계층으로 이동할 때는 바로 아래 계층을 거쳐서 순서대로 이동해야 함을 의미한다.
    • 이렇게 계층이 닫혀있는 이유는 한 계층의 변화의 전파를 최소화하기 위함이다.
    • 예를들어, Presentation에서 Persistence 계층으로 직접 접근한다면 더 간단하지만 Persistence 계층에 변화가 생길 때 Business 뿐만아니라 Presentation 계층에도 영향을 주게된다. 이런한 구조는 변화에 대처하기 힘들어진다.
  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

    • 컴포넌트가 의존성을 내부에서 직접 생성하는 것이 아닌 외부에서 주입 받도록 하는 디자인 패턴
    • 의존성을 외부에서 주입받기에 의존성이 있는 요소를 쉽게 대체 할 수 있어 해당 요소의 테스트를 쉽게할 수 있도록 한다.
    • 요소간 의존성을 줄일 수 있어 의존성 있는 요소의 변화나 혹은 대체되었을 때 이로인한 영향을 줄일 수 있어 유지보수에 유리하다.
  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

    • 함수 - 일급 객체:
      • JS에서 함수는 변수에 담을 수 있고, 인자로 전달할 수 있으며 반환값으로 전달할 수 있는 일급 시민이다.
      • 즉, 함수가 다른 함수의 인자로 사용되고 함수의 리턴값이 함수가 될 수 있고 함수가 변수에 저장될 수 있다.
    • 고차 함수:
      • JS에는 map, filter, reduce 와 같은 내장 고차함수가 존재한다.
      • 이들은 불변성을 지향하는 함수형 프로그래밍을 기반하여 개발자들이 함수형 스타일을 따를 수 있도록 한다.
    • 클로저:

      • 렉시컬 환경을 기억하는 함수이다.
      • 클로저가 FP에서 중요한 이유는 자신만의 폐쇄된 상태를 갖는 함수를 구현할 수 있기 떄문이다.
      • 아래의 예시처럼 함수를 하나의 부품처럼 찍어내는 function factory로 사용할 수 있다.
        
        // count라는 폐쇄된 유니크한 상태를 갖는 함수(counter)를 만들어내는 클로저 함수
        function createCounter() {
        let count = 0;
        return function() {
        count++;
        return count;
        }
        }

      const counter = createCounter(); console.log(counter()); // 1 console.log(counter()); // 2 console.log(counter()); // 3

    • 불변성:

      • 데이터가 생성된 시점이후로 변경되지 않음을 의미한다.
      • 부수 효과를 예방해 의도치 않은 결과를 예방하고 테스트와 디버깅을 쉽게 해주는 이점이 있다.
      • JS에서는 const로 원시 타입들의 불변성을 유지 할 수 있고, 원시 타입들이 아닌 것들은 object freezing을 통해 불변성을 지킬 수 있다.
        
        const person = {
        name: 'kim',
        age: 27,
        job: 'developer'
        };

      // person 객체에 불변성 부여 Object.freeze(person);

      // 아래와 같이 직접 프로퍼티 변경시 에러가 발생한다. person.age = 28;

      // 새로 나이를 업데이트 하기 위해서는 새로운 객체를 생성해야 한다. // 전개 연산자로 기존 객체를 깊은 복사한 후 수정할 값을 넣는다. const updatedPerson = Object.freeze({ ...person, age: 28 });

      console.log(person.age); // 27 console.log(updatedPerson.age); // 28

  5. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

    type SomeFunctionReturnString = () => string
    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
      // 해당 함수 내부를 구현해 주세요
      return new Promise<string>((resolve, reject) => {
        const cb = (): void => {
          try {
            const result = f();
            resolve(result);
          } catch (error) {
            reject(error);
          }
        };
        setTimeout(cb, seconds * 1000);
      });
    };
    const success = () => {
      return "successfully done";
    };
    const fail = () => {
      throw new Error("failed");
    };
    delay(success, 2)
      .then((res) => console.log(res))
      .catch((e) => console.log(e));
    delay(fail, 2)
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    결과값

    $ ts-node delay.ts
    successfully done
    Error: failed
  6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

    • 최근 프로젝트를 진행하며 좋은 코드를 작성하고자 OOP를 학습하고 적용하려 노력했습니다. 이번에는 FP를 학습해보고 다음 프로젝트에 적용해 볼 수 있으면 좋을 것 같습니다. Nest 프레임워크에서 FP를 어떻게 활용하고 테스트 코드를 어떻게 작성해야하는지 배워가고 싶습니다.