Giter Club home page Giter Club logo

wanted-pre-onboarding-challenge-be-task-jan.2023's People

Contributors

jun4928 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

wanted-pre-onboarding-challenge-be-task-jan.2023's Issues

사전 과제 제출

사전 과제

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

/**
 * Nest.Js에서 계정을 생성할 때 게정 생성 일자와 암호화를 적용하는 로직
 * 보통 이런 부분은 service 로직이나, 기타 영역에서 처리해야 하는데 Nest.Js에서는 스키마에 아래처럼 저장 전 핸들링을 할 수 있다는 부분이 마음에 들었습니다.
 */
AccountSchema.pre<AccountDocument>("save", function (next: Function) {
    const saltRound: number = 10;
    const accesDate: Date = new Date(new Date().getTime() + 9 * 60 * 60 * 1000);

    this.createdAt = accesDate;
    this.updatedAt = accesDate;

    bcrypt.genSalt(saltRound, (err, salt) => {
        if (err) return next(err);

        bcrypt.hash(this.password, salt, (err, hash) => {
            if (err) return next(err);
            this.password = hash;
            next();
        });
    });
});

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  • 보편적인 구조이며, 각 레이어들은 수평적으로 구조화 되어 있다.
  • 보통 제일 많이 사용하는 형태는 4개의 레이어로 구성되어 있다.
    • Presentation
      • UI나 브라우저 담당 영역
    • Business
      • 각 요청에 대한 비즈니스 로직 담당
    • Persistence
      • 데이터베이스에 접근해서 처리하는 영역
    • Database
      • 데이터베이스 영역
  • 장점
    • 시스템 분석의 용이
    • 변화에 대한 영향력을 한정할 수 있어 코딩이나 테스트를 계층별로 가능
    • 계층간 구조를 나누어 재사용성이 높음
  • 단점
    • 계층 구분이 어렵고, 잘못 구분 시 수정이 번번히 일어남
    • 설계 시 씽크홀 안티 패턴을 주의해야 한다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 개념
    • 특정 객체들 사이에 인터페이스를 두고, 클래스 레벨에서 의존관계가 고정되지 않도록 하고 런타임 시 관계를 동적으로 주입하는 것
  • 필요한 이유
    • 특정 클래스(2개 이상)들이 강하게 결합되는 문제
    • 객체들 간의 관계가 아닌 클래스 간의 관계가 맺어지는 문제
    • 이들을 해소하기 위해 DI를 사용

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

//Typescript를 주로 사용하며, 순수함수, 비상태,불변성, 선언형, 1급 객체와 고차 함수 등을 사용합니다.
//Next.Js, Nest.Js 두 프레임워크를 사용하여 개발을 하며, 함수형 프로그래밍을 지향합니다.

let sevenCntPool: number[] = Object.keys(appearCnt).map((item: string) => Number(item)).filter((item: number) => appearCnt[item] === 1);

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
				// 해당 함수 내부를 구현해 주세요
				return new Promise((resolve, reject) =>
            setTimeout(() => { 
                try {
                    resolve(f());
                }
                catch (e) {
                    reject(e)
                }
            }, seconds*1000),
        );
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

`$ ts-node delay.ts
successfully done
Error: failed`

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • 개발을 내려놓은지 꽤 오랜 시간이 흘렀고, 취미로 개발을 하다가 다시 개발업을 해보고 싶어서 이번에 참여하게 되었습니다.
  • 개인 서비스 개발을 하는데 방법론적인 부분과 언어에 대한 이해도를 올려보려고 학습에 참여하게 되었습니다.
  • 열심히 해보겠습니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요
 public SubscribedChannelListDto getAllSubscribeByChannelId(Long channelId) {
        Channel channel = channelService.getChannelByChannelId(channelId);
        List<Subscribe> subscribeList = subscribeRepository.findAllByChannel(channel);
        SubscribedChannelListDto subscribedChannelListDto = new SubscribedChannelListDto();
        subscribedChannelListDto.setId(channel.getId());
        subscribeList
                .stream()
                .forEach(subscribe -> {
                    subscribedChannelListDto.addSubscribedChannelId(subscribe.getSubscribedChannel().getId());
                });

        return subscribedChannelListDto;

    }

사이드 프로젝트로 제작했던 유튜브 클론코딩의 서비스로직입니다. 원래는 OOP방식으로 로직을 전부 구현을 했었는데, 이 프로젝트를 진행하면서 함수형 프로그래밍에 대한 매력을 알게되었습니다. 현재 적용된 소스코드는 간단한 코드들만 인터넷에서 보고 함수형 프로그래밍을 적용해봤는데 체계적으로 학습 후에는 위 코드 뿐만 아니라 서비스 로직등을 어떻게 더 고도화 시킬 수 있는지 궁금해서 공유했습니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
  • Layered Architecture는 소프트웨어 개발에서 가장 일반적으로 널리 사용되는 아키텍처입니다. 구성되는 계층의 숫자에 따라 N 계층 아키텍처 (N-tier Architecture) 라고도 합니다.
  • 일반적인 경우 4개의 레이어로 구분됨
    • Presentation Layer
      • 사용자의 데이터 전달이 주 목적
      • 대표적인 구성요소로는 View와 Controller가 있음
      • 비즈니스 로직이 어떻게 구성되어있는지 알 필요 없
    • Business Layer
      • 비즈니스 로직 수행이 주 관심사임
      • 수행한 로직 결과가 어떻게 출력되는지 어디서 데이터가 들어오는지는 관심 없고 로직만 수행
      • Service와 Domain Model등이 있
    • Persistence Layer
      • 어플리케이션 영속 구현을 위해 데이터 출처와 그 데이터를 가져오고 다루는것이 주 관심사임
      • 대표적인 구성요소로는 Repository와 DAO가 있
    • Database Layer
      • MySQL, MariaDB, PostgreSQL, MongoDB등 데이터베이스가 위치한 계층을 의미
  • 과도한 의존성을 방지하기 위한 구조임
  • 계층은 캡슐화되어 있고, 단일 책임을 갖고 특정 레이어는 다른 레이어에 영향을 주지 않고 변경될 수 있다.
  • ex) 서비스와 db를 직접 연결한다면 db에 변경사항이 일어났을때 연관된 서비스 로직까지 전부 변경되야하는 문제들이 발생하는것을 막기 위해 레이어를 여러 단계로 나누고 하위 레이어에만 연결하는 것이다.
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    자바 코드를 예시로 들었을 때
public class Store {

    private Pencil pencil;

    public Store() {
        this.pencil = new Pencil();
    }

}

위와같이 연필을 판매하는 가게 클래스가 있다해보겠습니다. 위 코드에서의 문제점은 Store클래스가 pencil클래스와 강하게 결합되어있는것 입니다.
가령 pencil내부의 코드가 수정되면 아래에 구현된 Store내부의 메소드들도 전부 바뀌어야합니다.
그 문제를 해결하기 위해 필요한게 다형성 즉 인터페이스입니다.

public interface Product {

}

public class Pencil implements Product {

}

연필을 위 코드와 같이 상품이라는 인터페이스를 상속받도록 해줍니다.
그럼

public class Store {

    private Product product;

    public Store(Product product) {
        this.product = product;
    }

}

그럼 Store클래스의 코드도 위처럼 변하게되는데 이렇게 되면, 프로그래밍을 하는 입장에서는 product내부의 객체가 연필, 펜, 지우개 등등의 값으로 변경되도 코드의 변경이 거의 없게됩니다.
그리고 위의 객체는 어플리케이션의 실행시점에 등록된 객체로 적절히 받아지고 이러한 이유로 이를 DI(Dependency Injection)이라 부릅니다. 필요한 의존성을 프레임워크에 의해 주입받기 때문이죠.

  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    사용 언어: Java
    Stream API를 주로 이용합니다.
public List<CommentDto> getComments(Long videoId) {
        List<Comment> commentList = commentRepository.findAllByVideoId(videoId);
        List<CommentDto> commentDtoList = commentList.stream().map(comment -> {
                    CommentDto commentDto = new CommentDto(comment);
                    return commentDto;
                })
                .collect(Collectors.toList());
        return commentDtoList;
    }

위의 예제는 Comment 리스트로 stream을 생성한 뒤, 각각의 댓글을 CommentDto 로 변환한 뒤 CommentDto리스트를 반환하는 코드입니다.

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

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
     return new Promise((resolve, reject)=>{
       setTimeout(()=>{
           try{
               resolve(f());
            }
           catch(e){
             reject("Error: " + f());
           }
       }, 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));
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  • 함수형 프로그래밍에 대한 매력을 느꼇지만, 아직 서비스에 제대로 적용할정도의 학습 수준은 아닌것같아 체계적인 학습 후 이후 만드는 서비스에 도입해보고싶습니다.
  • 다른 개발자분들을 경험해보고싶습니다. 재직했던 회사에서 백엔드 개발자가 저 한명이였고, 이후 학생들을 가르치는 역할을 했었기에 누군가에게 피드백을 받거나 내가 작성한 코드가 더 개선될 여지가 있는지 등에 대한 토론을 정말 해보고싶었지만 기회가 없었습니다. 다른 개발자분들과 함께 성장해 나가고싶습니다.
  • 이력서를 재검토 해보고싶습니다. 원티드가 가장 신뢰하는 채용 플랫폼이라 원하는 회사들에 지원했지만, 대부분 탈락하고 추후에 또 지원했지만 거의 대부분 탈락했습니다. 아무래도 열심히 공부하는것과는 별개로 이력서 부분에도 문제가 있는것같아 제대로 다시 작성해보고싶습니다.
    image

사전과제 제출

  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를 어떻게 활용하고 테스트 코드를 어떻게 작성해야하는지 배워가고 싶습니다.

[사전과제제출]

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    언어 상관없음
    어떤 로직이든 상관없음
    단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요
// 사이드프로젝트의 일환으로 작성한 코드입니다.
// -- 필요하지 않은 객체의 인스턴스화를 최소화 하기위하여 static method로 만들어 보았습니다.
// -- 해당 방법이 옳은 방법인지 더 나은 방법이 있는지 궁금합니다.
public class ConvertQuestionImgae {

    public static Question JpgToBase64 (Question question){

        String basicPath = "/home/kai/mocktest/qpaper";
        byte[] fileContent = null;
        try {
            fileContent = FileUtils.readFileToByteArray(
                    new File(basicPath+ "/"
                            + question.getYy() + "/"
                            + question.getExamCd() + "/"
                            + question.getSubCd() + "/"
                            + question.getQuestionPath()
                    )
            );
        }catch (Exception e) {e.printStackTrace();}

        String encodedString = Base64.getEncoder().encodeToString(fileContent);
        question.setImgBase(encodedString);
        return question;
    }
}
  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    -> 표현계층, 비지니스계층, 영속계층 등의 여러 개층으로 나누어진 아키텍쳐로
    일반적인 웹에서 각계층의 역할은

    1. 표현계층 : URL에 대한 비지니스로직 매핑, 응답을 담당합니다.
    2. 비지니스계층 : 실질적인 로직을 수행하는 계층으로 업무에대한 프로세스를 수행합니다.
    3. 영속계층 : DB와 연결 및 CRUD를 담당합니다.

  2. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    -> 의존성 주입은 외부에서 자동적으로 인스턴스화를 진행하는 것입니다.
    -> 필요한 이유는 서비스의 확장에 따른 부작용을 최소화 하기 위해서 입니다.

  3. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    -> 자바 StreamAPI

    • 스트림 생성, 중간 연산, 최종 연산 으로 이루어져 있습니다.

    @Override
    public List<List<Question>> getQuestion(Map<String, Object> subjectParams) {
    
    	return Arrays.asList(((String) subjectParams.get("subCds")).split(",")).stream()
    			.map(subCd -> new Subject(subjectParams,subCd))
    			.map(subject -> dao.getQuestion(subject))
    			.collect(Collectors.toList());
    }
    
    

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

    type SomeFunctionReturnString = () => string

        function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
            // 해당 함수 내부를 구현해 주세요
            const execute = (() => {
                try {
                return f();
                } catch (error) {
                return "Error: failed";
                }
            })();
            return new Promise((resolve) => setTimeout(resolve, seconds * 1000, execute));
        }

        const success = () => {
          return "successfully done";
        };

        const fail = () => {
          throw new Error("failed");
        };

        delay(success, 2) // 2초 뒤에 successfully done 로그
          .then((res) => console.log(res))
          .catch((e) => console.log(e));

        delay(fail, 2) // 2초 뒤에 failed 로그
          .then((res) => console.log(res))
          .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    -> 강의를 통하여 스프링뿐이 아닌 백엔드 분야에서 보다 넓은시야를 가지고 이직할 수 있는 능력을 얻고 싶습니다.

사전 과제 제출

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

  • services에서 매개변수 params에 하나 이상의 key-value 객체를 입력받았을 때 업데이트 기능의 raw query가 바르게 동작하도록 구현한 코드인데 타입스크립트로 API를 구현한다면 어떤 방식으로 구현할 수 있는지 기대됩니다
const query = (params = {name : "이름", num : 1234}) => { 
      let setClauses = Object.entries(params).map( 
          ([key, value]) => {
              return typeof value === "string" ? `${key} = '${value}'` :  `${key} = ${value}`;
          });
      return `SET ${setClauses.join(', ')}`;
}; 

// "SET name = '이름', num = 1234"

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  1. 정의 : 코드의 구조를 더 체계적이고 효율적으로 구현하는 것
  2. 핵심 :
  • 단방향 의존성 : 각각의 레이어는 오직 자기보다 하위의 레이어에만 의존한다.
  • 관심사 분리(Seperation Of Concern, SOC) : 각 레이어 별 역할이 구분되어 명확하다. 역할의 중첩이 없다.
  1. 장점 :
  • 확장성 : 각 레이어가 서로 독립적이고 역할이 분명하므로 서로에게 끼치는 영향을 최소화하면서 확장하거나 수정할 수 있다.
  • 가독성 : 레이어가 완벽하게 분리되어 있고 역할이 명확하므로 가독성이 높아진다.
    코드 구조를 파악하기 쉽고 각 레이어의 코드의 목적이 명확하고 범위도 확실하기 때문이다.
  • 재사용성 : 레이어가 독립적이므로 business layer는 여러 다른 presentation layer에 적용될 수 있다.
  • 테스트 가능성 : 레이어가 나뉘는 것처럼 각 레이어의 테스트 코드도 명확하게 나눌 수 있으며, 명확하고 범위가 확실한 기능만을 테스트하기 쉽다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  1. 개념
  • 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴
  • 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고
    런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
  1. 필요성
  • 서로 다른 클래스 간 강하게 결합되어 있는 경우 유연성이 떨어지는 문제점이 있는데
    이를 해결하기 위해 필요하다

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

function solution(numbers) {
    return numbers.reduce((a, b)=> a+b, 0)/numbers.length
}
  • 정수 배열numbers를 입력받아 요소들의 평균을 반환하는 함수입니다
  • 함수형 프로그래밍의 핵심 개념의 하나로서, 입출력이 순수한 순수함수의 특징이 있습니다

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        return new Promise<string>((resolve, reject) => {
        setTimeout(()=>{
          try{
            resolve(f());
          }catch(e){
            reject(e);
          }
        }, seconds*1000);
      });
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • typescript와 nestjs 등 기술스택을 학습하고 실무 역량을 키울 수 있는 좋은 시간이 되었으면 좋겠습니다

사전과제 제출

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

설명 : 무중단 배포를 위한 스크립트 파일로, Github Actions에서 이 파일을 실행하도록 해서 docker compose 기반의 blue-green 배포 방식을 적용했습니다.
공유한 이유 : 쓰고 나서 잘 짠 것 같아 뿌듯해서!

#!/bin/bash

EXIST_BLUE=$(docker-compose -p image-blue -f /build/frontend/docker-compose.blue.yml ps | grep Up)

echo $EXIST_BLUE

if [ -z "$EXIST_BLUE" ]; then
  echo "Blue UP"
  docker-compose -p image-blue -f /build/frontend/docker-compose.blue.yml up -d
  BEFORE_COMPOSE="green"
  AFTER_COMPOSE="blue"
else
  echo "Green UP"
  docker-compose -p image-green -f /build/frontend/docker-compose.green.yml up -d
  BEFORE_COMPOSE="blue"
  AFTER_COMPOSE="green"
fi

sleep 10

EXIST_AFTER=$(docker-compose -p image-${AFTER_COMPOSE} -f /build/frontend/docker-compose.${AFTER_COMPOSE}.yml ps | grep Up)
if [ -n "$EXIST_AFTER" ]; then
  cp /build/frontend/nginx.${AFTER_COMPOSE}.conf /etc/nginx/sites-available/frontend
  nginx -s reload

  docker-compose -p image-${BEFORE_COMPOSE} -f /build/frontend/docker-compose.${BEFORE_COMPOSE}.yml down
  echo "$BEFORE_COMPOSE down"
fi

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

Layered Architecture는 말 그대로 계층이 있는 구조로, 계층별 역할을 구분하고 구분한 계층에서 담당한 일만 하도록 하는 구조입니다.
아키텍처가 적용된 예시로, 서버에서 사용자의 요청을 직접 받는 부분, 사용자의 요청을 통해 얻은 데이터로 특정 비즈니스 로직을 수행하는 부분, 비즈니스 로직을 수행하기 위해 DB에서 데이터를 조회하는 부분을 구분하여 각각 Controller, Service, Repository로 구분하고 코드를 분리하는 것을 들 수 있습니다.
사용자의 요청이 변경되는 경우 Controller를, 비즈니스 로직을 변경해야 할 경우 Service를, DB에서 다른 형태의 데이터를 조회해야 할 경우 Repository를 수정하면 되기 때문에 코드의 유지보수가 용이합니다. Service와 Repository의 코드가 합쳐져 있을 경우, Service 안의 다른 메소드에서 동일한 DB 데이터 조회를 진행할 때 중복되는 코드가 발생하게 되는데, 이를 Repository에 분리한다면 코드의 재사용성 또한 높아집니다.
종합하자면, Layered Architecture는 개발자가 코드를 더 효율적이고 가독성 높게 작성하기 위해 목적에 맞게 코드의 계층을 나눈 구조라고 할 수 있습니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency Injection은 특정 코드의 외부에서 해당 코드에 필요한 의존관계를 지정해줄 수 있다는 개념입니다.
클래스 A에서 인터페이스 B를 필요로 하고, 인터페이스 B가 클래스 C, 클래스 D의 두 가지 구현체가 존재한다고 가정하면, 클래스 A에서 클래스 C를 사용하는 경우와 클래스 D를 사용하는 경우에 클래스 A에 B b = new C(); 또는 B b = new D();의 두 가지 형태 코드가 존재할 수 있습니다. 이 경우 A는 인터페이스 B에 어떤 클래스를 구현체로 사용하는 지 알고 있는 상황이 됩니다. 외부에서 클래스 A를 사용할 경우에 생성자에 저 둘 중 하나의 코드를 사용한다면, 다른 코드를 사용할 경우 메소드를 분리하거나 클래스를 새로 작성해야 할 수도 있습니다.
이를 해결하기 위해 외부에서 B b = new C(); 또는 B b = new D();를 선언하고 A a = new A(b);의 형태로 클래스 A의 생성자에 사용할 인터페이스를 지정해 준다면 A에서 인터페이스 B에 어떤 것이 사용되는 지 알 필요가 없는 코드를 작성할 수 있습니다. 이처럼 클래스 간 과도한 의존 관계에서 벗어나기 위해 의존성 주입이라는 개념이 필요하다고 생각합니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Java는 Consumer라는 인터페이스를 통해 함수형 프로그래밍을 지원합니다. Consumer라는 이름답게, 소비하는 역할만을 하며, 무언가를 반환하지 않습니다. 제네릭을 통해 변수를 전달받고, 선언된 Consumer는 값을 받아서 지정한 기능을 수행합니다. 아래의 예시를 통해 쉽게 알 수 있습니다.

Consumer<String> printString = System.out::println;

printString.accept("Hello?");

// 결과물 : 콘솔에 Hello?가 출력됨

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    // 해당 함수 내부를 구현해 주세요
    return new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            const string = f();
            resolve(string);
          } catch (e) {
            reject(e);
          }
        }, seconds * 1000);
    });
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

절차지향을 주로 사용하던 절차지향형 인간으로서, 함수형 프로그래밍을 이해하는 것이 쉬운 것 같으면서도 어려웠던 것 같아요. 이번 프리온보딩을 통해 조금 더 정확하게 함수형 프로그래밍을 이해하고 사용할 수 있는 사람이 되고 싶고, 나아가 좋은 사람으로 좋은 기업에서 열정을 가지고 일하며 가능하다면 함수형 프로그래밍을 적용싶어 보고 싶습니다!

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
class BuildQueryString {
  constructor(table) {
    this.table = table;
  }
  makeSelectQuery({ columnArr, whereArr }) {
    const columns =
      columnArr !== undefined && Array.isArray(columnArr) ? columnArr.join(", ") : "*";
    const wheres =
      whereArr !== undefined && Array.isArray(whereArr)
        ? `where ${whereArr.join(" and ")}`
        : "";
    return `select ${columns} from ${this.table} ${wheres}`;
  }

