4 분 소요

미션2 LMS 강의 자료1

📖TDD와 리팩터링

Test Driven Development(테스트 주도 개발, TDD)

  • 테스트를 먼저 작성하고 그 후 실제 코드를 작성하는 방법
  • 개발 전에 테스트 코드를 짜는 것보단 문제를 작은 단위로 정의하고, 피드백을 자주 받으면서 그 해답을 찾아가는 과정이 TDD의 기본 취지


TDD 사이클

  • 빨강 - 실패하는 작은 테스트
  • 초록 - 빨리 테스트가 통과하게끔 만든다.
  • 파랑 - 리팩토링: 중복 코드 제거, 일반화


고려할 점

  • 생성자를 추가하는 것을 추천
  • 메소드 추가는 비추천



📖프로그래밍 패러다임 종류

명령형 프로그래밍

  • 문제를 어떻게(HOW) 해결할 것인지에 초점
  • 명령어들로 구성
  • 절차적, 객체지향 프로그래밍


1. 절차적 프로그래밍

  • 명령어의 목록


2. 객체 지향 프로그래밍

  • 여러 개의 독립적 단위, 객체의 모임
  • 클래스로 발전
  • 추상화, 상속, 다형성, 캡슐화
  • 다형성: 메서드의 인자의 개수나 자료형에 따라서 다른 기능
  • 캡슐화: 객체의 세부 구현 내용을 숨긴다.(보안, 유지보수, 재사용)
  • 함수의 비일관성
  • 객체 내 상태 변화


선언형 프로그래밍

  • 무엇(WHAT)에 초점
  • 함수형, 논리형 프로그래밍


1. 함수형 프로그래밍

  • 함수의 정의들로 구성
  • 함수들의 집합
  • 개발자가 더 중요한 문제에 집중할 수 있도록
  • 일급 함수: 변수에 함수 할당, 함수 인자 전달, 함수 반환
    const numbers = [1, 2, 3];
    const result = numbers.map(function (number, index) {
      return number * 2;
    }); //[2, 4, 6]
    
  • 순수 함수: 동일한 인자가 들어오면 항상 동일한 결과를 반환
  • 불변성: 최초 생성된 값이 변경되지 않음
    const newArray = [...originals, 4];
    



📖객체

모듈화

  • 협력적: 외부의 도움을 받는 객체, 모든 것을 스스로 처리하는 객체는 복잡해진다.
  • 자율적: 내부와 외부를 명확하게 구분, 다른 객체가 ‘무엇’을 수행하는 지는 알 수 있지만 ‘어떻게’ 수행하는 지는 모른다.
  • 단일 책임: 한 가지 기능을 변경할 때에는 하나의 클래스만 변경
  • 캡슐화: 객체의 데이터를 직접 꺼내지 않고, 객체에 메세지를 던지도록 구조를 바꾼다.



📖유효성 검사 중복될 때

상속보다는 조합을 사용하자

조합 (먼저 생각하기)

class WinningLotto {
  constructor(winningLotto, bonusNumber) {
    if (winningLotto.has(bonusNumber)) {
      throw new Error("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
    }

    this.winningLotto = winningLotto;
    this.bonusNumber = bonusNumber;
  }
}

new WinningLotto(new Lotto([1, 2, 3, 4, 5, 6]), 7);


상속

class WinningLotto extends Lotto {
  constructor(numbers, bonusNumber) {
    super(numbers);

    if (numbers.includes(bonusNumber)) {
      throw new Error("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
    }

    this.bonusNumber = bonusNumber;
  }
}

new WinningLotto([1, 2, 3, 4, 5, 6], 7);



📖함수

JavaScript는

  • 멀티 패러다임 프로그래밍 언어: 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원
  • 일반적인 호스트 환경은 브라우저이지만, 서버 사이드, 데스크탑 앱 등 점차 다양한 호스트 환경에서 사용되고 있다.
  • 함수 역시 하나의 객체


일급 함수

JS에서 함수는 일급 객체

고차 함수

  • 다른 함수를 인자로 받거나, 함수를 리턴하는 함수를 만들 수 있다.
  • callback, 다양한 배열 내장 메서드


클로저