  makeInsertQuery(columnArr, valuesArr) {
    const column = columnArr.join(", ");
    const values = valuesArr
      .map((value) => (typeof value == "string" ? "'" + value + "'" : value))
      .join(", ");
    return `insert into ${this.table} (${column}) values (${values})`;
  }
}

개발공부를 시작하고 sql을 처음 접할때 짰던 코드입니다. 굉장히 문제가 많고(DB인젝션, 추가 쿼리문 어려움 등) 부족한 코드이지만, 어떻게 하면 반복을 줄일수 있을까 고민하며, 혼자 재밌어하고 뿌듯해했던 코드입니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    개발에서 계층을 나누어 설계하는 구조를 말한다. 구성되는 계층의 숫자에 따라 n 계층 아키텍처라고도 한다. 계층마다 특정 역할과 관심사별로 나뉘며, 각 계층은 해당 계층의 요소나 계층상 아래에 위치한 요소에만 의존하게 한다.

  2. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    OOP 에서 클래스간에 의존성이 있다는것은 서로 영향을 받는다는것을 의미한다. 의존성 주입이란 의존성을 줄이기 위한 방법으로 필요로 하는 객체를 스스로 생성하는 것이 아닌, 외부로부터 주입받는 기법을 의미한다.
    의존성 주입을 사용하면, 클래스간의 결합도가 약해져, 리팩토링이 쉬워지고, 코드를 유연하게해 확장이 쉬워진다.

  3. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    함수형 프로그래밍은 인풋에 따라 순수하게 아웃풋이 결정되는 순수 함수를 기반으로 하는 프로그래밍 기법.
    const arr = [1,2,3,4,5,6,7,8,9,10]; const answer = arr.reduce((pre, cur) => { return pre + cur; }); console.log(answer);
    reduce 를 이용한 간단한 순수함수,

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

     type SomeFunctionReturnString = () => string
     function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
         // 해당 함수 내부를 구현해 주세요
         return new Promise((resolve, reject)=>{
             setTimeout(()=>{
                 try{
                     resolve(f())
                 }catch(error){
                     reject(`Error: ${error.message}`)
                 }
             }, seconds*1000)
         })
    
     };
    
     const success = () => {
       return "successfully done";
     };
    
     const fail = () => {
       throw new Error("failed");
     };
    
     delay(success, 2) // 2초 뒤에 successfully done 로그
       .then((res) => console.log(res))
       .catch((e) => console.log(e));
    
     delay(fail, 2) // 2초 뒤에 failed 로그
       .then((res) => console.log(res))
       .catch((e) => console.log(e));
    
6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  함수형 프로그래밍에 대해 흡수하여, 좀더 강력한 개발자가 되고 싶슴다.

사전 과제 제출

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

  async getDogsDistance({ id }) {
    const result = [];
    const distance = await this.cacheManager.get(id);

    for (let i = 0; i < Object.keys(distance).length; i++) {
      const tmp = new AroundDogOutput(); //객체 타입 리턴 받기 위해 새로운 타입 지정
      (tmp.dogId = Object.keys(distance)[i]),
        (tmp.distance = Object.values(distance)[i]);
      result.push(tmp);
    }

    return result;
  }

사이드프로젝트로 진행했던 작업 중 일부입니다. redis에 저장되어 있는 객체값을 호출해서 새로운 output 타입에 담아 return 하는 함수입니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

책임과 성격이 다른 것을 크게 그룹으로 만들어 분리해두는 것
유사한 관심사들을 layer로 나눠서 수직적으로 배열한 것
보통 웹 기반의 엔터프라이즈 애플리케이션은 3개의 계층을 갖는다고 해서 3계층 애플리케이션이라고도 합니다.

Presentation Layer : 웹 기반의 UI를 만들어내고 그 흐름을 관리하는 계층
Service Layer : 비즈니스 로직을 담고 있는 계층
DataAccess Layer : 백엔드의 DB나 레거시 시스템과 연동하는 인터페이스 역할을 하는 계층
(Infrastructure 계층)

이렇게 계층을 나누어 분리하는 이유는 유지 보수할 때 다른 계층에 있는 부분을 수정하지 않아도 되기에 편리하기 때문입니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

DI(Dependency Injection) 의존성 주입은 Tight Coupling(강한 결합)을 Loose Coupling(느슨한 결합)으로 전환 시키는 방법이며, 제어의 역전(Inversion of Control)의 기술중 하나입니다.
DI(Dependency Injection) 의존성 주입에 총 3가지의 방법이 존재하며 이 중 Constructor Inject(생성자 주입)이 많은 Design pattern에서 권장됩니다.
의존성주입을 사용하는 이유는 코드의 재사용성을 높여주고 테스트에 용이하며 종속성이 감소하기 때문에 변경 및 수정사항에 민감하지 않는다는 장점이 있습니다. 또한 결합도는 낮추면서 유연성과 확장성을 향상 시킬 수 있으며 객체간의 의존관계를 직접 설정할 수 있습니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

객체를 중심으로 사고하고 프로그램을 작성하는 객체지향 프로그래밍과 달리 함수형 프로그래밍은 데이터를 함수로 연결하는 것을 중심으로 사고하고 프로그래밍을 하는 것을 뜻합니다. 함수형 프로그래밍은 선언형 프로그래밍과 순수 함수를 이용해 문제를 해결하는 프로그래밍 패러다임입니다. 선언형 프로그래밍과 순수 함수 덕에 코드가 간결해지고, 유지보수와 가독성이 크게 증가한다는 장점을 가지고 있습니다.

순수 함수를 활용한 함수형 프로그그래밍 예제

const ret = [1,3,6,8,12]
.reduce((max,num) => num > max ? num : max, 0)
console.log(ret) //12

순수 함수란 출력이 입력에만 의존하는 것을 의미하기 때문에 위의 예제와 같이 순수 함수들을 블록처럼 쌓아 로직을 구현하고 고차 함수를 통해 재사용성을 높인 프로그래밍을 함수형 프로그래밍 언어라고 합니다.

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

type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (e) {
        reject(e);
      }
    }, 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
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    객체지향언어를 사용하는 백엔드 개발자 분들이 많은데 함수형 언어를 사용하시는 개발자 분들은 어떻게 개발하고 계신지 궁금했고 nestjs에 대한 부족한 학습을 다른 동료분들과 함께 진행하고 배우고 싶습니다.

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
private static int[] solution(int[] array, int[][] commands) {
    int[] answer = new int[commands.length];
    int[] real = array;
    int i=0;

    for(int[] arr : commands){
        array = Arrays.copyOfRange(array, arr[0]-1, arr[1]);
        Arrays.sort(array);
        answer[i] = array[arr[2]-1];
        i++;
        array = real;
    }
    return answer;
}
  • 최근 코딩테스트를 하면서 copyOfRange를 사용하는 방법을 공부했는데 새로 알게 된 개념이라 공유합니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  • 소프르웨어 시스템을 분리하는 방법의 하나로 계층의 아래에 해당하는 요소에 의존하는 아키텍처이다.
  • 일반적으로 4계층으로 이뤄져 있으며, Presentation / Business / Persistence / Database Layer로 나뉜다.
  • Presentation Layer : 시스템을 사용하는 사용자와의 상호작용을 처리, MVC단
  • Business Layer : 서비스 핵심 로직으로 유효성 검사, 계산 등을 수항하는 논리 계층이다.
  • Persistence Layer : DAO 계층. DB, 외부 API 통신을 처리하는 계층이다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 클래스 간 의존성을 외부에서 주입하는 것.
  • 클래스 간 의존 관계를 생성하게 되는데, 객체 지향적인 설계가 가능하게 한다.
  • 의존성 주입으로 클래스간 결합도가 약해지게 되는데, 이 경우 하나의 수정으로 리펙토링을 수월하게 하고, 확장성을 높이는데에 있다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

  • java
  • collection, steam를 이용하거나 람다를 이용한 간결한 표현방식을 선호합니다.
Optional<MaintenanceSub> maintenancesub = GetSubCategory(name);
if(maintenancesub.isEmpty()){
    return this.SubCategorys.stream().filter(f -> f.getList().contains(name)).count() > 0;
}else{
    return SubCategorys.contains(maintenancesub.get());
}

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        return new Promise<string>((resolve, reject) => {
          setTimeout( () => {
            try{
              const msg = f();
              return resolve(msg);
            } catch (e) {
              reject(e);
            }
          } , seconds);
        })
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • 강의에서 제공하는 언어를 사용해보지 않았는데 이번 기회에 스케줄에 맞춰 학습하고 이해도를 높이고 싶습니다.

사전 과제 제출

사전과제

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
 catch(exception: HttpException, host: ArgumentsHost) {
   const ctx = host.switchToHttp();
   const response = ctx.getResponse<Response>();
   const status = exception.getStatus();
   const err = exception.getResponse() as
     | { message: any; statusCode: number }
     | { error: string; statusCode: 400; message: string[] }; // class-validator 타이핑

   console.log(status, err);
   if (typeof err !== 'string' && err.statusCode === 400) {
     // class-validator 발생 에러
     return response.status(status).json({
       success: false,
       code: status,
       data: err.message,
     });
   }

   // 사용자 정의 에러(HttpException, BadRequestException 등..)
   response.status(status).json({
     success: false,
     code: status,
     data: err,
   });
 }
}

현재 nestjs로 사이드 프로젝트를 진행하고 있는데 예외처리를 조금 깔끔하게 하기 위해서 따로 신경을 쓰고 있는 부분입니다.
아직 다른 부분에 구현해야될 부분이 많지만 공유하고 싶습니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

소프트웨어 개발에서 가장 일반적으로 널리 사용되는 아키텍처이다. 구성되는 계층의 숫자에 따라 N계층 (N-tier Architecture) 라고도 한다.
어플내의 특정역활과 관심사(화면표시, 비즈니스 로직 수행, DB 작업등)별로 구분된다. 이는 관심사의 분리이며, 특정 기능만 수행하며 이런 특징은 유지보수성과 쉬운 테스트라는 장점이 있다.

  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    의존성 주입이란 클래스간 의존성을 클래스 외부에서 주입하는 것을 뜻한다. 더 자세하게는 의존성 주입은 클래스에 대한 의존성의 인터페이스화를 통한 코드 유연성 증대와 클래스의 인스턴스를 외부에서 생성하여 주입하는 것을 뜻한다.

장점으로는 한 클래스가 변경될 경우 다른 클래스가 변경될 필요성이 적어진다는 것을 클래스간의 결합도가 약해진다고 하는데, 클래스간의 결합도가 약해져, 리팩토링이 쉬워진다. 또한 특정클래스를 테스트하기 쉬워진다. 또한 코드를 유연하게 해, 확장을 쉽게 한다. 프로그램의 생명주기에 따라 생명주기별로 컨테이너를 관리 할수 있다면 리소스 낭비를 막을수 있다.

  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

기본적인 ES5를 따르고 있고

기본적인 예제는 다음과 같다.

// 고차 함수의 인수로 함수를 넘길 때, 해당 함수에서 바깥 스코프에 있는 변수를 사용할 수 있습니다.
const people = [
  {name: '윤아준', age: 19},
  {name: '신하경', age: 20}
]

function peopleOlderThan(people, threshold) {
  return people.filter(person => person.age > threshold);
}

peopleOlderThan(people, 19); // [ { name: '신하경', age: 20 } ]
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number) {
    return new Promise((resolve, reject) =>
        setTimeout(() => {
            const meg = f();
            try {
                resolve(meg);
            } catch (error) {
                resolve(meg);
            }
        }, 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));
**결과값**
```text
$ ts-node delay.ts
after 2 seconds
successfully done
Error: failed
```
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    다른 현업에 있는 분들의 생각하는 코드의 유지보수하기 좋은 코드는 무엇인가와 지금 타입스크립트, nestjs를 쓰며 oop를 맛보기하고 있는데 강의가 어떤 내용이 될까 궁금하고 발전의 기회가 되었으면 합니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    언어 상관없음
    어떤 로직이든 상관없음
    단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요

퍼블릭 블록체인에 서버에서 트랜잭션을 발생시켜 NFT를 민팅하는 코드입니다. 이정에 좇기다 보니 본의 아니게 약간 길고 많은 일을 하는 비지니스 로직이 구현되었습니다. 그럼에도 불구하고 공유하게 된 이유는 이런 코드를 리팩토링하고 싶다는 강한 의지가 있기 때문입니다.

async function mintPublic ({
orderNumber,
orderDate,
productName,
productType
}) {
const imagePath = await imageGenerator.createImage({
  filename: 'image-public.png',
  orderNumber,
  orderDate,
  productName,
  productType
})
const { imageUrl, tokenUri } = await uploadImageAndMetadata({
  imagePath,
  productName,
  productType,
  orderNumber,
  orderDate
})

const { caver, address } = caverUtils.getInstance({
  endpoint: PUBLIC_KLAYTN_RPC_ENDPOINT,
  privateKey: PUBLIC_PRIVATE_KEY
})
const nftContract = caver.contract.create(
  PUBLIC_NFT_CONTRACT_ABI,
  PUBLIC_NFT_CONTRACT_ADDRESS
)
const receipt = await nftContract.send(
  { from: address, gas: MAX_GAS },
  'createToken',
  tokenUri
)
const mintTxHash = receipt.transactionHash
const tokenId = receipt.events.Transfer.returnValues.tokenId
await dbUtils.query(INSERT_NFT, [
  orderNumber,
  orderDate,
  productName,
  productType,
  CHAIN_ID,
  PUBLIC_NFT_CONTRACT_ADDRESS,
  mintTxHash,
  tokenId,
  imageUrl,
  tokenUri
])
return {
  imageUrl,
  tokenUri,
  chainId: CHAIN_ID,
  contractAddress: PUBLIC_NFT_CONTRACT_ADDRESS,
  tokenId
}
}
  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

마틴 파울러의 엔터프라이즈 애플리케이션 아키텍처 패턴에서는 다음과 같은 3계층 분리를 데이터 중심 에플리케이션을 모듈화하는 대표적인 방법으로 제시한다.

layers

계층화를 하는 이유 또한 다음과 같은 세가지로 이야기하고 있다.

  • 관심사 분리하여 개발자 뇌의 부하 분산
  • 모듈들의 구체적 구현체 교체의 용이성
  • 모듈 분기점들이 존재함으로서 좀 더 쉽게 테스트 가능한 코드를 작성하게 됨.
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

객체의 의존 관계를 외부에서 결정하고 런타임에 주입하는 것이 의존성 주입이다. 토비의 스프링에서는 다음의 세 가지 조건을 충족하는 작업을 의존관계 주입이라 말한다.

  • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
  • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
  • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.

이일민, 토비의 스프링 3.1, 에이콘(2012), p114

DI의 장접으로는

  • 의존성이 줄어든다.
  • 재사용성이 높은 코드가 된다.
  • 테스트하기 좋은 코드가 된다.
  • 가독성이 높아진다.
  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Higher-order 함수들인 filter, map, reduce는 함수형 프로그래밍에 중요한 요소이다.

배열의 원소들의 합을 구하는 함수를 map을 사용하여 다음과 같이 구현할 수 있다.

function sum(numbers) {
  return numbers.reduce((a, b) => a + b, 0)
}
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        return new Promise<string>((resolve, reject) => {
          setTimeout(() => {
            try {
              resolve(f());
            } catch (error) {
              reject(`${error.name}: ${error.message}`);
            }
          }, seconds * MS_IN_SECOND);
        });
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형 사고 방식과 자바스크립트 함수형 문법을 익히고 실무에서 레거시 코드를 함수형으로 리팩토링 하는 방법과 이로 인헤 얻을 수 있는 효과에 대해서 배우고 싶습니다.

사전과제 제출

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

    • 언어 상관없음
    • 어떤 로직이든 상관없음
    • 단, 길이가 길지 않은 함수 단위가 좋습니다
    const sendNotification = async (uId, payload) => {
        try {
            const subs = await db.LoadSubscribe(uId).then((result) => (result?.subscription ? JSON.parse(result?.subscription) : []));
    
            await Promise.all(
                subs.map((sub) =>
                    webPush.sendNotification(sub, JSON.stringify(payload)).catch(async (e) => {
                        // 해당 구독 삭제
                        const prevSubs = await db.LoadSubscribe(uId).then((result) => (result?.subscription ? JSON.parse(result?.subscription) : []));
                        const subs = prevSubs.filter((prevSub) => !_.isEqual(prevSub, sub));
                        db.updateSubscribe(uId, subs);
                    }),
                ),
            );
        } catch (e) {
            console.error(e);
        }
    }

    해당 코드는 Notifications API 을 활용하여 클라이언트 단에 알림을 보내는 함수입니다.
    db에 저장된 endPoint를 가져와 비동기 작업을 Promise.all을 활용하여 병렬 처리하여 속도를 높였으며 작업 중 에러가 발생하는(클라이언트 접근이 중단된) endPoint를 삭제하는 작업도 하고있습니다.

  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    4-tier-layered-architecture
    소프트웨어 개발에 사용 되는 아키텍처로 각 계층은 역할 별로 구분됩니다.
    시스템의 결합도는 낮아지고 응집도가 높아집니다.
    코드의 재사용성을 높이고 유지보수성을 확장할 수 있습니다.
    코드를 분리 하면서 함수별 크기가 줄어들어 모든 도메인을 다 알필요가 없고 테스트 하기에도 용이합니다.

  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    의존성 주입(DI)은 하나의 객체가 다른 객체의 의존성을 제공하는 기술입니다.
    코드의 결합도를 낮추고 코드의 가독성과 재사용성을 높여주며 테스트하기 용이해집니다.

  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

    const arr = ['1', '2', '3', '4', '5'];
    console.log(arr); // [ '1', '2', '3', '4', '5' ]
    console.log(arr.filter(v => +v > 3)); // [ '4', '5' ]
    console.log(arr.map(n => +n)); // [ 1, 2, 3, 4, 5 ]
    console.log(arr.map(n => +n).reduce((v, sum) => sum + v, 0)); // 15
  5. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

    type SomeFunctionReturnString = () => string;
    
    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            resolve(f());
          } catch (err) {
            reject(err);
          }
        }, 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
    after 2 seconds
    successfully done
    Error: failed
    
  6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형 프로그래밍에 더욱 적응하며 실무에도 잘 활용하고 싶습니다.
    그리고 멘토님의 강의를 통해 실무에서 활용할만한 스킬을 배워보도록 하겠습니다.

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
공유하고 싶은 코드는 없습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

코드의 유지보수나, 확장의 용이성을 위하여 관심사별로 계층을 분리하는 아키텍처입니다.
주로 Presentation Layer, Business Layer, Persistence Layer, Database Layer등으로 구성합니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

책임을 나눠 코드를 작성하다 보면 코드 간의 의존관계가 생기게 됩니다.
DI는 의존관계를 직접 작성하는 것이 아닌 런타임 시점에 외부에서(스프링 컨테이너, 네스트 프로바이더 등등..)
결정하고 주입해주는 것입니다.

코드로서 의존관계를 모두 선언한다는 것은 각 코드들이 강하게 결합되어 있다는 뜻이고, 이는 유지보수의 큰 걸림돌이 됩니다.
또, 객체지향 설계 원칙 중 OCP와 DIP를 지키는 좋은 방법이 됩니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

명령형으로 for, if등을 사용하는 것이 아닌 자료의 흐름에 따라 선언형으로 코드를 작성하는 것입니다.
JS에서는 함수가 1급 객체이기에 함수를 인자로 사용할 수 있습니다.

const pow = n => n*n;
const arr = [1, 2, 3, 4, 5];
console.log(arr.map((i)=> i*i));
console.log(arr.map((i)=> pow(i)));

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
   return new Promise<string>((resolve, reject)=>{
       setTimeout(()=>{
           try{
               resolve(f());
            }
           catch(e){
               reject(e);
           }
       }, 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
    failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

흔히 함수형이라고 하면 JAVA에 Stream API와 JS에 map, filter, reduce 등등..
순회에 관련된 것 이상으로는 생각하기 어렵습니다.
이번 강의를 통해 함수형 패러다임을 더 깊게 이해하고 싶습니다.
``

사전 과제 제출

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

function HandleError() {
    return function (target : any, propertyKey : string, descriptor : PropertyDescriptor){        
				console.log(target);
        console.log(propertyKey);
        console.log(descriptor);
        const method = descriptor.value;
        descriptor.value =function(){
            try {
                method();
            }catch(e){
                console.log(e);
            }
        }
    }
}
class Greeter {
    @HandleError()
    hello(){
        throw new Error("테스트 에러");
    }
}
const t = new Greeter();
t.hello();

/* 기초적인 수준의 데커레이터지만 Typescript언어와 Nest.js 프레임워크를 처음 공부하고 
데커레이터의 개념에 대해 이해하는데 오랜 시간이 걸렸는데,해당 메서드 데커레이터 코드를 직접 작성해보며 
데커레이터의 의미와 활용법을 이해할 수 있게되어 공유하고 싶습니다.
*/ 

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  • 코드의 구조를 더 체계적으로, 효율적으로 하기 위해 논리적, 기능적으로 영역을 구분하여 구현한 것을 코드의 아키텍처라고 합니다.
  • 아키텍처는 확장성 , 재사용성, 유지 보수 가능성, 가독성, 테스트 가능성을 목표로 구조화 됩니다.
  • 이를 구현하기 위해 코드가 주된 역할과 집중해야할 기능에 대해 분리한 뒤, 서로 다른 기능의 코드는 신경 쓰지 않도록 하는 Separation Of Concerns(관심사 분리) 가 이루어져야 합니다.
  • Layered Architecture(계층 아키텍처) 는 ****Multi-tier Architecture라고도 불리는, 백엔드 API에서 가장 널리 쓰이는 아키텍처 입니다.

Untitled

  • 가장 기초적인 레이어드 아키텍처는 일반적으로 Presentation Layer, Business Layer, Persistence Layer 로 ****구현됩니다.
  • Presentation Layer는 해당 시스템을 사용하는 사용자 혹은 클라이언트 시스템과 직접적으로 연결되는 부분입니다.
  • Business Layer는 이름 그대로 비즈니스 로직을 구현하는 부분입니다.
  • Persistence Layer는 데이터베이스와 관련된 로직을 구현하는 부분입니다.
  • 레이어드 아키텍처는 단방향 의존성(각각의 레이어는 오직 자신보다 하위에 있는 레이어에만 의존하는 성질)과 관심사의 분리를 통해 아키텍처의 목표를 구현할 수 있습니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 의존성 주입은 디자인 패턴의 한 종류로 두 객체 간의 의존 관계에서 오는 문제점을 해결하기 위한 것입니다.
  • 의존 대상 B가 변하면, A에 영향을 미칠때 A와 B는 의존 관계에 있다고 정의합니다.
  • 의존 관계가 복잡하게 얽혀있는 코드에서는 에러가 발생 시 원인을 찾거나 해결하는 것이 어렵기 때문에 코드의 품질과 안정성을 해치게 됩니다.
  • 클래스 외부에서 객체를 생성하여 내부에 주입하는 의존성 주입을 통해 의존 관계를 느슨하고 유연하게 만들어 이러한 문제를 해결할 수 있습니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

  • 지금까지 가장 많이 사용했던 Javascript를 통해 함수형 프로그래밍을 구현해 보고자 합니다.
  • Javascript의 대표적인 함수형 프로그래밍 메서드인 map을 통해 list 배열 내의 이름을 파스칼 케이스로 변환한 뒤 오름차순으로 정렬해 보겠습니다.
let list = ["kim eungsoo","jo joonhyoung","jo kyungchan","jeoung dayoung"]
let firstCase = (sting) =>{
	return string.chatAt(0).toUpperCase() + string.slice(1)
}
let lastCase = (string) =>{
	return string.split(' ').map(firstCase).join(' ')	
}
list
	.maps(string => firstCase(string))
	.maps(string => lastCast(string))
	.sort()

스크린샷 2023-01-05 20-13-57

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

type SomeFunctionReturnString = () => string
function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise<string>((success, fail) => {
    setTimeout(() => {    
      try {
        success(f())
    } catch(e){
      fail(e);
    }
  } , seconds * 1000);
});

};
const success = () => {
  return "successfully done";
};
const fail = () => {
  throw new Error("failed");
};

스크린샷 2023-01-05 20-20-04

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • 기존 자바스크립트 언어와 Express 프레임워크 환경으로 절차 지향적인 코드를 작성해왔던 주니어 개발자로서 이번 챌린지는 새로운 경험이면서도 동시에 대조적인 두 언어와 환경, 지향점의 특성과 장단점을 대조적으로 비교 분석하고, 상황에 따라 적절한 개발 도구를 선택하여 활용할 수 있는 기회라고 생각합니다. 챌린지의 1차적인 목표는 취업이지만 한층 더 높은 수준의 개발자로 성장하기 위한 기회라고 생각하고 완주해보겠습니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    => 공유하고 싶은 코드는 없습니다!

  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    계층 아키텍쳐는 소프트웨어 개발에서 가장 일반적으로 사용되는 아키텍쳐로, 관심사 분리를 통해서 각 계층마다 역할을 나누어 놓은 방식입니다.

  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    의존성 주입이란, 클래스 간의 의존성을 외부에서 주입하는 것을 의미합니다. 클래스 간에 의존성이 있을 경우, 한 클래스에 변화가 생기면 다른 클래스가 영향을 받게 됩니다. 외부에서 의존성을 주입한다면, 의존성을 줄일 수 있으며 결합도는 낮추고 유연성을 높일 수 있습니다.

  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    자바스크립트에서 함수형 프로그래밍 함수에는 map, reduce, filter이 있습니다.
    map은 해당 배열의 각 요소에 인자로 받는 함수를 실행시킵니다

let arr = [1, 2, 3]
arr = arr.map((el) => {
    return el * 2 })
// [2, 4, 6]

위의 예제처럼 arr의 각 요소에 2를 곱하는 함수를 map의 인자로 전달하면, 각 요소에 2가 곱해진 배열을 리턴합니다.

  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  // 해당 함수 내부를 구현해 주세요
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (e) {
        reject(`Error: ${e.message}`);
      }
    }, seconds * 1000);
  });
}

const success = () => {
  return 'successfully done';
};

const fail = () => {
  throw new Error('failed');
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형 프로그래밍으로 개발을 시작했지만 아직은 함수형 프로그래밍의 장점과 객체 지향 프로그래밍과의 차이와 장단점을 업무에 반영시키기 어려운 것 같습니다. 이번 기회를 통해서 배운 것을 업무에 반영 시킬 수 있는 개발자가 되고 싶습니다.

사전 과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
async getRelatedUsers(_id: string, option: RELATION) {
    const user = await this.userRepository.findById(_id);
    if (!user) {
      throw new BadRequestException('요청한 사용자는 없는 사용자입니다.');
    }

    const { followings, followers } = user;
    const userIdList = option == RELATION.FOLLOWERS ? followers : followings;하기
    return await Promise.all(
      userIdList.map(async (userId) => {
        return getUserBasicInfo(await this.userRepository.findById(userId));
      }),
    );
  }

이유 : Promise all을 처음 사용해보고 속도향상이 되는걸 확인했을 때 뿌듯했던 것 같습니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    소프트웨어 개발에서 가장 일반적으로 널리 사용되는 아키텍처로, 각 계층은 어플리케이션 내에서의 특정 역할과 관심사(화면 표시, 비즈니스 로직 수행, DB 작업 등)별로 구분된다.
    이는 Layered Architecture 의 강력한 기능인 '관심사의 분리 (Separation of Concern)' 를 의미한다.
    관심사의 분리가 충족되면 각 계층의 역할을 수행할 수 있는데 집중하여 도메인 로직을 개발할 수 있고 테스트 로직을 작성할 수 있기 떄문에 유지보수에도 용이하다.

  2. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 개념
    • 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴
    • 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
    • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
    • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
    • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.
  • 필요한 이유
    • 두 클래스가 강하게 결합되면 유연성이 떨어진다.
    • 재사용성이 높은 코드가 된다.
    • 테스트하기 좋은 코드가 된다.
    • 가독성이 높아진다.
  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
// 함수를 인자로 전달받고 함수를 반환하는 고차 함수
function makeCounter(predicate) {
  // 자유 변수. num의 상태는 유지되어야 한다.
  let num = 0;
  // 클로저. num의 상태를 유지한다.
  return function () {
    // predicate는 자유 변수 num의 상태를 변화시킨다.
    num = predicate(num);
    return num;
  };
}

// 보조 함수
function increase(n) {
  return ++n;
}

// makeCounter는 함수를 인수로 전달받는다. 그리고 클로저를 반환한다.
const increaser = makeCounter(increase);
console.log(increaser()); // 1
console.log(increaser()); // 2
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
   return new Promise<string>((resolve, reject) => {
      setTimeout( () => {
        try{
          const msg = f();
          return resolve(msg);
        } catch (e) {
          reject(e);
        }
      } , seconds);
    })
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형 프로그래밍이 어떤 것인지는 알고 있지만, 막상 실제 프로젝트에 적용해보기 어려웠던 것 같습니다.
    강의를 통해 함수형 프로그래밍과 친해져서 리팩토링에 적용해보고 싶습니다.

사전과제 제출

사전과제

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

    <script>
      const urlId = document.location.href.split('#')[1]
      switch (urlId) {
        case 'link1':
          location.href="~"    
          break;
        case 'link2':
          location.href="~"
          break;
      }    
    </script>

    js를 사용한 링크 랩핑 코드, 나에게 당장 필요한 것을 잘 만들어 보는 것이 중요한 것 같다.

  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

    1. 계층 아키텍처: 역할을 분리한다.
  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

    1. 의존성 주입(Dependency Injection): 애플리케이션의 구성 요소가 자신이 사용할 외부 자원을 자신의 생성자나 메서드를 통해 전달받는 것
    2. 필요성: 사용하는 것을 명확하게 함 중복을 감소, 다른 것을 불러오는 전역적 이슈 해결
  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

    1. JavaScript 에서 함수형 프로그래맹 스펙으로는 다음과 같은 고차함수가 있습니다.
      • Map, forEach, reduce, filter, every, some
  5. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    return new Promise((resolve, reject) => {
    setTimeout(function () {
      try {
        const res = f();
        resolve(res);
      } catch (error) {
        reject(error);
      }
    }, 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));
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  • 실무에서 고려해야할 요소들에 대한 관점 얻기
  • 함수형 프로그래밍을 프로젝트에 적용하기
  • NestJS 스러운 코드 작성하기

사전과제 제출

1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요.
아직 개발 초보라서 과정 내용 중 그나마 비동기 처리와 관련있는 코드(ajax를 통해 비동기 처리)를 공유합니다.

@RequestMapping("/do_qna_list")
public @ResponseBody Map<String, Object> do_qna_list
(@RequestParam Map<String, Object> dataMap, HttpServletRequest request, Model model) throws Exception {
	Map<String, Object> qnaMap = new HashMap<String, Object>();
	qnaMap = qnaService.qna_list(dataMap);
	return qnaMap;
}

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  • 소프트웨어 개발에서 일반적으로 사용되는 아키텍처.
  • 관심사 기능별 계층 분리
  • 높은 유지보수성
  • 쉬운 테스트
  • User Request -> 1 -> 2 -> 3 -> 4 -> 3 -> 2 ->1 -> User

a) Presentation Layer

  • 화면에 정보를 표시
  • view, controller

b) Business Layer

  • 1번으로 보낼 데이터를 선별 전달
  • Service, Domain Model

c) Persistence Layer

  • 2번으로 보낼 데이터를 추출, 가공
  • Repository, DAO

d) Database Layer

  • DB가 위치

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것

a) 주입방법

  • Contructor Injection : 생성자를 통한 전달
  • Method(Setter) Injection : setter()를 통한 전달
  • Field Injection : 멤버 변수를 통한 전달

b) 필요한 이유(사용 시 장점)

  • 의존성이 감소
  • 재사용성이 높은 코드
  • 테스트하기 유용
  • 가독성 증가

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

  • Java를 메인으로 OOP 위주 개발을 배웠습니다.
  • 이번 챌린지를 통해 함수형 프로그래밍을 배워보고 싶습니다.

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			try {
				console.log( __filename);
				resolve(f());
			} catch(e) {
				reject(e);
			}
		}, seconds*1000);
	});
};

const success = () => {
	return "successfully done";
};

const fail = () => {
	throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
	.then((res) => console.log(res))
	.catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
	.then((res) => console.log(res))
	.catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • 더 많이 배우고 성장하여 제대로 된 개발자가 되고 싶습니다. 현재 수준은 국비학원을 통해 겨우 걷는 방법을 배운거라 생각합니다.
    짧은 기간이지만 최근 트랜드인 typescript와 Node, Nest를 배우고 취업 스펙트럼을 더욱 넓히고 싶습니다.

사전과제 제출

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

public RegisterGameResultDto joinGame(Long gameId,
                                      Long currentUserId) {
    User currentUser = userRepository.findById(currentUserId)
        .orElseThrow(() -> new UserNotFound(currentUserId));

    Game game = gameRepository.findById(gameId)
        .orElseThrow(() -> new GameNotFound(gameId));

    List<Register> registers = registerRepository.findByGameId(gameId);

    Register register = game.join(currentUser, registers);

    if (register != null) {
        Register savedRegister = registerRepository.save(register);

        Post post = postRepository.findById(game.postId())
            .orElseThrow(PostNotFound::new);

        User postAuthor = userRepository.findById(post.userId())
            .orElseThrow(() -> new UserNotFound(post.userId()));

        Notice notice = savedRegister.createRegisterNotice(
            currentUser,
            postAuthor
        );

        noticeRepository.save(notice);
    }

    return new RegisterGameResultDto(gameId);
}

위 소스코드는 개인 프로젝트에서 Spring Boot로 구현한 서버 애플리케이션의 Application Layer에 있는 Service 로직의 하나를 가져온 것입니다.
코드 중 Register register = game.join(currentUser, registers)은 본래 다음의 구조였습니다.

registers.forEach(register -> {
    if (register.userId().equals(accessedUserId)
        && (register.status().value().equals(RegisterStatus.PROCESSING)
        || register.status().value().equals(RegisterStatus.ACCEPTED))) {
        throw new RegisterGameFailed("이미 신청 중이거나 신청이 완료된 운동입니다.");
    }
});
List<Register> members = registers.stream()
    .filter(register -> register.status().value().equals(RegisterStatus.ACCEPTED))
    .toList();

if (members.size() >= game.targetMemberCount().value()) {
    throw new RegisterGameFailed("참가 정원이 모두 차 참가를 신청할 수 없습니다.", game.id());
}

Register register = new Register(
    accessedUserId,
    gameId,
    new RegisterStatus(RegisterStatus.PROCESSING)
);

리팩터링 이전의 구조는 Application Layer에 비즈니스 로직이 드러나 있는 형태였고, 테스트 코드로 코드의 동작을 검증하면서 구현을 진행하는 과정에서 테스트를 위한 데이터를 세팅하는 로직이 너무 복잡해져 테스트 코드를 작성하기 어려웠습니다.

다른 분들의 도움을 받아 비즈니스 로직을 객체가 수행하도록 리팩터링을 진행하면서 코드가 간결해지고, 테스트 코드의 크기가 줄어드는 것을 확인할 수 있었습니다. 이전까지는 단순히 Layered Architecture가 유연한 소스코드를 작성하기 쉽다고만 들었고 체감이 잘 되지 않았지만, 좋지 못했던 구조의 코드를 리팩터링하면서 Layer의 역할에 따른 관심사의 분리의 필요성을 체감하는 계기가 되었기에 해당 소스코드를 공유하게 되었습니다.

Reference

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

Layered Architecture는 소프트웨어 아키텍처의 한 종류로, 소프트웨어를 구성하는 conceptual한 요소들을 논리적으로 구조화하는 매커니즘인 Layer로 소프트웨어의 주요 동작인 Presentation, Application Processing, Data management를 논리적으로 분리합니다. Layer는 System infrastructure를 구성하는 하드웨어 요소들을 물리적으로 구조화하는 매커니즘인 Tier와 비교될 수 있습니다.

일반적인 객체지향 설계 환경에서 Layer는 다음의 4가지 계층으로 구분됩니다.

  • Presentation Layer: View 또는 UI를 나타냅니다.
  • Application Layer: 각 기능이나 동작을 Controller와 Service로 나눠 나타냅니다. 특정 Business Layer의 비즈니스 로직에 대한 API 정의를 캡슐화합니다.
  • Business Layer: 비즈니스 객체가 서로 상호작용하는 방식인 비즈니스 로직을 나타냅니다.
  • Data Access Layer: 영속성, 로깅, 네트워킹 등을 통해 Business Layer를 지원합니다.

Layered Architecture의 가치는 관심사를 분리해 각 Layer에서 특정 영역을 집중적으로 다루게 하는 데 있습니다. 각각의 Layer에 관련된 코드를 Layer 별로 집중시킴으로써 로직이 분리되어 있지 않은 경우 대비 각각의 Layer를 훨씬 명료하고, 유연하고, 재사용 가능한 구조로 설계하고 구축할 수 있습니다.

Layer 간의 연결은 설계 의존성을 한 방향으로 두어 느슨하게 결합하도록 합니다. 일반적으로 상위 Layer이 하위 Layer의 인터페이스를 호출하는 식으로 이루어지고, 경우에 따라 하위 수준의 Layer가 상위 수준의 Layer와 통신해야 할 경우에는 콜백이나 관찰자 패턴을 적용하기도 합니다.

References

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency Injection은 디자인 패턴의 하나로, 객체 또는 함수가, 의존하고 있는 다른 객체 또는 함수를 전달받아 사용하는 패턴입니다.

Java의 웹 프레임워크인 Spring Boot에서 MVC 패턴을 적용하는 경우, 하위 Layer를 상위 Layer에 다음과 같은 방식으로 의존성을 주입할 수 있습니다.

// controllers/PlaceController.java
@RestController
@RequestMapping("places")
public class PlaceController {
    private final GetPlaceService getPlaceService;

    public PlaceController(GetPlaceService getPlaceService) {
        this.getPlaceService = getPlaceService;
    }

    @GetMapping("{placeId}")
    public PlaceDto place(
        @PathVariable Long placeId
    ) {
        return getPlaceService.getTargetPlace(placeId);
    }
}

// services/GetPlaceService.java
@Service
@Transactional
public class GetPlaceService {
    // ...
}

Dependency Injection은 다음과 같은 이점을 가집니다.

  • 두 영역 간의 의존성 및 결합도가 감소합니다.
    다른 객체나 함수를 전달받는 쪽에서는 전달받은 요소가 어떻게 구성되는지 구체적으로 알지 않아도, 인터페이스만을 아는 것만으로 요소를 사용할 수 있습니다. 소스코드의 관심사가 분리되므로 Layer나 요소의 재사용성, 유지보수성이 용이해집니다.

  • 단위 테스트의 복잡성이 줄어듭니다.
    특정 객체나 함수를 테스트할 때, 실제로 테스트하려는 대상이나 로직이 아닌 의존적인 객체나 함수를 stub이나 mock으로 구성하기 용이해집니다. 이로 인해 테스트 코드의 구조가 단순해지고, 실제로 테스트하려는 영역에 집중할 수 있습니다.

Reference

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Java는 Java 8부터 함수형 프로그래밍을 위한 인터페이스로 람다식, Stream API, 함수형 인터페이스를 제공하고 있습니다.

1. 람다식

Java의 람다식은 익명 함수를 구현하는 방식 중의 하나로, 다음과 같이 구성됩니다.

FunctionalInterface example = () -> System.out.println("message");

람다식을 구성하는 요소는 다음과 같습니다.

  • (): Method Signature
  • ->: Lambda Operator
  • System.out.println("message"): Method Implementation

2. Stream API

Stream API는 컬렉션이나 배열에 저장된 요소들에 순차적으로 혹은 병렬적으로 접근해 특정한 동작을 처리하는 메서드들을 지원하는 컬렉션입니다.

Stream API를 이용해 특정 컬렉션의 모든 요소를 화면에 출력하는 코드의 예시는 다음과 같습니다.

List<String> messages = List.of("Hello", "World", "How", "Are", "You");

messages.stream()
    .sorted()
    .forEach(System.out::println);
Are
Hello
How
World
You

3. 함수형 인터페이스

Java에서 함수형 인터페이스는 1개의 추상 메서드를 갖는 interface를 의미합니다. 함수형 인터페이스는 람다식을 이용해 구현체를 생성할 수 있습니다.

Java에서 제공하는 함수형 인터페이스에는 Runner, Supplier<T>, Consumer<T>, Function<T, R>, Predicate<T> 등이 있습니다.

  • Runnable
    매개변수와 반환 값 모두 없는 형태입니다.
Runnable runnable = () -> System.out.println("message");
runnable.run();
  • Supplier<T>
    매개변수가 없고, T 타입의 값을 반환합니다. 구현체가 랜덤 값을 반환하는 로직이 아니라면 항상 동일한 결과를 반환합니다.
Supplier<String> supplier = () -> "message";
System.out.println(supplier.get());
  • Consumer<T>
    매개변수로 T 타입의 값을 받고, 반환 값은 없습니다.
Consumer<String> consumer = (message) -> System.out.println(message);
consumer.accept("message");

cf. 람다식이 하나의 인자를 받아 해당 인자를 특정 메서드의 인자로 넘겨주는 동작을 수행할 경우, method reference의 형태로 나타낼 수 있습니다.

// 위의 Consumer와 동일한 결과를 반환합니다.
Consumer<String> consumer = System.out::println;
consumer.accept("message");
  • Function<T, R>
    매개변수로 T 타입의 값을 받고, R 타입의 값을 반환합니다.
Function<String, Integer> function = String::length;
System.out.println(function.apply("Hello"));
  • Predicate<T>
    매개변수로 T 타입의 값을 받고, boolean 값을 반환합니다.
Predicate<String, Integer> predicate = (string) -> string.startsWith("a");
System.out.println(predicate.test("abcdefg"));
References

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    // 해당 함수 내부를 구현해 주세요
};

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
function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  let message: string;

  const checkError = () => {
    try {
      message = f();
    } catch (error) {
      if (error instanceof Error) {
        const errorMessage = error.message
        setTimeout(() => console.log(`Error: ${errorMessage}`), seconds * 1000);
      }
    }
  }

  checkError();

  return new Promise<string>((resolve) => {
    if (message) {
      setTimeout(() => resolve(message), seconds * 1000);
    }
  });
};

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