  • 함수의 private state가 필요하다면 클로저를 활용한다.
  • 아래는 클로저 예시이다. 이 경우 클로저를 사용할 필요는 없지만 예시의 하나로 보면 좋을 것 같다.
const createRandomGenerator = () => {
  const lottoNumbers = new Array(45).fill().map((_, index) => index + 1);

  return () => {
    lottoNumbers.sort(() => Math.random() - 0.5);
    return lottoNumbers.slice(0, 6);
  };
};
const generateLottoNumbers = createRandomGenerator();
console.log(generateLottoNumbers());
// 예시: [7, 14, 19, 23, 35, 42]


화살표 함수

  • 함수 본문이 간단한 return문만 포함할 때는 화살표 함수 문법을 사용하면 간결하게 작성할 수 있다.
  • 함수가 정의된 스코프의 this를 사용하기 때문에 함수를 다른 곳으로 전달할 때의 this에 대한 혼란을 줄일 수 있다.
  • 단일 표현식을 반환할 때 중괄호 {}를 생략하면 return이 필요 없다.
function shuffle(array) {
  return array.sort(() => Math.random() - 0.5);
}
// vs
const shuffle = (array) => array.sort(() => Math.random() - 0.5);


함수형 프로그래밍

1. 가능하면 순수 함수로 작성한다.

  • 함수의 파라미터가 함수의 input을 제공하고, 주어진 이 input에 의해서 output이 결정되도록 만든다.
  • 이러한 함수를 부수 효과가 없는 순수 함수라고 부른다.
// not pure
const numbers = [1, 2, 3, 4, 5];
function shuffle() {
  return numbers.sort(() => Math.random() - 0.5);
}

// pure
function shuffle(numbers) {
  return numbers.sort(() => Math.random() - 0.5);
}


하지만 순수 함수로만 어플리케이션을 만들 수는 없다. 아래는 중요한 부수 효과들이다.

브라우저에서의 이벤트 처리
화면에 출력
API 통신
웹 API를 사용하는 코드
데이터베이스 읽기/쓰기


  • 순수 함수는 동작을 예측하기 쉽다. 주어진 input이 같다면 항상 같은 output을 기대할 수 있기 때문이다.
  • 순수 함수는 테스트하기 쉽다. 함수 외부의 요소에 의존하는 것이 없으며, input과 output이 명확하다.
  • 테스트하기 어려운 랜덤과 같은 요소들을 분리해냈듯이, 부수 효과가 있는 함수들은 가능한 부수 효과를 위해서만 동작할 수 있도록 따로 구분한다.


2. 데이터를 불변으로 유지한다.

변수를 선언할 때는 const를 활용한다.

  • let 대신 const를 사용하는 것을 지향한다.
  • 함수를 분리하거나 선언형 방식으로 리팩토링하게 될 것이다.
  • 참조형(객체, 배열)으로 되어있는 자료형은 const일 때 참조 값 자체를 재할당할 수는 없지만 내부 속성이나 값을 변경할 수 있다.
  • Object.freeze()로 이를 해결할 수 있다.


값을 변경할 때에는 복사본을 만들어 활용한다.

const numbers = [1, 3, 5, 4, 2];

const sortNumbers = (numbers) => {
  return numbers.sort((a, b) => a - b);
};

console.log(numbers); // 원본 배열 바뀜 [1, 2, 3, 4, 5]
const numbers = [1, 3, 5, 4, 2];

const sortNumbers = (numbers) => {
  return [...numbers].sort((a, b) => a - b);
};

console.log(numbers); // 원본 배열 안 바뀜 [1, 3, 5, 4 ,2]


복사본 만들기

  • slice()

    const copied = numbers.slice();
    
  • Object.assign()

    const copied = Object.assign({}, object);
    
  • 전개 연산자(spread operator)

    const copied = [...numbers];
    


3. 선언형 코드를 지향한다.

  • 함수로 분리하고 함수의 이름으로 어떤 동작을 하는지를 드러낸다.
  • 함수를 인자로 넘겨줄 때도 필요하다면 기명함수로 만들어 가독성을 높인다.

댓글남기기