백엔드 개발자로의 첫 취업을 준비하면서 Java와 Spring Boot를 학습하고, 개인 프로젝트를 진행하면서 학습한 것들을 적용해보는 것을 시도했습니다. 취업 준비를 위해 채용 공고를 둘러보면서 기술 스택으로 Java와 Spring Boot뿐만 아니라 JavaScript, TypeScript, node.js를 사용하고 있는 기업들도 많음을 확인할 수 있었습니다. Java뿐만 아니라 JavaScript, TypeScript를 이용해서도 백엔드 애플리케이션을 제작하는 역량을 기르고, 새로운 영역에 적극적으로 도전해 성취하는 경험을 하고 싶습니다.

사전과제 제출 python

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

  • 언어 상관없음

  • 어떤 로직이든 상관없음

  • 단, 길이가 길지 않은 함수 단위가 좋습니다

백준 2133번 타일채우기 답 / 친구가 못풀었는데 나는 풀어서 보면 기분이 좋아지는 코드 입니다.

def n_cases(n):

    if n % 2 != 0 :
        return 0

    else : 
      k = n//2
      answer = [3]
      for i in range(1,k):
          answer.append( answer[i-1] * 3 + sum(answer[0:i-1]) * 2 +2 )
      return answer[-1]%1000000007

2.소프트웨어에 포함된 개체들은 서로 얽히고설켜 있습니다.

하나의 개체를 변경하면 연결된 개체들에 연쇄적으로 영향을 줍니다.
소프트웨어 구조를 주기적으로 변경할 필요가 있는데 아키텍처가 잘 짜여 있으면 소프트웨어 변경을 쉽게 할 수 있어 유지보수하기 수월해집니다. 또한 요구사항에 빠르게 대응할 수 있고 테스트도 빠르게 할 수 있게 됩니다. 아키텍처를 관리하지 않으면 시간이 지날수록 기능을 추가하기 힘들어집니다. 기존 소스 코드를 바꾸는 데 시간이 많이 들기 때문입니다.

계층형 아키텍처(Layered Architecture)는 다음과 같은 계층 구조를 갖습니다.
User Interface

User Interface management
Authentication and authorization

Core business logic/application functionality
System utilities

System support(OS, database etc)

각각의 레이어는 특정 서비스를 제공하도록 구성되어 있으며 같은 목적의 코드들을 모아두어 코드들의 관심사를 분리합니다.
각각의 레이어 사이에는 인터페이스가 있으며 바로 아래 레이어는 바로 위 레이어에 서비스를 제공합니다.

다음과 같은 장단점이 있습니다.
장점 : 인터페이스를 동일하게 유지하면 하나의 계층을 새로운 구현으로 대체할 수 있습니다.
단점 : 계층적으로 명백하게 구분하는 작업이 보통 어렵습니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

business logic과 인프라스트럭처 사이에 무수한 의존성이 존재합니다.
인프라스트럭처의 변경에 business logic이 영향을 받습니다.
business logic을 이러한 변경으로부터 분리해 보호해야 합니다.
이때 의존성 주입(Dependency Injection 이하 DI)을 통해 이를 달성할 수 있습니다.

의존성 주입이란 클래스에 대한 의존성의 인터페이스 화를 통한 코드 유연성 증대 + 클래스의 인스턴스를 외부에서 생성하여 주입하는 것을 뜻합니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    // 해당 함수 내부를 구현해 주세요
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

백엔드가 뭔지 감을 잡고 싶습니다.

사전과제 제출

1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요.
언어 상관없음
어떤 로직이든 상관없음
단, 길이가 길지 않은 함수 단위가 좋습니다

테스트 코드 작성시 한글 메소드를 활용하면 이해하기 더 쉬운 테스트 코드를 작성 할 수 있어서 공유 드립니다.

    @DisplayName("Bearer Auth")
    @Test
    void myInfoWithBearerAuth() {
        //when
        final ExtractableResponse<Response> 토근_로그인_응답 = 토큰_요청("[email protected]", "password");

        //then
        로그인_됨(토근_로그인_응답);
    }

    public static ExtractableResponse<Response> 토큰_요청(String email, String password) {
        TokenRequest tokenRequest = new TokenRequest(email, password);
        return RestAssured.given().log().all()
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .body(tokenRequest)
                .when().post("/login/token")
                .then().log().all()
                .extract();
    }

    private void 로그인_됨(ExtractableResponse<Response> response) {
        assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.as(TokenResponse.class).getAccessToken()).isNotEmpty();
    }

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요.

계층 아키텍처 패턴의 각 계층에는 애플리케이션 내에서 특정 역할과 책임이 있어 특정 계층에는 특정 행위만 담당함

레이어드 아키텍쳐 패턴에서의 구성 요소(component)들은 각 레이어에 수평적으로 구조화되어있다. 레이어드 아키텍처 패턴은 정확히 한 패턴에 몇개의 어떤 레이어가 있어야 하는지를 명시하지 않지만, 가장 보편적인 레이어드 아키텍처 패턴은 4개의 레이어로 구성되어있다; presentation, business, persistence, database이다.

* Presentation layer: UI, 브라우저에서의 유저와의 통신 로직을 다룸.
* Business layer: 요청에 따른 비즈니스 로직을 다룸.
* Persistence layer: DAO(Data Access Object) , ORM과 관련된 데이터베이스에 접근해서 데이터를 저장, 수정하는 함수 로직을 다룸.
* Database layer: 데이터가  저장되어있는 곳. 데이터베이스.

개인적으로 레이어드 아키텍처는 의존성관리와 응집성을 높히는데 중점을 둔다고 생각이 되며 단일책임원칙과 잘어울리는 아키텍처라고 생각이되며
단점으로 레이어(계층)이 늘어날경우 복잡도가 증가할수도 있겠다라는 생각이 듭니다.

참조
1. 레이어드 아키텍쳐( Layered Architecture)
2. 오레일리

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

DI 의존성주입이란 의존하는 객체가 직접 의존객체를 생성하지 않고 주입(Set나 ,생성자 ,필드 인젝션 등) 주입 받아서 생성되는 형태를 말한다.

  • 의존하는 객체란? (예시)

    public class AhasC {
    C c;

    AhasC(){
    // A객체 생성안에서 C를 생성하고 있다 굉장히 강한 의존관계
    c = new C();
    }

    }

    DI 를 하게 되면 객체 외부에서 객체가 주입하게 되어 객체 생성시점이 아닌 외부에서 생성이 되기 때문에 온전히 객체를 본연의 객체를 생성할 수 있다.
    가령 A라는 객체 안에서 B라는 객체를 생성한다고 가정을 해보자 B라는 객체의 생성 파라미터가 수정이 되었을때 A라는 객체도 수정되어야한다. 이는 단일책임원칙에 위반된다고 생각이 된다.

  • DI 사용한 예시

    public class AhasC {
    C c;
    //C 의객체의 파라미터가 변경되어도 AhasC 객체에는 영향이 없다.
    AhasC(C c){
    this.c = c;
    }
    }

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

JAVA언어의 Functional Programming은 Stream 패키지로 구현할 수 있습니다.
Collections의 요소들을 이용하여 함수형 연산을 지원합니다.

대표적인 함수

  • map(): map()은 스트림이 가진 요소에 정의한 함수를 적용해 새로운 스트림을 반환합니다. 주로 새로운 데이터를 만들어야 할 때 사용합니다.
List<Integer> number = Arrays.asList(1, 2, 3, 4, 5);
// 곱연산된값의 새로운 리스트를 반환 
List<Integer> square = number.stream().map(x -> x * x)
    .collect(Collectors.toList());

filter(): filter()는 스트림이 가진 요소를 정의한 함수를 이용해 선택하고 새로운 스트림을 반환합니다. 주로 특정 값을 찾아야 하는 경우에 사용합니다.

List<String> values = Arrays.asList("aa", "ab", "bb", "ba");
//a가 포함된 문자열을 필터링하여 새로운 리스트를 반환함  
List result = values.stream().filter(value -> value.contains("a"))
    .collect(Collectors.toList());


reduce(): reduce()는 스트림이 가진 요소를 줄이는데(reduce) 사용됩니다. 주로 sum과 같이 결과 값을 산출할 때 사용됩니다.


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
//합계를 구함 
int result = numbers.stream().reduce(0, (sum, number) -> sum + number);

기본 매커니즘은 Stream 으로 연산을 진행하고 종결 연산자를 통해 새로운 값을 반환하는것이 특징

참조 [Java - Stream API는 함수형 프로그래밍을 할 수 있게 해준다](https://7942yongdae.tistory.com/160)

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

type SomeFunctionReturnString = () => string;


const makeMillisecond = (seconds: number):number => seconds * 1000


function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (error) {
        if (error instanceof Error) {
          reject(`ERROR :${error.message}`);
        }
      }
    }, makeMillisecond(seconds));
  });
}

const success = () => {
  return 'successfully done';
};

const fail = () => {
  throw new Error('failed');
};

console.log('after 2 seconds');

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
after 2 seconds
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

이번 강의를 통해 명확하게 객체지향과 함수형 프로그래밍의 차이를 이해하고 함수형 프로그래밍을 통해 어떻게 프로젝트에 적용할지에 대해서 생각해보고 배우는 과정을 기대하고 있으며 어떨때 함수형을 써야할지와 객체지향을 써야할지를 구분하고 싶습니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    언어 상관없음
    어떤 로직이든 상관없음
    단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요
export class BaseService<T> {
  constructor() {}
  resObj(data: T): IResObj<T> {
    return new IResObj(200, false, 'success', data);
  }

  resBoolean(data: boolean): IResObj<boolean> {
    return new IResObj(200, false, 'success', data);
  }

  resNumber(data: number): IResObj<number> {
    return new IResObj(200, false, 'success', data);
  }

  resList(data: any): IResObjList<T> {
    return new IResObjList(200, false, 'success', data);
  }

  resError(message: string): IError {
    return new IError(HttpStatus.BAD_REQUEST, message);
  }

  objValidate(obj: T): void {
    if (!obj) throw new Error('findedObj not found');
  }

}

-> 모든 서비스 레이어에서 사용될 수 있는 기본적인 응답 형태의 함수들을 모아놓은 클래스입니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

->
리퀘스트에 대한 역할을 분리하여 각각의 레이어는 맡은 바 일에 대한 책임을 다 하는 것입니다.
일반적으로 presentation, business, persistence, data 레이어로 구성되어 있습니다.
presentation: http 통신에 관한 요청에 대한 응답을 담당합니다.
business: 비즈니스 로직이 주로 위치합니다.
persistence: 데이터베이스 접근을 담당합니다.
data: 데이터베이스

  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

->

개념: 추상화된 객체를 외부에서 주입합니다.
필요한 이유 : 여러 클래스에 의존하는 A클래스에서 의존하는 클래스를 생성한 후 문제를 해결하는 경우 비슷한 코드의 중복과 코드가 길어지는 경우가 많아 불핋요한 비용이 발생합니다.
A클래스에서 필요한 객체를 외부에서 주입하도록하여 A클래스의 코드에서 발생하는 비용을 줄일 수 있습니다.

  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

-> 이번 강의를 통해서 배워보겠습니다.

  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
    type SomeFunctionReturnString = () => string
type SomeFunctionReturnString = () => string;
  function delay(
    f: SomeFunctionReturnString,
    seconds: number,
  ): Promise<string> {
    return new Promise((res, rej) => {
      setTimeout(() => {
        try {
          res(f());
        } catch (err) {
          rej(err);
        }
      }, seconds * 1000);
    });
    // 해당 함수 내부를 구현해 주세요
  }

  const success = () => {
    return 'successfully done';
  };

  const fail = () => {
    throw new Error('failed');
  };

  delay(success, 2) // 2초 뒤에 successfully done 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));

  delay(fail, 2) // 2초 뒤에 failed 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));
결과값

    $ ts-node delay.ts
    successfully done
    Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  • “과락하지 않는 코드를 작성하고 싶어요”
  • “주니어 수준의 최소한의 기본기는 갖추고 싶어요”
  • “좋은 코드와 나쁜 코드의 기준을 알고 싶어요”
  • “기술 과제 면접 질문은 어떻게 대비해야 할까요?”

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    함수형으로 짜여진 코드가 없어서 공유를 못합니다.

  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    레이어드 아키텍처 패턴은 정확히 한 패턴에 몇개의 어떤 레이어가 있어야 하는지를 명시하지 않지만, 가장 보편적인 레이어드 아키텍처 패턴은 4개의 레이어로 구성되어있습니다. presentation, business, persistence, database있습니다.
    -Presentation layer: UI, 브라우저에서의 유저와의 통신 로직을 다룸.
    -Business layer: 요청에 따른 비즈니스 로직을 다룸.
    -Persistence layer: DAO(Data Access Object) , ORM과 관련된 데이터베이스에 접근해서 데이터를 저장, 수정하는 함수 로직을 다룸.
    -Database layer: 데이터가 다 저장되어있는 곳. 데이터베이스.
    핵심 원칙은 한 계층의 모든 요소는 오직 같은 계층에 존재하는 다른 요소나 계층상 "아래"에 위치한 요소에만 의존한다는 것입니다.

  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    -개념: 의존성 주입이란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해줍니다. 의존성이란 한 객체가 다른 객체를 사용할 때 의존성이 있다고 합니다.
    -필요 이유:Test가 용이해지고, 코드의 재활용성을 높여주며, 객체 간의 의존성(종속성)을 줄이거나 없엘 수 있고, 객체 간의 결합도이 낮추면서 유연한 코드를 작성할 수 있습니다.

  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

let arr = [1, 2, 3, 4, 5];
let map = arr.map(function (x) {
  return x * 2;
});
console.log(map);
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (err) {
        reject(err);
      }
    }, 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
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형적 사고와 실무에서 어떻게 사용되는지 알고 싶습니다.

사전과제 템플릿

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
해당 code block 에 올려주세요

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        // 해당 함수 내부를 구현해 주세요
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

사전과제 제출

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

export function setUpENV() {
  if (process.env.NODE_ENV === 'test') {
    dotenv.config({ path: path.join(__dirname, '../../.env.test') });
  } else {
    throw Error(`올바른 환경이 아닙니다 환경 변수를 확인 해 주세요!: ${process.env.NODE_ENV}`);
  }
}

export async function createTestSchema() {
  createConnectionPool();
  const pool = getPromisePool();
  const schema = fs
    .readFileSync(path.join(__dirname, '../../../sql/test-schema.sql'))
    .toString('utf-8');

  await pool.query(schema);
}

export async function clearTestSchema() {
  const pool = getPromisePool();
  await pool.query(
    'DROP TABLE IF EXISTS `my-blog-test`.`comment`, `my-blog-test`.`member`, `my-blog-test`.`post`, `my-blog-test`.`post_like`, `my-blog-test`.`post_tag`, `my-blog-test`.`series`, `my-blog-test`.`tag`, `my-blog-test`.`temp_post`;'
  );
}

TypeScript express 환경에서 각 테스트마다 격리된 테스트 DB 스키마를 생성하는 코드입니다.
Data Access계층 단위 테스트하는데 사용하고 있습니다.
항상 스프링부트의 힘을 빌려서 테스트를 작성하다가 처음으로 테스트환경을 구축했던게 기억에 남아서 공유했습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층형 아키텍처란 프로그램을 개발할 때 연관이 있는 모듈끼리 계층을 나눠서 개발하는 아키텍처입니다.
계층을 나눠서 개발하면 계층에 수정사항이 발생했을 때 수정의 여파가 다른 계층까지 미치는 영향을 최소화 할 수 있기 때문에 큰 프로젝트일 수록 계층을 나눠서 개발하면 좋습니다.

3.Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

객체지향 프로그래밍을 하게되면, 필연적으로 각 클래스끼리 관계를 맺고 클래스의 협력을 통해서 프로그램이 동작하도록 구성하게 됩니다.

하나의 클래스는 다양한 클래스와 연결을 맺고 있으며 SOLID원칙을 준수하면서 프로그램을 작성하게 되면 객체의 연관관계는 인터페이스를 타입으로 가지게 됩니다.

이때 이 멤버에 주입되는 인스턴스에 따라서 프로그램의 실행흐름이 결정되게 되는데 이러한 인스턴스를 외부에서 주입하는 방식을 의존성 주입이라고 합니다.

인스턴스를 클래스 외부에서 설정하게되면 인스턴스를 바꿔줘야 할 때 직접 클래스를 들어가서 수정해주지 않아도 되어서 코드의 수정없이 프로그램의 실행 흐름을 바꿀 수 있다는 장점이 있습니다.

이러한 의존성 주입을 해주는 프레임워크를 IOC 컨테이너라고 하며 대표적으로는 spring 프레임워크가 있습니다.
의존성 주입은 프레임워크가 없어도 구현할 수 있는 패턴이지만 컨테이너가 제공해주는 다양한 기능 (싱글톤, 의존성 자동 주입)등을 사용하기 위해서 보통은 프레임워크를 사용합니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요.

const arr = [1, 2, 3, 4, 5];
const newArr = arr.map((x) => x * 2); 
console.log(arr);// [ 1, 2, 3, 4, 5 ]
console.log(newArr); // [ 2, 4, 6, 8, 10 ]

아직은 자바스크립트가 미숙하고 함수형프로그래밍도 깊이 공부한 적이 없어서 간략한 예제를 들고 왔습니다.
javascript의 map함수는 배열의 요소를 돌며 각 요소에 콜백함수를 수행하고 새로운 배열을 만들어서 반환합니다.

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

type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (e) {
        reject(e);
      }
    }, 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));

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

강의를 통해서 멘토님의 경험에서 나오는 팁들을 알아가고 싶습니다.

사전 과제 제출

사전과제

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

    • 언어 상관없음
    • 어떤 로직이든 상관없음
    • 단, 길이가 길지 않은 함수 단위가 좋습니다

    연습을 하며 문제를 풀 때 배열의 합을 구하는 과정이 필요한 곳이 많았는데 함수로 만들어 사용했었습니다. 그래서 간편했습니다.

function sumOfArray(arr) {
    let result = 0
    for (let i = 0; i < arr.length; i++) {
        result += arr[i]
    }
    return result
}
  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    "n-계층 아키텍처" 라고도 불립니다. 계층 아키텍처는 소프트웨어 시스템이 여러 계층으로 구성되고 각 계층이 특정 목적을 수행하는 소프트웨어 설계 패턴입니다. 레이어는 일반적으로 계층 구조로 구성됩니다.
    계층 아키텍처에서 계층을 구성하는 다양한 방식이 있지만 일반적인 방식은 다음과 같습니다.
  • presentation layer
  • business-logic layer
  • data-access layer
  • data-storage layer
    계층 아키텍처의 주요 이점 중 하나는 관심사의 분리를 통해 시스템을 더 쉽게 유지보수 할 수 있게 됩니다. 또한 서로 다른 계층을 독립적으로 개발하고 테스트 할 수 있어 개발 프로세스가 보다 효율적이게 됩니다. 하지만 관리하고 통신하는 레이어가 많아지기 때문에 복잡성과 오버헤드가 추가로 발생할 수 있다는 단점도 있습니다.
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    클래스 또는 함수가 종속성을 직접 만들지 않고 외부 소스에서 받을 수 있도록 하는 소프트웨어 디자인 패턴입니다. 종속성은 기능을 수행하기 위해 클래스 또는 기능에 필요한 개체 또는 서비스입니다.
    종속성 주입을 사용하는 이유는 소프트웨어 시스템의 다양한 구성 요소를 분리하여 수정 및 유지 관리를 더 쉽게 만드는 데 도움이 되기 때문입니다. 종속성을 클래스나 함수 내에서 만드는 대신 클래스나 함수에 주입하면 클래스나 함수가 더욱 모듈화되고 테스트하기 쉬워집니다.
class UserService {
  constructor(repository) {
    this.repository = repository;
  }
}

class UserRepository {
  constructor() {
    this.users = [];
  }
}

const repository = new UserRepository();
const service = new UserService(repository);

위의 예제에서 UserService 클래스는 자체 생성이 아니라 생성자를 통해 저장소 종속성을 받습니다. 이를 통해 UserService 클래스는 UserRepository 클래스를 다양한 구현과 함께 사용할 수 있으므로 더 모듈화 되고 테스트 하기 쉽습니다.
종속성 주입은 생성자 주입, 세터 주입, 함수 주입 등 다양한 방법으로 구현이 가능합니다.
4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
Javascript에서 함수형 프로그래밍의 몇 가지 일반적인 기능들
일급함수, 고차함수, 순수함수가 있습니다.

// 두 숫자를 더하는 순수함수
function add(x, y) {
  return x + y;
}

// 함수와 값을 인자로 받는 고차 함수
// 항상 주어진 값을 반환하는 새 함수를 반환
function always(fn, value) {
  return function() {
    return value;
  }
}

// 항상 5를 반환하는 새 함수
const alwaysFive = always(add, 5);
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

    type SomeFunctionReturnString = () => string
    
    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
      return new Promise((resolve, reject) => {
      setTimeout(() => {
          try {
            resolve(f());
          } catch (e) {
            reject(e);
          }
        }, 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
    after 2 seconds
    successfully done
    Error: failed
    
  2. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    다양한 것들을 많이 경험해보고 내가 정말 재미있어하는 것을 찾고 싶습니다. 잘 부탁드립니다!

사전 과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
async parseAllCategory(allCategory) {
    let categoryIds = [];
    let categories = [];

    for (let i = 0; i < allCategory.length; ++i) {
      categoryIds.push(allCategory[i]._id);
    }

    // 메인 카테고리 수 만큼 배열을 순회
    for (let i = 0; i < categoryIds.length; ++i) {
      let subCategoryNames = [];
      const subCategories = await this.subCategoryModel.findByCategoryIdAll(categoryIds[i]);

      // 메인 카테고리에 해당하는 서브카테고리 수 만큼 배열을 순회하며 서브카테고리명을 배열에 저장
      for (let j = 0; j < subCategories.length; ++j) {
        subCategoryNames.push(subCategories[j].subCategoryName);
      }

      let { categoryName } = await this.categoryModel.findById(categoryIds[i]);

      // { 키: 메인카테고리명, 값: 서브 카테고리 배열} 객체 생성후 배열에 push
      let tmpCategory = {};
      tmpCategory[categoryName] = subCategoryNames;
      categories.push(tmpCategory);
    }

    return categories;
  }

간단 로직 설명 및 공유 이유

  • db에 존재하는 모든 카테고리(메인카테고리 - 서브카테고리)를 client에 전달하기 위해 작성한 파싱함수
  • 챌린지 이후 고차함수를 활용 해 조금 더 자바스크립트 다운 코드로 리팩토링 해보고 싶음

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층 아키텍쳐

  • S/W 개발에서 가장 일반적으로 사용되는 아키텍처
  • 구성되는 계층의 숫자에 따라 N 계층 (N-tier) 아키텍처 라고 함
  • 각 계층은 app내에서의 특정 역할 (예: 화면 표시, 비즈니스 로직 수행, DB 통신 등) 별로 구분 됨
  • 따라서 특정 계층의 구성요소는 해당 계층에 관련된 기능만 수행
  • 장점: 유지보수와 테스트에 용이

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성 주입이란?

  • 클래스간 의존성을 클래스 외부에서 주입하는 것
    • 클래스에 대한 의존성의 인터페이스화를 통한 코드 유연성 증대 + 클래스의 인스턴스를 외부에서 생성하여 주입

의존성 주입의 필요성

  • 클래스간의 결합도가 약해져, 리펙토링과 테스트가 편해진다
  • 인터페이스 기반 설계는 코드를 유연하게 하여 확장이 쉬워진다
  • UI가 있는 프로그램에서는 생명 주기가 중요한데, 생명주기별로 Container를 관리할 수 있게 된다면 리소스의 낭비를 막을 수 있다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Array.prototype.reduce()

  • arr.reduce(callback[, initialValue])
  • 배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환

예제

var arr = [1,2,3,4,5,6,7,8,9,10];
arr.reduce(function(prev, cur) {
  return prev + cur;
}); // 55

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

type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  // 해당 함수 내부를 구현해 주세요
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      }catch (e) {
        reject(e);
      }
    }, seconds * 1000);
  });
}

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

  • node.js 백엔드 개발자로서의 역량 강화
  • 취업

사전과제 제출!

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
getChatRoomInfo(roomName: string): string[] {
    const tmp: string[] = [];
    this.rooms.get(roomName).users.forEach((e) => {
      tmp.push(e.intra);
    });
    return tmp;
  }

전체 채팅방을 임시 배열에 담아서 return해주는 코드

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    각 계층은 어플리케이션 내에서의 특정 역할과 관심사(화면 표시, 비즈니스 로직 수행, DB작업 등) 별로 구분된다. 이는 Layered Architecture의 강력한 기능인 '관심사의 분리' 를 의미한다. 특정 계층의 구성요소는 해당 계층에 관견된 기능만 수행한다. 이런 특징은 높은 유지보수성과 쉬운 테스트

  2. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    개념 : 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것!
    장점 1 : 의존성이 줄어든다.
    장점 2: 재사용성이 높은 코드가 된다
    장점 3: 테스트하기 좋은 코드가 된다.
    장점 4: 가독성이 높어진다!

  3. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

var condition = function(x) { return x % 2 === 0; }
var ex = function(array, cond) {
  return array.filter(cond);
};
ex(arr, condition);

condition이라는 변수를 인자로 받아서 조건에 맞는 arr배열 내의 값을 return 하는 순수함수 입니다.

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

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
           try {
            resolve(f());
           } catch (e) {
           reject(e);
         }
        }, seconds * 1000);
      });
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    주기적으로 공부를 하는 시간을 가지게 되어서 유익한 지식함량의 시간이 되었으면 좋겠다!

사전 과제 제출

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

Nest.js 프레임워크와 TypeORM 을 사용하여 진행했던 프로젝트입니다.
'참가중인 채팅방 목록' 을 불러오는 함수이며, TypeORM 의 QueryBuilder 를 사용해
OutputType 을 새로 지정하여 return 했습니다.
채팅방은 1:1 채팅방만 존재하기에 Host, Guest( chatPair )로 Status를 구분했습니다.
마지막 'result' 부분을 타입을 지정해주지 않았는데 (빈 값이 올 수 있어서)
이 부분을 타입을 어떻게 지정해야 할 지,
중간중간 Typescript 형식이 아닌 Javascript 형식으로 변수 선언을 한 부분이 있는데
이 부분은 어떻게 develop 할 수 있을지 조언을 얻어보고자 코드를 공유드립니다.

 /**
   * Find ChatRooms (Joined)
   * 내가(dogId) 참가한 모든 채팅방들 찾아오기.
   * Host, Guest 인 모든 채팅방을 찾아서
   * 채팅방 id, 대화상대 정보, 마지막 채팅메시지를 찾아
   * 가장 최신 대화 순으로 정렬해 반환한다.
   * @param dogId 내 강아지 id
   * @returns 찾은 채팅방들의 정보들.
   */
  async findChatRooms({ dogId }) {
    // 내가 host인 채팅방들
    const hostRoomsInfo = await this.chatRoomsRepository.find({
      where: { dog: { id: dogId } },
      relations: { dog: true },
    });
    // 내가 guest인 채팅방들
    const guestRoomsInfo = await this.chatRoomsRepository.find({
      where: { chatPairId: dogId },
      relations: { dog: true },
    });
    // 방 정보들 합치기
    const myRoomsInfo = [...hostRoomsInfo, ...guestRoomsInfo];

    // 채팅 상대방 강아지 정보 가져오기
    // 1. 내가 host일 때 - 상대방이 guest
    const chatGuestDogs = [];
    for (const chatRoom of hostRoomsInfo) {
      const chatGuestDog = await this.dogsRepository.findOne({
        where: { id: chatRoom.chatPairId },
        relations: { img: true },
      });
      chatGuestDogs.push(chatGuestDog);
    }
    // 2. 내가 guest일 때 - 상대방이 host
    const chatHostDogs = [];
    for (const chatRoom of guestRoomsInfo) {
      const chatHostDog = await this.dogsRepository.findOne({
        where: { id: chatRoom.dog.id },
        relations: { img: true },
      });
      chatHostDogs.push(chatHostDog);
    }
    // 상대방 강아지 정보들 합치기
    const chatPairDogs = [...chatGuestDogs, ...chatHostDogs];

    // 채팅방의 마지막 메시지 가져오기
    const lastMessages = [];
    for (const chatRoom of myRoomsInfo) {
      const findLastMessageByChatRoomId = await this.dataSource
        .getRepository(ChatMessage)
        .createQueryBuilder('chatMessage')
        .where('chatMessage.chatRoomId = :id', {
          id: chatRoom.id,
        })
        .orderBy('chatMessage.chatCreatedAt', 'DESC')
        .getOne();
      lastMessages.push(findLastMessageByChatRoomId);
    }

    let result = [];
    myRoomsInfo.map((chatRoom, idx) => {
      const output = new ChatRoomsOutput();
      output.id = chatRoom.id;
      output.chatPairDog = chatPairDogs[idx];
      output.lastMessage = lastMessages[idx];
      result.push(output);
    });

    // 최신 메시지 순으로 결과값 정렬
    result = result.sort(
      (a, b) => b.lastMessage.chatCreatedAt - a.lastMessage.chatCreatedAt,
    );

    return result;
  }

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층 아키텍처는 Application 설계 및 개발 시, 개발 목적에 따라 Layer(계층)을 논리적/물리적으로 나누어
각 계층의 독립성 및 유지보수성을 높이는 데에 그 목적이 있습니다. (일반적으로 3-tier, 4-tier 의 Layer로 나누곤 합니다.)
흔히 웹 개발에 사용하는 MVC 패턴도 이 계층 아키텍쳐에서 비롯되어 있습니다.
유지보수성, 독립성에 있어서 많은 장점을 가져오는 이 계층 아키텍쳐도
각 계층들이 '격리' 되어있기에 이 계층들을 연결하는 Infrastructure에 '의존'하게 된다는 단점 또한 존재합니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성 주입에 대해 이해하기 위해서는 loose Coupling(느슨한 결합)에 대해 이해할 필요가 있고,
느슨한 결합을 이해하기 위해서는 Tight Coupling(강한 결합)에 대해 이해할 필요가 있습니다.
강한 결합은 각각의 클래스(혹은 메소드)들이 서로의 변화가 서로에게 영향을 미치는 상태를 표현합니다.
A와 B가 강한 결합으로 이루어져 있다면, B는 A에서만 쓰일 수 있으며 B가 없이는 A가 완성 될 수 없는 상태를 말하는데요,
느슨한 결합은 각각의 클래스(혹은 메소드)들이 서로의 변화가 서로에게 영향을 미치지 않는 상태를 표현합니다.
A와 B가 느슨한 결합으로 이루어져 있다면, A는 B 대신 C를 사용할 수도 있고, B는 꼭 A가 아닌 Z에도 쓰일 수 있게 됩니다.

DI, 의존성 주입은 이렇게 각각의 클래스들의 의존 관계를 분리하여
의존 대상의 변화에 취약한 강한 결합을 느슨한 결합으로 대체하는 것이고
이를 통해 재사용성, 테스트 용이성, 가독성을 높이는 장점들을 가져올 수 있습니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

JS에서 사용되는 배열 내의 메소드들은
JS에서 사용되는 데이터들을 함수형 프로그래밍을 통해 다루는 좋은 예시가 됩니다.

const arr = [1, 2, 3, 4, 5];
const exFnc = arr.map( function(val) {
    return val + 10;
});

console.log(exFnc);

출력결과

[11, 12, 13, 14, 15]

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        return new Promise<string>((success, fail) => {
            setTimeout(() => {    
                try {
                    success(f())
                } catch(e){
                    fail(e);
                }
            }, seconds * 1000);
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

실제 실무에서 사용되는 함수형 프로그래밍에 익숙해지고 싶고
추가적으로 기회가 된다면 테스트 코드를 작성하는 법에 대해
그리고 테스트 코드의 실제적 적용에 대해 배워보고 싶습니다!

사전 과제 제출

사전과제

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
let count = [0, 0, 0, 0];
function totalcount(data) {
  data.map((e) => {
    if (e.choice === 1) {
      ++count[0];
    } else if (e.choice === 2) {
      ++count[1];
    } else if (e.choice === 3) {
      ++count[2];
    } else if (e.choice === 4) {
      ++count[3];
    }
  });
  let totalcount = count[0] + count[1] + count[2] + count[3];
  return totalcount;
}

const VoteRepository = require("../repositories/vote.repository");

class VoteService {
  voteRepository = new VoteRepository();

  postVote = async (userKey, selectKey, choice) => {
    const isSelect = await this.voteRepository.findOneSelect(selectKey);

    if (!isSelect) throw new ErrorCustom(400, "해당 선택글이 존재하지 않습니다.");
    if (userKey === isSelect.userKey) throw new ErrorCustom(400, "본인 글에는 투표할 수 없습니다.");
    if (isSelect.completion === true) throw new ErrorCustom(400, "투표가 마감되었습니다.");

    const voteCheck = await this.voteRepository.findOneVote(selectKey, userKey);
    if (!voteCheck) {
      await this.voteRepository.createVote(selectKey, userKey, choice);

      let votePoint = await this.voteRepository.incrementPoint(userKey);
      const allVotes = await this.voteRepository.findAllVote(selectKey);
      const total = totalcount(allVotes);

      function rate(i) {
        const num = (count[i] / total) * 100;
        return Math.round(num * 100) / 100;
      }

      return {
        1: rate(0), 2: rate(1), 3: rate(2), 4: rate(3),
        total,
        isVote: choice,
        votePoint: votePoint.point,
      };
    } else {
      throw new ErrorCustom(400, "이미 투표를 실시했습니다.");
    }
  };
}

팀프로젝트를 진행 하면서 게시물에 투표를 실시하는 서비스 로직입니다.
다른 서비스 로직에서도 사용할 수 있게 총 투표수를 합산하는 함수를 만들어 사용했습니다.
DB에서 게시물의 유무, 작성자의 게시물인지, 투표를 진행 했는지 등을 확인하여 게시물에 투표를 할 수 있도록 만들었습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층을 분리해서 관리하는 아키텍처 패턴
현재 가장 흔하게 사용되고 있는 아키텍처 패턴 중 하나
단순하고 대중적이면서 비용도 적게 들어 모든 어플리케이션의 사실상 표준 아키텍처
계층을 분리해서 유지하고, 각 계층이 자신의 바로 아래 계층에만 의존하게 만드는 것이 목표

3계층 아키텍처의 계층

  • 프레젠테이션 계층 (Presentation Layer)
  • 비즈니스 로직 계층 (Business Logic Layer)
  • 데이터 엑세스 계층 (Persistence Layer)

계층형 아키텍처 패턴의 장점

  • 각 계층별로 의존성이 낮아 모듈을 교체하더라도 코드 수정이 용이함
  • 각 계층별로 단위 테스트를 작성할 수 있어 테스트 코드를 조금 더 용이하게 구성할 수 있음

3계층 아키텍처의 3가지 처리과정

  1. Controller : 어플리케이션의 가장 바깥 부분, 요청/응답을 처리함
    클라이언트의 요청을 처리 한 후 서버에서 처리된 결과를 반환해주는 역할
  2. Service : 어플리케이션의 중간 부분, 실제 중요한 작동이 많이 일어나는 부분
    아키텍처의 가장 핵심적인 비즈니스 로직이 수행되는 부분
  3. Repository : 어플리케이션의 가장 안쪽 부분, DB와 맞닿아 있음
    실제 데이터베이스의 데이터에 접근

처리과정 플로우

  1. 클라이언트(Client)가 요청(Request)을 보낸다.
  2. 요청(Request)을 URL에 알맞은 컨트롤러(Controller)가 수신받는다.
  3. 컨트롤러(Controller)는 넘어온 요청을 처리하기 위해 서비스(Service)를 호출한다.
  4. 서비스(Service)는 필요한 데이터를 가져오기 위해 저장소(Repository)에게 데이터를 요청한다.
  5. 서비스(Service)는 저장소(Repository)에서 가져온 데이터를 가공하여 컨트롤러(Controller)에게 데이터를 넘긴다.
  6. 컨트롤러(Controller)는 서비스(Service)의 결과물(Response)을 클라이언트(Client)에게 전달해준다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

클래스간 의존성을 클래스 외부에서 주입하는 것을 뜻함
객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것

의존성 주입의 장점

  • 의존성이 줄어든다.
  • 재사용성이 높은 코드가 된다.
  • 테스트하기 용이하다.
  • 가독성이 높아진다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

let arr = [1, 2, 3, 4, 5, 6];

// map 함수
let double = arr.map((x) => x * 2);
console.log(double); // [2, 4, 6, 8, 10, 12]

// filter 함수
let even = arr.filter((x) => x % 2 === 0);
console.log(even); // [2, 4, 6]

// reduce 함수
let add = arr.reduce((acc, cur) => acc + cur, 0);
console.log(add); // 21

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

type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((res, rej) => {
    setTimeout(() => {
      try {
        console.log(`after ${seconds} seconds`);
        res(f());
      } catch (err) {
        rej(err);
      }
    }, 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
after 2 seconds
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

개발 공부를 시작한지 얼마 되지 않아 기초가 많이 부족한것을 알고 있기에,
다른 사람들은 어떤 방법으로 코드를 짜야는지 어떤 것이 더 옳고, 효율적인지 등
다양한 코드를 보면서 기본적인 지식을 늘리고 더 나은 코드를 만들고 싶습니다.

사전과제

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
updateTree: async (ctx) => {
   const _ = ctx.request.body
   if(_.departments) {
     let index = 0
     for(let d in _.departments) {
       let depart = await models.department.findByPk(_.departments[d].id)
       depart.order = index
       depart.depth = 1
       depart.save()
       index++
      if(_.departments[d].children) {
         checkTreeNode(_.departments[d].children, depart.id, 2)
       }
     }
   } else {
    response.noContent(ctx)
   }
 }
async function checkTreeNode(nodes, parentId, lv) {
 if(nodes.length > 0) {
   nodes.map((node, index)=>{
     let depart = await models.department.findByPk(node.id)
       depart.order = index + 1
       depart.depth = lv
       depart.parentId = parseInt(parentId)
       depart.save()
       index++
       if(node.children)
         checkTreeNode(node.children, node.id, lv+1)
   })
 }
}

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

someArr.map((item,index)=> item.value)
someArr.filter((item,index)=> item.value > 10)
someArr.sort((a,b)=>a - b)
someArr.reduce((cur,nv)=> cur+nv, 0)

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

    type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string>{
        // 해당 함수 내부를 구현해 주세요
        return new Promise((resolve,reject)=>{
 setTimeout(()=>{
   try {
     resolve(f());
 }
 catch (e) {
     reject(e)
 }
 },seconds * 1000)
})
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
export function myPromiseAll(arr) {
  if (!arr?.length) return Promise.reject('No promise!');
  return new Promise((resolve, reject) => {
    const data = [];
    let pending = arr.length;
    console.time('Async!');
    arr.map((el, idx) =>
      el(idx + 1)
        .then((res) => {
          data[idx] = res;
          pending--;
          if (pending === 0) {
            resolve(data);
            console.timeEnd('Async!');
          }
        })
        .catch((err) => reject(err))
    );
  });
}

자바스크립트를 공부할 당시 자바스크립트 자체 내장 모듈들을 직접 구현해보며 공부했던 경험이 기억에 남습니다. Promise에 관한 온전한 이해가 쉽지 않았던 상황에서 해당 메소드 들을 구현해보며 Promise의 작동 방식에 대해 조금 더 이해할 수 있게 되었습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층 아키텍처는 비지니스 로직과 UI로직을 분리하여 독립된 모듈로 나누어서 구성하는 API패턴입니다. 각각 역할에 따라 연결되어 전체의 시스템을 구현하는 아키텍쳐입니다. 일반적으로 Presentation layer, Business layer, Persistence layer로 구성되어 있으며 복잡하지 않고, 비용도 저렴하므로 소규모 프로젝트에 적합한 아키텍쳐라고 보여집니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency는 의존한다는 의미입니다.
예를 들어 A는 B에 의존하는 관계가 있다면, B가 변화할 시 A도 변화하기 마련입니다.
Dependency Injection이란 이러한 의존성을 클래스 내부에서 결정하는 것이 아니라 외부에서 사용자가 의존관계를 결정하고 주입하는 것을 의미합니다.
실제 코드에서는 의존관계를 인터페이스로 추상화 하여 외부에서 생성자를 통해 클래스 내부로 주입시키는 방식으로 진행됩니다.
이러한 DI가 필요한 이유는 인터페이스 추상화를 통해 진행되기 때문에 주입받는 대상이 변하더라도 코드 자체를 수정할 일이 줄어듭니다. 이를 통해서 의존성을 줄일 수 있습니다. 또한 클래스 분리가 쉬워지며 이로 인해 테스트하기가 용이해집니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

함수를 인수로 받을 수 있고, 함수의 반환 값으로써 사용할 수 있는 함수들을 고차 함수라고 부르며, Javascript에서 이를 지원하고 있습니다. 이를 바탕으로 콜백함수로 활용이 가능합니다. 또한 렉시컬 환경을 통해 클로저를 활용할 수 있으며 이를 통해서 순수 함수를 구현할 수도 있습니다.

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

type SomeFunctionReturnString = () => string;

const SECONDS: number = 1000;
const SUCCESS_STATEMENT: string = 'successfully done';
const FAIL_STATEMENT: string = 'failed';

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  // 해당 함수 내부를 구현해 주세요
  return new Promise<string>((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (e) {
        reject(e);
      }
    }, seconds * SECONDS);
  });
}

const success = () => {
  return SUCCESS_STATEMENT;
};

const fail = () => {
  throw new Error(FAIL_STATEMENT);
};

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. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

프리온보딩을 진행하며 JS로 백엔드를 공부하는데에 도움이 될 만한 지식들을 얻어가고 싶습니다. 일급함수를 지원하는 JS의 이점을 살려 함수형 프로그래밍 또한 잘 사용할 수 있도록 학습하고 싶습니다. 추후 OOP와 FP를 잘 활용하여 유지보수하기 좋고 가독성이 좋은 코드를 작성하는 개발자로 성장하기 위한 조그마한 발판으로 삼고 싶습니다.

사전과제 제출

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

//controller
//인가코드와 state로 네이버 oAuth 토큰 가져오기(NestJS)
@Post('naver/token')
  async getToken(@Body() { code, state }: NaverGetCode) {
    const result = await this.authService.getNaverToken(code, state);
    if (result === false) {
      return '네이버 토큰발급 실패';
    }
    return `네이버 토큰 발급 성공`;
  }
//service
//async await 사용
export class AuthService {
   async getNaverToken(code: string, state: string) {
       const data: any = {
         grant_type: 'authorization_code',
         client_id: process.env.NAVER_ID,
         client_secret: process.env.NAVER_PW,
         code,
         state,
       };
       const response: any = await this.tokenFetch(data);
       return response;
   }


  async tokenFetch(data: any) {
    const queryString = Object.keys(data)
      .map(
        (k: any) => encodeURIComponent(k) + '=' + encodeURIComponent(data[k]),
      )
      .join('&');

    const url = 'https://nid.naver.com/oauth2.0/token?' + queryString;
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    }).then((res) => res.json());

    return response;
  }
}

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

특정 역할로 구분되는, 예를 들어 화면 UI/비즈니스 로직/DB 작업등의 각각의 계층으로 설계하여 각 계층에 해당하는 역할만 수행하고 이 계층은 수직적으로 연결되어 있다. 유지보수와 확장 및 테스트가 쉽다는 장점이 있지만 단일 개체 서비스에서는 불필요한 연결과 의존하는 개체가 많아져 변경에 영향을 많이 받는 코드가 될 수 있다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

소스 코드의 수정, 변경 등에 영향을 많이 받는 강하게 결합된 클래스들을 분리하고, 애플리케이션 실행 시점에 객체 간의 관계를 결정해 줌으로써 결합도를 낮추고 유연성을 확보할 수 있다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

<?php
//$min 보다 큰 항목만 걸러내는 익명 필터 함수
function criteria_greater_than($min)
{
    return function($item) use ($min) {
        return $item > $min;
    };
}

$input = [1, 2, 3, 4, 5, 6];

// 동적으로 만들어낸 필터 함수를 array_filter 에 전달해서 입력을 필터링한다.
$output = array_filter($input, criteria_greater_than(3));

print_r($output); // 3보다 큰 숫자만 출력된다.

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    // 해당 함수 내부를 구현해 주세요
return new Promise((resolve, reject) => {
    const timeout = seconds * 1000;
    const handler = () => {
      try {
        const result = f();
        resolve(result);
      } catch (error) {
        reject(error);
      }
    };
    setTimeout(handler, timeout);
  });
};

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
after 2 seconds
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

NestJS 개념과 구조를 이해하고 새로 만들 애플리케이션에 적절한 방법을 찾아 잘~ 적용하고 싶습니다.

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
function filecheck($filename, $type = 'img') {
	// 파일명 검증
	if (empty($filename)) {
		return false;
	}

	// 확장자 분리
	$tmp = explode('.', $filename);
	$ext = $tmp[1];
    
	// 파일 형식 설정
	$haystack = array();
	switch($ext) {
		case 'img':
			$haystack = array('jpg', 'jpeg', 'png', 'gif');
			break;
		case 'excel':
			$haystack = array('xlsx', 'xls', 'csv');
			break;
		// 필요한 파일형식 조건 추가
	}

	// 확장자 검증
	if (in_array($ext, $haystack)) {
		return true;
	}
    
	return false;
}

제 블로그 인기글 중에 있는 코드여서 올려봅니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

  • 아키텍쳐의 컴포넌트들은 각각 어플리케이션의 특정한 역할을 수행하도록 가로로 나누어져 계층을 이룬다.
  • 가장 널리 알려진 아키텍쳐로 전통적인 IT workflow 와 조직 구성과 잘 맞아 떨어져서 많은 비즈니스에서 채택된다.
  • 주로 3가지 계층으로 이루어져 있다.
  • Presentation Layer: 유저 + 브라우저와 상호작용
  • Business Layer: 요청에 맞는 비즈니스 로직을 수행
  • persistence Layer: 데이터를 저장하고 관리
  • 각각의 계층은 다른 계층과 상호작용하지만, 다른 계층에서 발생하는 로직에는 신경쓰지 않아도 된다. 예를 들어, 데이터를 다루는 persistence layer는 그 데이터가 보여지는 presentation layer를 신경쓰지 않아도 되며, 오로지 자신의 역할에만 집중하면 된다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성 주입(Dependency Injection, DI)은 프로그래밍에서 구성요소간의 종속성을 소스코드에서 설정하지 않고 외부의 설정파일 등을 통해 컴파일 시점이나 실행 시점에 주입하도록 하는 디자인 패턴 중의 하나이다. - 위키백과

  • 의존성을 낮춘다.
  • 코드의 재사용성을 높인다.
  • 테스트하기 좋은 코드가 된다.
  • 가독성이 높아진다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

<?php
$input = [1, 2, 3, 4, 5, 6];

// 익명 함수를 하나 만들어서 변수에 대입
$filter_even = function($item) {
    return ($item % 2) === 0;
};

// array_filter 내장 함수는 배열과 함수를 인자로 받는다.
$output = array_filter($input, $filter_even);

// 익명 함수를 변수에 할당해서 전달할 필요없이 이렇게 하는 것도 가능하다.
$output = array_filter($input, function($item) {
    return ($item % 2) == 0;
});

print_r($output);

PHP는 일급 함수(first-class function)를 지원합니다. 이는 함수가 변수에 할당될 수 있다는 것입니다. 사용자가 정의한 함수나 내장 함수 모두 변수에 의해서 참조될 수 있고 동적으로 호출될 수 있습니다. 함수는 다른 함수의 인자로 전달될 수 있고 함수가 다른 함수를 리턴값으로 리턴하는 것도 가능합니다. 이런 기능을 고차함수(Higher-order function)라고 합니다.

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

type SomeFunctionReturnString = () => string;

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    const timeout = seconds * 1000;
    const handler = () => {
      try {
        const result = f();
        resolve(result);
      } catch (error) {
        reject(error);
      }
    };
    setTimeout(handler, timeout);
  });
}

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

서비스하고 있는 레거시 시스템 개편과 개인적으로 준비하고 있는 서비스에 FP로 접목하고 싶습니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    오브젝트의 속성 이름을 변경할 때, 사용하기 위한 타입입니다.
    DB 모델의 속성과 Endpoint에서 요구하는 속성의 이름이 다를 때, 타입을 두 개를 만들어줘야 합니다.
    이때 하드코딩하는 방법도 존재하지만, 하드코딩 보다는 타입을 확장해서 사용하는 것이 미래에 코드가 수정이 될 때, 동적인 코드가 변경할 것이 더 적을 것이다 라고 판단하여 작성하게 되었습니다.
export type RenameProperties<
  T extends {},
  M extends { [key: string]: keyof T }
> = {
  [K in keyof M]: T[M[K]];
} & {
  [K in Exclude<keyof T, M[keyof M]>]: T[K];
};
  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    Persistance, Service, Presentation 레이어 등 여러 레이어로 나누어지는 아키텍쳐입니다.
    예를 들어, Persistance에서는 DB에 대한 쿼리 로직, Service에서는 요청을 처리하는 로직, Presentation에서는 데이터를 보여주는 로직 등으로 분리하면, 각 레이어에서 자신이 맡은 일을 정확하게 하고 다음 레이어로 데이터를 전달하면 다음 레이어에서 자신의 역할을 다하고 또 다음 레이어로 전달하는 형태로 구조가 되어 있습니다.
    이것은 관심사의 분리를 통해 역할을 적절하게 나누어 각 레이어의 작업을 명확하게 할 수 있습니다.

  2. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    어떤 클래스 A가 B에 대해 의존성을 가지고 있을 때, B의 기능이 변경되면, A 또한 변경됩니다.
    이러한 A와 B의 의존성을 분리하기 위해서 사용하는 것이 DI입니다.
    DI는 A가 가지는 의존성을 B 뿐만 아니라, C, D 등 다른 객체에도 적용할 수 있도록 해줍니다.
    이것은 A의 객체를 생성할 때 다른 객체를 넣어주거나, 저장된 객체를 변경해주는 메서드를 통해서 구현되고는 합니다.
    이러한 행위는 의존성을 외부에서 정해주는 것으로 보여지고 의존성 주입이라는 용어로서 나타나게 되었습니다.

    DI는 의존성을 느슨하게 해주고, 덕분에 재사용성이 높은 코드 작성을 가능하게 해 줍니다.
    하나의 예로 콘서트의 정보를 나타낼 때, List 클래스가 존재하고, 여기에 Timeline을 주입하면, Timeline List가 되고, Artist를 주입하면, Artist List가 되기도 합니다.
    이처럼 DI를 통해 재사용성이 좋은 코드를 작성할 수 있습니다.

  3. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    Array.prototype.map, Array.prototype.forEach 등 JS(TS)에서 기본적으로 지원하는 메서드가 많이 존재합니다.
    이러한 함수들은 아래와 같이 사용이 가능합니다.

function adder(add: number) {
  return (num: number) => num + add
}
const add10 = adder(10);
console.log(add10(20));
console.log([1, 2, 3].map(add10));
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  // 해당 함수 내부를 구현해 주세요
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(f());
      } catch (error) {
        reject(error);
      }
    }, seconds);
  });
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    혼자서 공부를 하면서 알지 못한 부분들에 대해서 얻어가고 싶고, 작은 프로젝트를 할 때에는 "이것이 필요한가? 중요한가?" 의문이 들었던 부분들 중 특히 실무에서 꼭 필요로 하는 부분들을 얻어가고 주니어 개발자로서의 역량을 키우고 싶습니다.

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
char	*ft_strdup(char *str) {
	if (str == NULL)
		return NULL;
	int		strLen = strlen(str);
	char	*ret = malloc(sizeof(char) * (strLen + 1));
	if (ret == NULL)
		return NULL;
	for (int i = 0; i < strLen; i++) {
		ret[i] = str[i];
	}
	ret[strLen] = 0;
	return (ret);
}
  • 공유하고 싶은 이유 : C언어를 처음 시작할 때 동적 할당을 이해하고 작성했던 코드입니다.
    자주 사용했던 기능이라서 기억에 가장 남습니다.
  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
  • Layered Architecture는 소프트웨어 개발에서 가장 일반적으로 널리 사용되는 아키텍처이다.
  • 구성되는 계층의 숫자에 따라 N-tier Architecture라고 한다.
  • 각 계층은 어플리케이션 내에서의 특정 역할과 관심사(화면 표시, 비즈니스 로직 수행, DB 작업 등)별로 구분된다.
  • 특정 계층의 구성요소는 해당 계층에 관련된 기능만 수행하여 유지보수성이 높고, 테스트가 쉽다.
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
  • Dependency Injection : 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것이다.
  • Dependency Injection의 장점
    1. 의존성이 줄어든다.
    2. 재사용성이 높아진다.
    3. 테스트하기 좋은 코드가 된다.
    4. 기능들이 별도로 분리되어 가독성이 높아진다.
  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
  • 함수형 프로그래밍을 아직 잘 모르겠습니다.
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
	return new Promise<string>((success, fail) => {
		setTimeout(() => {
			try {
				success(f());
			} catch (e) {
				fail(e);
			}
		}, seconds * 1000);
	})
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  • TypeScript와 NestJs에 대하여 깊이 이해하여 사용할 수 있었으면 좋겠습니다.

사전 과제 제출

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

router.get('/home', (req,res) => {
  if (req.user == undefined) {
    res.render('main.njk', {
      title: 'To do app',
    })
  }else{
    console.log(`${req.user.name}님 접속을 환영합니다.`);
    res.render('main.njk', {
      title: 'To do app',
    })
  }
});

첫 개인프로젝트인 To Do App 을 만들 때 가장 먼저 만든 코드입니다.

머리로 생각만 하고 있는 것과 직접 코드를 짜려고 시도하는 것에는 큰 차이가 있다는 것을 처음 경험했습니다.

프로그래밍은 머리속으로 생각만 하는 것이 아닌 직접 코드를 짜보는 것이 정말 중요하다는 소중한 의미를 일깨워준 코드입니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

관심사의 분리 라는 개념이 핵심이 되는 아키텍처입니다.
각 계층은** 특정 역할**을 가지며, 해당 계층에 관련된 기능만 수행합니다.
장점은 높은 유지보수성과 쉬운 테스트입니다.

일반적으로 Presentation / Business / Persistence / Database 4계층으로 나누지만 상황에 따라 3계층이 될 수도, 5계층이 될 수도 있습니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency Injection(의존성 주입) 이란 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉을 의미한다.

의존성 주입의 목적은 객체의 생성과 사용의 관심을 분리하는 것이다.
이는 가독성과 코드 재사용을 높여준다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

const arr = [1,2,3,4,5,6,7,8,9,10];
arr.reduce(function(prev, cur) {
    return prev + cur;
});

js의 내장 함수인 reduce는 대표적인 함수형 프로그래밍의 예제입니다.

함수형 프로그래밍은 하나 이상의 인자를 받고, 받은 인자를 이용하여 반드시 결과물을 돌려주어야 합니다.

그리고 바꾸고자 하는 변수 외에 다른 변수를 바꾸는 부작용이 없어야합니다.

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

// 실력이 부족하여 다른 분들의 코드를 참고했습니다.

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
            try {
              resolve(f());
            } catch (e) {
              reject(e);
            }
          }, seconds * 1000);
        });
      };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));
결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

이번 챌린지를 통해 제게 부족한 부분들을 보충하고 더 나은 개발자로 한걸음 더 나가고 싶습니다.

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
public static String awards(Cars cars) {
    for (Car car : cars.getCar()) {
        if(car.getDistance() == maxDistance) {
            winner += car.getName() + ",";
        }

        else if(car.getDistance() > maxDistance) {
            maxDistance = car.getDistance();

            winner = car.getName() + ",";
        }
    }

    return winner.substring(0, winner.length() - 1);
}
public static String awards(Cars cars) {
    int maxDistance = cars.getCar().stream()
        .mapToInt(v -> v.getDistance())
        .max()
        .getAsInt();

    cars.getCar().stream()
        .filter(car -> car.getDistance() == maxDistance)
        .collect(Collectors.toList())
        .forEach(car -> {
            winner += car.getName() + ",";
        });

    return winner.substring(0, winner.length() - 1);
}

리팩토링을 진행하면서 기존 소스를 stream API를 이용하여 람다식으로 구현을 해 보았습니다.
매번 예제를 보며 따라치다가 제가 직접 생각하고 작성한 코드라 인상 깊어 선정하게 되었습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

계층형 아키텍쳐는, component들이 각 레이어에 맞게 수평적으로 구조화 되어 있다.
구성되는 계층의 숫자에 따라 N 계층 아키텍처라고 부를 수도 있다.
레이어가 정확히 몇 개로 구성 되어 있다 정할 수 없지만, 크게 3계층과 4계층 구조를 이루고 있다.

  • 3계층

    • Presentation
    • Application
    • Data
  • 4계층

    • Presentation : UI를 뜻하고, 브라우저에서 통신 로직을 담당
    • Business : 요청에 대한 처리 로직을 담당
    • Persistence : DB에 접근하여 데이터 처리 로직을 담당
    • Database : 데이터를 저장하는 곳

또는 정확한 레이어 구성이 정해진게 아니기에 business 와 persistence 사이에 service 계층이 추가 되어 사용 될 수 있다.

장점으로는

  1. 효과적인 개발과 테스트가 가능하고 유지 관리도 할 수 있다.
  2. 계층이 분리되어 있기에 각각 따로 동시에 개발 할 수 있다.
  3. 분리되어 있기에 수정이나 확장에 다른 계층에 영향을 주지 않는다.
  4. 데이터 계층이 분리되어 있어서 보안 강화 가능하다.

[참고]
https://velog.io/@hojin11choi/TIL-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90-Layered-Architecture

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성 주입이란. 외부에서 두 객체간의 관계를 결정해주는 디자인 패턴.
먼저 의존성이란 클래스간에 의존 관계가 있다는 것을 의미한다. 이 의존 관계라는 것은, 한 클래스가 바뀌게 되면 다른 클래스에 영향을 받는 것을 의미한다.

주입이란, 클래스 외부에서 객체를 생성하여 해당 객체를 클래스 내부에 주입하는 것을 의미한다.

그렇기에 의존성 주입을 하게 되면, 클래스간의 결합도가 약해지게 되면서, 한 쪽 클래스가 변경 될 경우 다른 한 쪽의 클래스 변경될 필요성이 적어진다는 것이다.

클래스간의 결합도까 작아져 유연성과 확장성을 향상 시킬 수 있으며, 인터페이스 기반 설계에 테스트 및 코드의 재사용성을 높여줘 리팩토링에 용이하다.

[참고]
https://kotlinworld.com/64

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

public BallStatus play(Ball input) {
    return balls.stream()
        .map(answer -> answer.play(input))
        .filter(BallStatus::isNotNoting)
        .findFirst()
        .orElse(BallStatus.NOTING);
}

자바에서도 8버전부터 람다식이 도입되면서 대표적으로 Stream API을 통해 함수형 프로그램밍이 가능해졌습니다.
Stream의 특징으로는, 원본 값을 유지하되, 데이터를 활용 할 수 있다는 것 입니다.
또, 단점으로는 어디 부분에서 오류가 났는지 디버깅이 어렵다는 것 입니다.

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            try {
                resolve(f());
            }
            catch (error) {
                reject("" + error);
            }
        }, seconds * 1000);
    });
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

console.log("after 2 seconds");

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
after 2 seconds
successfully done
Error: failed

6.강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

아직 함수형 프로그래밍이 낯설어 쓰려고해도 주춤거리고 결국 기존 방법대로 사용하고 있기에, 이번 강의를 통해 자신있게 코드를 작성할 수 있도록 발전하고 싶습니다. 그리고 이런 강의 자체가 처음이라 강의 마지막이 되었을때, 배움에 있어서 내가 성장했구나라는 뿌듯함을 느껴보고 싶습니다 ☺️👍🏻

사전과제 제출

1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
다음은 Google에서 검색된 apple앱의 ID를 받아오는 서비스입니다.
이전 프로젝트에서 구현했던 'Google Search Engine Api 서비스 입니다.' 구글에서 검색어를 입력하면, 검색된 링크에서 앱ID를 파싱했었어야 했습니다. 앱id의 형식은 "id389562983" 형태인데, 숫자는 9자리 또는 10자리가 될 수 있었습니다. 다음 코드는, 숫자만 추출하여 배열에 담아 return하는 함수입니다.

  async findAppId(search: string) {
    let filtered = [];
    function isNum(val) {      // 숫자인지 확인해주는 함수.
      return !isNaN(val);
    }
    try {
      const found = [];
      const result = await this.httpservice.axiosRef.get(
        `https://www.googleapis.com/customsearch/v1/siterestrict?key=${process.env.GOOGLE_API_KEY}&cx=${process.env.GOOGLE_ENGINE_ID}&q=${search}`,
      );
      for (const item of result.data.items) {
        const words = await item.link.split('/id'); // 링크에서 '/id'를 기준으로 문자열을 나눈 후,
        let appId = '';
        for (const word of words) {
          // 앱 id는 10자리, 9자리 두종류가 있음. 10자리일 경우 10자리 반환, 9자리일경우 9자리 반환
          if (isNum(word.substr(0, 10))) {
            appId = word.substr(0, 10);
            break;
          } else if (isNum(word.substr(0, 9))) {
            appId = word.substr(0, 9);
            break;
          } else {
            appId = '';
          }
        }
        if (isNum(appId) && appId.length >= 9) found.push(appId);
      }
      filtered = [...new Set(found)]; // 중복제거
    } catch (e) {
      if (e) throw new NotFoundException();
    }
    return filtered;
  }

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
'계층형 아키텍쳐'는 역할에 따라 계층을 분리해 놓은 구조입니다. Nest.js의 경우 Controller, Module, Service, DTO 등으로 나뉘어 있고, 이렇게 역할에 따라 분리해 놓은 구조는 추후 유지보수에 용이함과 동시에 매우 깔끔하게 정리되었다고 주관적으로 생각합니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
(Nest.js프로젝트에서의 경험을 토대로 답변하겠습니다)
예를 들어, [Auth모듈, User모듈] 두개의 모듈이 있다고 가정하겠습니다. 각각의 모듈은 Controller, Module, Service, DTO를 가지고 있습니다. 하지만, Auth.controller.ts 에서 User.service.ts의 서비스를 끌어다 쓰고 싶으면, Auth.module.ts에 의존성을 주입해주어야 합니다.

쉽게 말해, 각각의 모듈은 각각의 기능을 가지고 있기에 분리되어 있는 구조입니다. 따라서, 다른 모듈의 기능을 가져다 쓰고 싶을 때, 모듈에 다른 모듈의 의존성을 주입해주어야 합니다. 이 의존성 주입은, 재사용성, 가독성을 증진시켜줍니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

const array = [13, 14, 37, 42, 73, 77, 153, 777];
const array2 = array.filter((v) => (v % 7 === 0));
console.log(array2) 
// 결과
// [14, 42, 77]

JS내에서 지원하는 메서드들이 있습니다. map, filter, reduce... 등. 위는 filter를 적용한 예시입니다.

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise<string>((resolve, reject) => {
    setTimeout(() => {    
      try {
        resolve(f())
      } catch(e){
        reject(e);
      }
    } , 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));

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
Nest.js기반 백엔드 프로젝트를 경험하면서, 공식문서를 여러번 읽었습니다. 하지만 다양한 사람들과 함께 얘기 나누고, 배우면서, 더 깊이있는 배움을 가지고 싶습니다.

사전 과제 제출

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

async getDailyChart(dayInfo: DayInfo): Promise<ChartData | null> {
//받은 날짜로 계산
const toDate: Date = new Date(dayInfo.date);
const fromDate: Date = new Date(toDate);
fromDate.setDate(toDate.getDate() - 6);
toDate.setDate(toDate.getDate() + 1);
const from: string = fromDate.toISOString().slice(0, 10);
const to: string = toDate.toISOString().slice(0, 10);

const updatedInfo: FromToInfo = {
user_id: dayInfo.user_id,
from,
to,
};

//전체 데이터 받음
const data = await this.calendarModel.findByDate(updatedInfo);

//인터페이스 초기화
const dailyData: ChartData = {
userId: dayInfo.user_id,
weight: [0, 0, 0, 0, 0, 0, 0],
kcalAvg: [0, 0, 0, 0, 0, 0, 0],
carbAvg: [0, 0, 0, 0, 0, 0, 0],
proteinAvg: [0, 0, 0, 0, 0, 0, 0],
fatAvg: [0, 0, 0, 0, 0, 0, 0],
kcalSum: 0,
carbSum: 0,
proteinSum: 0,
fatSum: 0,
sugarsSum: 0,
natriumSum: 0,
cholesterolSum: 0,
saturatedfattySum: 0,
transfatSum: 0,
};

if (!data || data.length === 0) {
return dailyData;
}

const chartSlotList: string[] = new Array(7);
for (let i = 0; i < 7; i++) {
chartSlotList[i] = String(
dayjs(fromDate).add(i, 'day').format('YYYY-MM-DD'),
);
}

let count = 0;
for (let day = 0; day < 7; day++) {
if (chartSlotList[day] === data[count].date.toISOString().slice(0, 10)) {
dailyData.weight[day] = data[count].todayWeight;
dailyData.kcalAvg[day] = data[count].currentKcal;
dailyData.carbAvg[day] = data[count].carbSum;
dailyData.proteinAvg[day] = data[count].proteinSum;
dailyData.fatAvg[day] = data[count].fatSum;
dailyData.kcalSum = data[count].currentKcal + dailyData.kcalSum;
dailyData.carbSum = data[count].carbSum + dailyData.carbSum;
dailyData.proteinSum = data[count].proteinSum + dailyData.proteinSum;
dailyData.fatSum = data[count].fatSum + dailyData.fatSum;
dailyData.sugarsSum = data[count].sugarsSum + dailyData.sugarsSum;
dailyData.natriumSum = data[count].natriumSum + dailyData.natriumSum;
dailyData.cholesterolSum =
data[count].cholesterolSum + dailyData.cholesterolSum;
dailyData.saturatedfattySum =
data[count].saturatedfattySum + dailyData.saturatedfattySum;
dailyData.transfatSum = data[count].transfatSum + dailyData.transfatSum;
count++;
}
if (count >= data.length) break;
}

return dailyData;
}

식단 관리 웹 어플리케이션을 제작할 때 차트 API를 위해 작성했던 서비스 함수입니다.
서비스의 기능은 아래와 같습니다.

  • 7일간의 기간 동안 하루 섭취한 영양소의 평균을 보여준다
    당시에는 기간이 촉박해 하드 코딩에 가깝게 처리했으나 더 좋은 로직을 생각해내고 싶어 공유합니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

Layered Architecture

계층 아키텍쳐는 자바 EE 어플리케이션의 사실상의 표준이 되는 등 널리 알려져있다.
계층화된 아키텍쳐 패턴 안의 구성 요소는 수평적으로 구성되며, 각각의 레이어는 어플리케이션 안에서 특별한 역할을 수행한다. 대부분 계층 아키텍쳐는 Presentation, Business, Persistence, Database, 네 개의 표준 계층으로 구성된다. 각 계층은 특정한 비즈니스 요구를 만족시키기 위한 작업을 추상화한다. 각 계층은 서로가 무슨 일을 하는지 알 필요가 없다.

계층은 표현 계층, 비즈니스 계층, 지속 계층, 데이터베이스 계층으로 나누어져 있다.

이처럼, 계층 아키텍처의 가장 강력한 기능 중 하나는 구성 요소간의 관심사 분리이다. 특정 계층 내에 있는 구성 요소들은 그 계층에 관련된 로직만을 다룬다.
또한 아키텍쳐 내의 계층은 전부 닫혀 있다. 이 뜻은 리퀘스트가 계층 간에서 이동할 때 바로 아래 계층을 통과해야 그 다음 계층 또한 통과할 수 있다는 것이다. 물론 바로 직접 리퀘스트를 보내는 것이 매우 빠를 테지만 격리 계층을 위해서 이와 같은 규칙을 지킨다. 예로, 만약 표현 계층에서 바로 비즈니스 지속성 계층으로 리퀘스트를 보낸다면 지속성 계층에서 행한 작업을 각각의 비즈니스 계층과 데이터베이스 계층에게도 반영을 해야 한다. 이렇게 된다면 아키텍처 계층간 상호 종속성이 높아지고 매우 밀접하게 결합된 어플리케이션이 되어 변경하기가 어려워진다.

리퀘스트 흐름은 보통 다음과 같다.

  1. 화면을 보고 있는 사용자가 정보를 요청한다.
  2. 요청은 delegated 모듈로 전달되어 해당 요청을 처리하기 위해 비즈니스 계층의 Object로 다시 전달된다.
  3. Object는 요청을 받고 로직을 수행하기 위해 Data Access Object를 부른다.
  4. Object가 데이터베이스 계층으로부터 데이터를 받으면 지속성 계층, 비즈니스 계층, 표현 계층으로 전달되고 화면을 보고 있는 사용자에게 최종 전달된다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency Injection 의존성 주입

의존성 : 의존대상이 변하면 의존하는 대상에게도 영향을 미치는 것

의존성이 높으면 변경을 자주 해야 하며 어려울지도 모른다. 하지만 의존 관계를 추상화하거나 하면 더 다양한 의존 관계를 맺을 수 있다.
이러한 의존 관계를 외부에서 결정하고 주입하는 것이 의존성 주입이다. 즉, 객체가 의존하는 다른 객체를 외부에서 선언한 뒤에 이를 주입 받아 사용하는 것이다.

장점

  1. 의존성이 줄어든다
  2. 재사용성이 높다
  3. 테스트성이 좋다
  4. 가독성이 높다

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Scala를 공부 중입니다. 아직 공부 중이라 마땅한 예제가 없습니다.

스칼라는 객체 지향 언어의 특징과 함수형 언어의 특징을 함께 가지는 다중 패러다임 프로그래밍 언어이다. 스칼라는 모든 함수를 값으로 생각한다. 고차 함수를 지원하고 함수의 중첩을 허용하며 커링 또한 지원한다. 스칼라는 함수형 언어의 특징을 가지기 때문에 자바에 비해 코드 길이가 짧으며 바이트 코드를 최적화하여 자바보다 속도가 20% 정도 빠르다.

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

type SomeFunctionReturnString = () => string

    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
        // 해당 함수 내부를 구현해 주세요
        return new Promise<string>((success, fails)=> {

            setTimeout(() => {
                try{
                    success(f());
                }catch(e){
                    fails(e);
                }
            }, seconds * 1000);
        });
    };

    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed

Screen Shot 2023-01-05 at 5 24 44 PM

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

다른 분들과 꾸준히 챌린지를 도전하며 함수형 프로그래밍을 실무에 꼭 적용하고 싶습니다. 또한 트렌드 또한 익히고 싶습니다.

사전과제 제출

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

  • 언어 상관없음
  • 어떤 로직이든 상관없음
  • 단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요
    @PostMapping(value = "/members/new")
    public String create(MemberForm form) {
        Member member = new Member();
        member.setName(form.getName());
        memberService.join(member);
        return "redirect:/";
    }
spring 을 공부하면서 PostMapping, GetMapping 을 사용하였던 코드의 일부 입니다. 
 이번 기회에 nest.js typescript를 이용하여 프로젝트를 만들고 싶습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

프로그래밍 개발에서 많이 채택 되는 아키텍처. 
다른 계층에서 발생하는 문제나 알고리즘들은 굳이 신경 쓸 필요 X . 
 그러다 보니 유지보수와 테스팅이 쉬운게 장점. 
총 4개의 계층으로 나누어서 진행 

- Presentation Layer 
- Business Layer
- Persistence Layer
- Database Layer

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성 주입 개념
- 외부에서 두 객체 간 관계 결정해주는 디자인 패턴이다.
- 직접적으로 작성하는게 아닌 외부 의존관계에서 런타임 시 관계를 동적으로 주입해 주는걸 뜻한다.

의존성 왜 필요한가?
- 각 코드들이 강하게 결합되어 있을 경우 제약이 많아지고 확장성이 떨어진다.
- 의존성 주입을 하여 결합도를 낮추고 객체의 유연성을 높일 수 있기 때문

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

함수형 프로그래밍 정의
- 대입문을 사용하지 않는 프로그래밍, 문제 해결을 위한 작은 함수를 작성하는 뜻
let grade = [80,70,90,85,100]

grade.filter((value) => value>=90);
grade.sort(fun(a,b) {
    return a-b;
});
grade.map((value) => value *2);

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

type SomeFunctionReturnString = () => string
function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  // 해당 함수 내부를 구현해 주세요
  return new Promise<string>((sucess, fails) => {
    
    setTimeout(() => {    
      try {
        sucess(f())
    } catch(e){
      fails(e);
    }
  } , seconds * 1000);
});

};
const success = () => {
  return "successfully done";
};
const fail = () => {
  throw new Error("failed");
};
delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));
delay(fail, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

이번 프리온 보딩 백엔드를 하면서 제가 가지고 있던 프론트 지식에 더불어 백으로 데이터 베이스를 연동하는 프로젝트를 진행하고 있습니다. 또한 그동안 기능성만 중시하였다면 가독성과 유지보수를 쉽게 하기 위한 노력의 발판으로 삼아 앞으로 나아가고 싶습니다.

사전과제 제출

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

공공 api를 활용하여 필요한 정보를 가져온 후 가공하는 코드입니다.
출근시간대 특정 버스 이용객 수를 가져오는데, 출근시간대에 맞춰 정보를 가공했습니다.
공유라기보다는 많이 부족해서 리마인드할 겸, 혹시 피드백을 받을 수 있을까 해서 올려봅니다.

const getPassengersByLine = async(busNum) => {
  const today = new Date();
  const thisYear = today.getFullYear();
  const thisMonth = '0' + (today.getMonth() - 1);
  const yyyymm = String(thisYear) + String(thisMonth);
  
  let howManyPassenger = await fetch(
    `http://openapi.seoul.go.kr:8088/${process.env.SEOUL_KEY}/json/CardBusTimeNew/1/5/${yyyymm}/${busNum}`,
    {
      method : "get"
    }
  );

  const response = await howManyPassenger.json();

  if (!response.CardBusTimeNew) {
    const err = new Error("유효하지 않은 정보입니다.");
    err.statusCode = 400;
    throw err;
  } else {
    const coreInfo = response["CardBusTimeNew"]["row"]
    let result = [];

    for(let i = 0; i < coreInfo.length; i++) {
      result[i] = {
      ["버스정류장명"] : coreInfo[i]["BUS_STA_NM"],
      ["6시 하차 승객 수"] : coreInfo[i]["SIX_ALIGHT_NUM"],
      ["6시 승차 승객 수"] : coreInfo[i]["SIX_RIDE_NUM"],
      ["7시 승차 승객 수"] : coreInfo[i]["SEVEN_RIDE_NUM"],
      ["7시 하차 승객 수"] : coreInfo[i]["SEVEN_ALIGHT_NUM"],
      ["8시 승차 승객 수"] : coreInfo[i]["EIGHT_RIDE_NUM"],
      ["8시 하차 승객 수"] : coreInfo[i]["EIGHT_ALIGHT_NUM"],
      ["9시 승차 승객 수"] : coreInfo[i]["NINE_RIDE_NUM"],
      ["9시 하차 승객 수"] : coreInfo[i]["NINE_ALIGHT_NUM"]
      };
  };
  return result;
  };
};

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

코드를 한 파일에 몰아 넣으면 가독성이 떨어질 뿐 아니라 프로젝트가 커질 수록 파일이 계속해서 무거워지기 때문에 유지보수와 확장성에도 좋지 않습니다. 이에 따라 코드를 모듈화 하여 계층(레이어)에 맞는 코드를 나눠 작성하는 구조입니다.
보통 클라이언트에서 요청을 하면 요청에 맞는 router로 전송이 된 후,
controller단에서 router를 거쳐 들어온 코드를 받아 키 에러 등 누락된 것이 없는지 확인한 후에
service단에서 비즈니스 로직을 통과합니다.(아이디/비밀번호 검증, 기타 서비스 관련 코드)
그 후 데이터가 필요하면 dao단에서 db에 데이터를 받아온 후 다시 클라이언트 쪽으로 단계별로 전송하는 구조입니다.

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

의존성은 하나의 코드가 다른 코드에 의존하는 상태를 말하는데,
만약 a코드가 b코드를 사용한다면 'a코드는 b코드에 의존하고 있다'고 할 수 있습니다.
a코드는 b코드를 사용하기 위해 a코드 내부에서 직접 만들 수 있는데 이 경우 b코드와의 결합은 강해집니다.
반면에 외부에서 b코드를 만들고, a코드는 이를 주입받아 사용할 수 있는데 이 경우를 의존성 주입이라고 할 수 있습니다.

전자는 개발자가 모든 코드를 직접 제어하는 반면에,
IoC(제어역전)가 발생하면 제어하는 주체가 바뀝니다.
즉, a가 b를 직접 참조했다면 IoC가 발생하면 매개체가 제어 주체가 되어 a, b코드를 제어하게 됩니다.
매개체는 IoC 컨테이너라고 하며 보통 프레임워크가 그 역할을 합니다.(nest.js, 스프링 등)
IoC 컨테이너는 제어권을 사용하여 의존성 관리, 인스턴스 생성 및 주입, 메모리 해제의 역할을 합니다.

의존성 주입이 일어나면 외부 코드를 사용하기 때문에 코드의 유지보수와 재사용성이 용이해지며, 코드의 양 또한 감소합니다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

javascript를 사용 중입니다.
함수형 프로그래밍에서는 순수함수를 사용하는 것으로 알고 있습니다.
map, filter, reduce 메소드를 예로 들 수 있습니다.

//map 메소드 사용
const arr = [1, 2, 3, 4, 5];
const result = arr.map(x => x * 10);
// [10, 20, 30, 40, 50]

map 메소드를 사용하면 원본 배열에 변화가 없고, map의 대상 배열 외의 사용 변수가 없습니다.
함수형 프로그래밍 경험이 없어서 이번에 배워서 학습할 계획입니다.

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

    type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try{
        resolve(f());
      } catch(err) {
        reject(err);
      }
    }, seconds * 1000)
  }
)}
    const success = () => {
      return "successfully done";
    };

    const fail = () => {
      throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
      .then((res) => console.log(res))
      .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

취준생으로서 여러 채용공고를 보면 typescript와 nest.js가 정말 많이 사용된다는 것을 느꼈습니다.
부트캠프에서 javascript, node.js 기반의 백엔드 기술을 학습했는데 취업 문이 좁게 느껴져서 답답한 면이 있었는데, 이번 기회에 새로운 기술들을 배워 역량을 키우고 싶습니다.
또한 함수형 프로그래밍이나 의존성 주입 등 생소한 내용이 많아서 공부에 대한 부담이 많은게 사실이지만 즐거운 마음으로 새로운 공부를 시작해볼까 합니다.
신입 개발자가 알아야 하는 실무에서 많이 쓰는 기술이 있다면 알고 싶습니다!

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    언어 상관없음
    어떤 로직이든 상관없음
    단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요
export class BaseService<T> {
  constructor() {}
  resObj(data: T): IResObj<T> {
    return new IResObj(200, false, 'success', data);
  }

  resBoolean(data: boolean): IResObj<boolean> {
    return new IResObj(200, false, 'success', data);
  }

  resNumber(data: number): IResObj<number> {
    return new IResObj(200, false, 'success', data);
  }

  resList(data: any): IResObjList<T> {
    return new IResObjList(200, false, 'success', data);
  }

  resError(message: string): IError {
    return new IError(HttpStatus.BAD_REQUEST, message);
  }

  objValidate(obj: T): void {
    if (!obj) throw new Error('findedObj not found');
  }

}

-> 모든 서비스 레이어에서 사용될 수 있는 기본적인 응답 형태의 함수들을 모아놓은 클래스입니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

->
리퀘스트에 대한 역할을 분리하여 각각의 레이어는 맡은 바 일에 대한 책임을 다 하는 것입니다.
일반적으로 presentation, business, persistence, data 레이어로 구성되어 있습니다.
presentation: http 통신에 관한 요청에 대한 응답을 담당합니다.
business: 비즈니스 로직이 주로 위치합니다.
persistence: 데이터베이스 접근을 담당합니다.
data: 데이터베이스

  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

->

개념: 추상화된 객체를 외부에서 주입합니다.
필요한 이유 : 여러 클래스에 의존하는 A클래스에서 의존하는 클래스를 생성한 후 문제를 해결하는 경우 비슷한 코드의 중복과 코드가 길어지는 경우가 많아 불핋요한 비용이 발생합니다.
A클래스에서 필요한 객체를 외부에서 주입하도록하여 A클래스의 코드에서 발생하는 비용을 줄일 수 있습니다.

  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

-> 이번 강의를 통해서 배워보겠습니다.

  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
    type SomeFunctionReturnString = () => string
type SomeFunctionReturnString = () => string;
  function delay(
    f: SomeFunctionReturnString,
    seconds: number,
  ): Promise<string> {
    return new Promise((res, rej) => {
      setTimeout(() => {
        try {
          res(f());
        } catch (err) {
          rej(err);
        }
      }, seconds * 1000);
    });
    // 해당 함수 내부를 구현해 주세요
  }

  const success = () => {
    return 'successfully done';
  };

  const fail = () => {
    throw new Error('failed');
  };

  delay(success, 2) // 2초 뒤에 successfully done 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));

  delay(fail, 2) // 2초 뒤에 failed 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));
결과값

    $ ts-node delay.ts
    successfully done
    Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
  • “과락하지 않는 코드를 작성하고 싶어요”
  • “주니어 수준의 최소한의 기본기는 갖추고 싶어요”
  • “좋은 코드와 나쁜 코드의 기준을 알고 싶어요”
  • “기술 과제 면접 질문은 어떻게 대비해야 할까요?”

사전 과제 제출

사전과제

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요
    • 언어 상관없음
    • 어떤 로직이든 상관없음
    • 단, 길이가 길지 않은 함수 단위가 좋습니다
const TodoAddPage = () => {
  const [todoInfo, setTodoInfo] = useState({ title: '', content: '' });
  const navigate = useNavigate();

  const onChange = (e: ChangeEvent<HTMLInputElement>): void => {
    setTodoInfo({ ...todoInfo, [e.target.name]: e.target.value });
  };

  const addTodo = (e: MouseEvent<HTMLElement>) => {
    e.preventDefault();
    console.log(todoInfo);
    createTodo(todoInfo).then(() => {
      console.log('add todo successed!');
      navigate(`/todo`);
    });
  };
};

typeScript로 구현한 todo-list의 일부분
처음으로 jsx를 모두 tsx로 변환하여 리팩토링한 프로젝트라서 의미가 있습니다
처음에는 조금 번거롭지만 숨겨진 error를 더 빨리 찾을 수 있다는 장점이 있다고 생각합니다

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

image

소프트웨어 개발에서 일반적으로 사용되는 아키텍처 중 하나
각 계층은 어플리케이션 내에서 특정 역할과 관심사(화면 표시, 비즈니스 로직 수행, DB작업 등)별로 구분

사용자가 특정 고객 정보를 요청한 상황을 가정하여, Layered Architecture 가 이 요청을 수행하는 시나리오

  사용자가 보고있는 화면(Customer Screen, 흔히 말하는 View 라고 할 수 있을 것 같다)에서 사용자는 고객 정보를 요청한다.

  1) 이 요청은 그 요청을 처리할 수 있는 모듈이 무엇인지 알고있는 Customer Delegate (흔히 말하는 Controller 라고 할 수 있을 것 같다) 로 전달된다. 

  2) Customer Delegate 는 해당 요청을 처리하기 위해 Business Layer 의 Customer Object 로 요청을 다시 전달한다.

  3) Customer Object는 요청을 받고 비즈니스 로직을 수행하기 위한 데이터를 얻기 위해, Persistence Layer의 Customer dao 와 Order dao 에 요청을 보낸다.

  4) Persistence Layer 의 DAO들은 요청을 수행하기 위해 Database Layer 에 접근하여 데이터를 가져온다.

  5) 이 요청은 다시 반대로 Persistence Layer → Business Layer → Presentation Layer 로 전달되고 최종적으로 사용자에게 전달된다.
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    의존성 주입은 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것
  의존성 주입을 사용하는 이유?
  
  1. 의존성이 줄어든다.
    의존한다는 것은 그 의존 대상의 변화에 취약하다는 것이다. (대상이 변화했을 때, 이에 맞게 수정해야함)
    의존성 주입으로 구현했을 때, 주입 받는 대상이 변하더라도 그 구현 자체를 수정할 일이 없거나 줄어듬
  
  2. 재사용성이 높은 코드가 된다.
    하나의 클래스 내에서 사용하던 클래스를 별도로 구분하여 구현하면 다른 클래스에서 재사용이 가능
  
  3. 테스트하기 좋은 코드가 된다.
    두 클래스의 테스트를 분리하여 진행할 수 있음

  4. 가독성이 높아진다.
    기능들을 별도로 분리하게 되어 자연스럽게 가독성이 높아진다.

  https://jenkov.com/tutorials/dependency-injection/dependency-injection-benefits.html
  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    저는 주로 js로 개발을 하고 있습니다
    ES6에 내장되어 있는 map, filter, reduce, find등의 함수를 자주 사용하고 있습니다
    react로 개발하는 프로그램의 경우 Lodash/Underscore.js를 자주 사용했었는데 요새는 순수 함수로 더 자주 함수형 프로그래밍을 구현하고 있습니다
  const users = [
    { user: 'joey', age: 32 },
    { user: 'ross', age: 41 },
    { user: 'chandler', age: 39 },
  ];

// Native - 더 빠름
users.find(function (o) {
  return o.age < 40;
});

  // lodash
  _.find(users, function (o) {
    return o.age < 40;
  });

  const numbers = [10, 40, 230, 15, 18, 51, 1221];

  // lodash - 더 빠름
  _.filter(numbers, (num) => num % 3 === 0);

  // Native
  numbers.filter((num) => num % 3 === 0);
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
   type SomeFunctionReturnString = () => string;

   function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
     // 해당 함수 내부를 구현해 주세요
   }

   // 코드
   function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
     let timeoutId: NodeJS.Timeout;
     timeoutId = setTimeout(() => {}, 1000 * seconds);
     global.clearTimeout(timeoutId);

     return new Promise((resolve, rejects) => {
       f();
       console.log(`after ${seconds} seconds`);
       resolve('successfully done');
       rejects('Error: failed');
     });
   }

   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
after 2 seconds
successfully done
Error: failed
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
기능뿐만 아니라 가독성 좋은 코드를 디자인하고 작성하는 방법을 학습하고 싶습니다
집단 지성의 힘을 얻어 다양한 관점을 배우고 싶습니다
멘토님의 실무 경험에서 나오는 노하우를 전수받고 싶습니다
해당 강의 주제 뿐만 아니라 백엔드 개발의 트렌드를 배우고 따라가고 싶습니다

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 code block 을 사용해 올려주세요
    언어 상관없음
    어떤 로직이든 상관없음
    단, 길이가 길지 않은 함수 단위가 좋습니다
    해당 code block 에 올려주세요

  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    뷰 / 비즈니스 / 데이터 등 각자의 역할에 맞게 층을 나누고 해당 계층에서는 해당 로직만 수행

  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • 사용할 모듈을 외부 레퍼런스로 가져다 사용하는 것이 아닌, 인자로 받아서 사용하는 개념
  • 사용하는 모듈과 사용될 모듈의 의존성 제거, 같은 인터페이스라면 어떤 구현체라도 사용가능
  1. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

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

    function delay(f: SomeFunctionReturnString, seconds: number): Promise {
    // 해당 함수 내부를 구현해 주세요
    return new Promise((resolve) => {
    setTimeout(() => {
    resolve(f())
    }, seconds * 1000)
    })
    };

    const success = () => {
    return "successfully done";
    };

    const fail = () => {
    throw new Error("failed");
    };

    delay(success, 2) // 2초 뒤에 successfully done 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));

    delay(fail, 2) // 2초 뒤에 failed 로그
    .then((res) => console.log(res))
    .catch((e) => console.log(e));

사전과제 제출

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

const raiseCustomError = (message, statusCode) => {
  const err = new Error(message);
  err.statusCode = statusCode;
  throw err;
};

// 사용 예시 
if (!total_price || orderInfo.length === 0) {
    raiseCustomError("BAD_REQUEST", 400);
  }

customError가 발생했을 때, 에러 메세지를 반환해 주는 함수 입니다. 다양한 경우의 수를 고려해서 에러 핸들링을 해야하는데, 이 때 이를 모듈화해 사용하면 간결한 코드를 완성할 수 있어서 좋았습니다.

2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

구성 요소들이 수평적인 레이어로 조직화되어 있는 다층 구조 입니다. 모든 구성요소가 연결되어 있지만 분리되어있고 총 4개의 계층이 있습니다. 각각의 계층(레이어)는 하위에 있는 레이어에만 의존하는 단방향 의존성 특징을띄고 있습니다.

  • Presentation Layer : 클라이언트 시스템과 직접적으로 연결되는 부분으로, API의 엔드포인트를 정의하고 전송된 HTTP요청(req)를 읽어오는 로직
  • Business Layer : 실제 시스템이 구현해야하는 로직
  • Persistence Layer : 데이터베이스에서 데이터를 저장, 수정, 읽기등을 하는 로직 (DAO(Data Access Object) presentation, ORM(Object Relational Mappings) 등을 포함)
  • Database Layer : 모든 데이터베이스가 저장되는 레이어

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

클래스간 의존성을 클래스 외부에서 주입하는 것을 의미하며 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것입니다. 이를 사용하는 이유는,

  1. 의존성이 줄어든다 : 서로 의존성이 강한 객체 중 하나가 변화하게 되면 그 의존대상의 변화에 취약하다. DI를 통한 코드 구현은 이 부분을 보완해준다.
  2. 재사용성이 높은 코드 : 각각의 요소를 분리해서 재사용 할 수 있다.
  3. 테스트 하기 좋은 코드 : 각각의 객체를 분리해서 테스트할 수 있다.
  4. 가독성이 높아진다 : 기능들을 별도로 분리하게 되어 가독성이 높아진다.

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

이번 기간을 통해 함수형 프로그래밍을 더욱 잘 활용할 수 있길 기대해 봅니다 : )

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try{
        resolve(f());
      } catch(err) {
        reject(err);
      }
    }, seconds * 1000)
  }
)}

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

    $ ts-node delay.ts
    successfully done
    Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

과제를 수행하면서 아직 배워가야하는 것들이 많다는 생각이 들었습니다. 해당 기간을 통해 함수형 프로그래밍 과 더 좋은 코드가 무엇인지 고민하며 성장해가고 싶습니다.

사전 과제 제출

사전과제

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요
    • 언어 상관없음
    • 어떤 로직이든 상관없음
    • 단, 길이가 길지 않은 함수 단위가 좋습니다
const zipUtil = (file_name: string, data: string, password: string) => {
  file_name = `zip_files/${file_name}`;
  fs.writeFile(`${file_name}.csv`, "\uFEFF" + data, function (error) {});
  exec(
    `zip -rm -junk-paths --password ${password} ${file_name}.zip ${file_name}.csv`,
    function (error, stdout, stderr) {
      if (error) {
        throw error;
      }
    }
  );
};

서버상에서 엑셀 문서를 암호화된 압축파일로 생성할 필요한 적이 있어서 생성하여 사용하였습니다.

  1. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    소프트웨어 개발에서 가장 일반적으로 널리 사용되는 아키텍처로, 각 계층은 어플리케이션 내에서의 특정 역할과 관심사(화면 표시, 비즈니스 로직 수행, DB 작업 등)별로 구분된다.
    이는 Layered Architecture 의 강력한 기능인 '관심사의 분리 (Separation of Concern)' 를 의미한다.
    관심사의 분리가 충족되면 각 계층의 역할을 수행할 수 있는데 집중하여 도메인 로직을 개발할 수 있고 테스트 로직을 작성할 수 있기 떄문에 유지보수에도 용이하다.
  • 3-Tier Layer : Presentation Layer(프리젠테이션 레이어), Application Layer(애플리케이션 레이어), Data Layer(데이터 레이어)
  • 4-Tier Layer : Presentation Layer(프리젠테이션 레이어), Business Layer(비즈니스 레이어), Persistence Layer(퍼시스턴스 레이어), Database Layer(데이터베이스 레이어)
  1. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요
    Dependency Injection(의존성 주입) 이란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 별도의 객체를 사이에 둬서 객체간에 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

  2. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

const arr = [1, 2, 3, 4, 5];
arr.reduce((pre, value) => {
	return pre + value;
}, 0);
  1. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)

    type SomeFunctionReturnString = () => string
    
    function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          try {
            resolve(f());
          } catch (error) {
            reject(error);
          }
        }, 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
    after 2 seconds
    successfully done
    Error: failed
    
  2. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    함수형 프로그래밍에 대한 이해와 nestjs를 사용하면서 의존성 주입에 대한 구분과 이해를 높이고 싶습니다.

[사전 과제 제출]

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

private matchOption(datas: Data[], options: Option[]){
    return datas.filter(({option})=> {
        //filtering : 해당 조건 이외는 반영 X
        return option.filter(to => [3,4,5,6].includes(to.OptionTypeId) ).every(({optionType, value}) => {
            //옵션 값들 중 매칭되는 조건이 2가지
            //1. 범위안, 2. 이하 
            if([4,5,6].includes(optionType.id))
                return targetOptions.find( e => e.optionTypeId == optionType.id)?.value <= value;
            else if([3].includes(optionType.id))
                return Math.abs(targetOptions.find( e => e.optionTypeId == optionType.id)?.value - value) <= 1; 
        })
    })
}

옵션이 존재하는 데이터들이 존재하고
해당 옵션들을 입력받았을 경우 데이터의 옵션과 비교하여 매칭된 데이터를 조회함
옵션의 조건은 총 2가지 +-1 의 범위, 이하

위와 같은 요구사항을 코드로 구현했는데 스스로 코드에 냄새가 난다고 판단했고
같이 챌린지 하시는 분들과 좋은 피드백 나누고 싶어서 공유하게 되었습니다


2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

Layered Architecture의 목적은 확실한 관심사의 분리입니다

제가 최근에 DDD로 구현하려고자 하는 프로젝트에는 아래와 같이 layer를 형성해보았습니다

인터페이스 (Interface) : 서비스 외부로부터 입/출력 처리
애플리케이션 (Application) : 사용자 시나리오
도메인 (Domain) : 비즈니스 규칙
인프라스트럭처 (Infrastructure) : 기술적 세부 구현

기존의 Layered Architecture와의 차이점

기존의 Database Layer가 최하위 Layer이었고 그로 인해 데이터 베이스 중심 설계가 이루어 졌다면
비지니스 로직에 집중할 수 있도록 Domain Layer을 최하위 계층으로 도메인 주도 설계를 진행하였고
의존성 역전을 통해 Database Layer은 infrastructure계층에 구현하였습니다

3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

Dependency Injection는 의존성을 클래스의 내부가 아닌 외부에서 의존관계를 결정하고 주입하는 것을 의미합니다.
의존성을 내부에서 다 구현하여 모든 서비스가 단단히 구현되어 있고 A가 B에 의존적인 경우
B 대신 C를 A에 의존시키고 싶다면 A 코드를 수정해야 하는데 그러지말고 A가 의존하는 클래스를 외부에서
의존관계를 설정할 수 있도록 하게 코드를 구현한다면 굳이 A코드를 수정할 필요 없으니
훨씬 의존성도 줄고 재사용성도 높은 코드를 구현 할 수 있습니다

4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

Typescript를 사용하고 있으나 정확한 스펙을 알지 못하여 조사 후 정리하여 수정하도록 하겠습니다

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    return new Promise<string>((resolve,reject) => setTimeout(() => {
        try{
            resolve(f())
        }
        catch(e){
            reject(e)
        }
    }, seconds * 1000 ));
};

const success = () => {
  return "successfully done";
};

const fail = () => {
  throw new Error("failed");
};

delay(success, 2) // 2초 뒤에 successfully done 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

delay(fail, 2) // 2초 뒤에 failed 로그
  .then((res) => console.log(res))
  .catch((e) => console.log(e));

결과값

$ ts-node delay.ts
successfully done
Error: failed

6. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

nestjs 실무 사용 방법 팁과 함수형 프로그램에 대한 숙련도를 기대하고 있고
이후 연계된 취업 관련 팁도 궁금합니다

사전 과제 제출

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

언어 상관없음
어떤 로직이든 상관없음
단, 길이가 길지 않은 함수 단위가 좋습니다

def name_to_json(cursor):
    row = [dict((cursor.description[i][0], value) for i, value in enumerate(row)) for row in cursor.fetchall()]
    return row

위 코드는 DataBase에 연결하여 cursor.fetchall() 함수로 받아온 쿼리 결과를 json 형식으로 만들어 반환해주는 함수입니다.

Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요

레이어드 아키텍쳐 패턴에서의 구성 요소(component)들은 각 레이어에 수평적으로 구조화되어있다. 레이어드 아키텍처 패턴은 정확히 한 패턴에 몇개의 어떤 레이어가 있어야 하는지를 명시하지 않지만, 가장 보편적인 레이어드 아키텍처 패턴은 4개의 레이어로 구성되어있다; presentation, business, persistence, database이다.

Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요

  • Dependency Injection(의존성 주입)의 개념
    • 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
  • Dependency Injection(의존성 주입)이 필요한 이유
    • 복잡한 프로젝트일 경우 지속적이고 효율적인 유지보수를 위해서 의존성 주입이 필요하다고 생각이듭니다.

본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요

순수 함수들을 조합하여 전체 프로그램을 구현하는 방식으로 말 그대로 프로그램 내에서 데이터 연산 및 처리를 수학적인 개념에서 이해하여 다루려는 개념

  • side effect 차단
  • 모든 것을 객체로 취급
  • 보다 쉽고 안전한 동시성 작업
  1. 일급 함수

일급 함수는 아래와 같은 조건을 만족하는 함수로 대표적으로 kotlin, java script 함수들이 일급 함수에 속합니다. 파이썬 역시 모두 객체로 이루어져 있기 때문에 함수 역시 객체이고 따라서 파이썬의 함수 또한 일급 함수입니다.

  • 변수나 데이터 구조 내부에 할당 가능
  • 파라미터로 전달 가능
  • 반환 값(return value)으로 사용 가능
  • 할당에 사용된 이름과 무관히 고유하여 구별이 가능하고 동적 프로퍼티 할당이 가능
def factorial(n):
    '''factorial func -> n : int'''
    if n == 1 :
        return 1

    # 반환값으로 사용
    return n * factorial(n-1)

# 변수로 할당
fac = factorial
>>> <function factorial at 0x10d30eb00>

# 인수로 전달
[fac(i) for i in range(1,6) if i %2 ]
>>> [1, 6, 120]
  1. 고차 함수

람다 계산법에서 만들어진 개념으로 일급 함수의 부분집합으로 볼 수 있습니다.

  • 함수에 함수를 인수로 전달 가능
  • 함수의 반환 값으로 함수를 사용 가능
  1. 순수 함수

함수형 프로그래밍에 꼭 필요한 개념입니다.

  • 동일한 입력에는 항상 동일한 결과를 반환
  • 함수의 실행이 프로그램 전체 실행과는 무관하다.(즉 side effect가 없다)
a = 10
def test(b):
    a = 20
    print(a)
    print(b)

test(10)
>> 20
>> 10

print(a)
>> 10

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

type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    // 해당 함수 내부를 구현해 주세요
};

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
after 2 seconds
successfully done
Error: failed

강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요

아예 모르는 내용에 대해서 새롭게 배워보고자 강의를 신청하였습니다. 해당 강의를 듣고 역량을 넓히고 싶습니다 화이팅!

사전과제 제출

  1. 본인이 작성했던 코드 중 공유하고 싶은 코드를 이유와 함께 마크다운 코드블락을 사용해 올려주세요
    최근 개인코드 중에는 생각나는게 없네요 ㅠ
  2. Layered Architecture(계층 아키텍처)에 대해서 설명해 주세요
    목적이나 관심사에 따라 함수나 로직의 정의를 계층( Layered ) 하게 나누는 아키텍처를 말합니다.
    저는 이 계층을 나눌때 가장 중요한 것은 같은 레이어에서는 로직이 서로를 간섭,의존이 생기는 것을 피하고 해당 레이어의 컨셉을 벗어나지 않는 것이 중요하다고 생각합니다. 아주 단편적으로 예를 들면, 여러 로직이나 함수가 있는데, 그것이 하나의 폴더에 다 들어가 있다고 하면, 유지보수하기 힘들 것 같네요. ( 적절한지 모르겠네요 ㅎㅎ )
  3. Dependency Injection(의존성 주입)의 개념과 함께, 왜 필요한지 작성해 주세요.
    의존성 주입이란 쉽게 말해 파라매터 전달을 통한 독립된 객체의 행위를 넘겨주어 사용하는 것을 말합니다.
    저는 이 의존성 주입이 필요한 이유는 목적에 따라 모듈을 분리함으로써, 결합도를 낮추고 응집도를 올리는데 필요한 부분이라고 생각합니다. 실생활에서 지켜지지 않았을 때 문제가 되는 것을 예를 들어, 하나의 함수를 고치는데 그 함수가 너무 여러기능을 하기 때문에 다른 기능들에게도 영향이 가는것을 줄일 수 있습니다.
  4. 본인이 사용하는 언어의 Functional Programming(함수형 프로그래밍) 스펙을 예제와 함께 소개해 주세요
    저는 JavaScript를 많이 사용하는데, 이쪽에서 사용하는 map, filter, reduce 등이 있습니다.
  5. (코드 작성) 다음 스펙을 만족하는 delay 함수를 작성해 주세요 (hint: Promise 사용)
type SomeFunctionReturnString = () => string

function delay(f: SomeFunctionReturnString, seconds: number): Promise<string> {
    return new Promise((resolve,reject) => {
        setTimeout(()=> {
            try{
                resolve(f());
            }catch(error){
                let message = 'unknown error';
                if (error instanceof Error) message = `${error.name}: ${error.message}`;
                if (error instanceof Object) message = error.toString();
                reject(message);
            }
        }, 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));
  1. 강의를 통해서 기대하는 바, 또는 얻고 싶은 팁을 적어주세요
    Nest를 좀 잘하고 싶고요. 백엔드 아키텍쳐 라는 개념을 좀 더 잘 배우고 싶습니다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.