2/17 금 (Rule of Three 중복 제거 리팩토링, 생생한 예제 코드가 여기있다) TIL
(막간 보충 공부중)
오늘 한 것:
- Mars Rover Kata와 중복 제거 리팩토링 시범Test-Driven Development (TDD) in JavaScript #4 - Duplication & The Rule Of ThreeIn this video, Jason Gorman illustrates how refactoring to remove duplication from our code can lead us to a better design, and demonstrates the Rule of Three that can guide us towards better abstractions and protect us from leaving refactoring too late. The example used is the Mars Rover Kata https://kata-log.rocks/mars-rover-kata
https://www.youtube.com/watch?v=dFemuNMjgr4
Mars Rover Katahttps://kata-log.rocks/mars-rover-kata
- 프로그래머스 Lv0 점의 위치 구하기
- 프로그래머스 Lv0 배열 뒤집기
- 8시 문제 풀이 스터디
- Nest.js로 간단 게시판 만들기 코드 재작성 (2회차) ⇒ 오오오 이해가 된다 된다..!
공부 자료 후보
- Mars Rover Kata - 왼쪽으로 돌기도 구현해보기. (조금 더 도움을 받으려면 여기 - https://www.youtube.com/watch?v=CStNXUDc10Y&list=PL1tIFPlmF4ykUGElb7NIUbaI5r4A8DuCQ&index=6)
- (리액트 + 인수(Acceptance) TDD 테스트 ⇒ 할 일 프로그램을 인수테스트 하는데, 리액트랑 잠깐 공부해 볼 시간 있으면 봐도 좋을 것)Test-Driven Development in JS with Acceptance Tests🤔 This video explains why TDD is not about testing to find bugs, but instead is used to find the best technical solution. I'll discuss red-green-refactor and do live-coding to show how you can use TDD with Acceptance Tests. 🌱 Source code: https://github.com/branneman/tdd-example 0:00 Intro 0:57 Why TDD 6:48 The TDD loop 13:12 TDD with Acceptance Tests
https://www.youtube.com/watch?v=ym62X_gvMXs
TypeORM 이슈
entities: [Article]
여기 참조하라고: https://docs.nestjs.com/recipes/sql-typeorm#getting-started
(아마존 AWS 무슨무슨 인스턴스 사용하고 있는지 전체를 보고 싶을 때: )
“청구서”를 확인해 힌트를 얻거나 - https://us-east-1.console.aws.amazon.com/billing/home?region=us-east-1#/bills?year=2023&month=2
“Free tier” 항목을 확인해 힌트를 얻는다 - https://us-east-1.console.aws.amazon.com/billing/home?region=us-east-1#/freetier
“Rule of Three”, 중복 제거 리팩토링의 황금률
“Rule of Three”, 중복 제거 리팩토링의 황금률
중복을 제거하기 위한 리팩토링을 실시하기 위한 최적의 타이밍은 반복되는 코드를 3번 작성하게 됐을 때이다.
예시로, Mars Rover 라는 코딩 문제 중 ‘화성 탐사 무인기를 오른쪽으로 방향 전환 시켜라’라는 기능을 테스트 및 구현중이라고 하자.
소스 코드 리팩토링 예시
리팩토링 이전
// src/mars-rover-kata.js
function go(rover, instruction) {
if (rover.facing === 'N') {
rover.facing = 'E'
} else if (rover.facing === 'E') {
rover.facing = 'S'
} else {
rover.facing = 'W';
}
return { ...rover };
}
module.exports.go = go;
이렇게 if문으로 3번 반복되어 쓰여지는 타이밍에 리팩토링을 하도록 한다.
이후
function go(rover, instruction) {
const compass = ['N', 'E', 'S', 'W'];
rover.facing = compass[(compass.indexOf(rover.facing) + 1) % compass.length]
return { ...rover };
}
module.exports.go = go;
아니면 더 간단하게 이렇게도
function go(rover, instruction) {
const compass = ['N', 'E', 'S', 'W'];
return {...rover, facing: compass[(compass.indexOf(rover.facing) + 1) % compass.length]}
}
module.exports.go = go;
테스트 코드 리팩토링 예시
짝이 되는 테스트 코드도 리팩토링의 대상이다!
이전
// src/mars-rover-kata.test.js
const { go } = require('./mars-rover-kata')
describe('Mars Rover', () => {
it('turns right from N to E', () => {
let rover = {facing: 'N'}
rover = go(rover, 'R')
expect(rover.facing).toEqual('E');
});
it('turns right from E to S', () => {
let rover = {facing: 'E'};
rover = go(rover, 'R');
expect(rover.facing).toEqual('S');
});
it('turns right from S to W', () => {
let rover = {facing: 'S'}
rover = go(rover, 'R')
expect(rover.facing).toEqual('W');
});
it('turns right from W to N', () => {
let rover = {facing: 'W'}
rover = go(rover, 'R')
expect(rover.facing).toEqual('N');
});
})
// =>
PASS src/mars-rover-kata.test.js
Mars Rover
√ turns right from N to E (1 ms)
√ turns right from E to S
√ turns right from S to W
√ turns right from W to N (1 ms)
테스트 케이스(it) 마다 같은 패턴이 반복되고 있다. 리팩토링 해보자.
좋지 않은 리팩토링 (나의 시도):
// src/mars-rover-kata.test.js
const { go } = require('./mars-rover-kata')
describe('Mars Rover', () => {
it('turns right properly from any of the starting direction', () => {
let rover = {facing: 'N'}
rover = go(rover, 'R')
expect(rover.facing).toEqual('E');
rover = go(rover, 'R')
expect(rover.facing).toEqual('S');
rover = go(rover, 'R')
expect(rover.facing).toEqual('W');
rover = go(rover, 'R')
expect(rover.facing).toEqual('N');
});
})
// =>
PASS src/mars-rover-kata.test.js
Mars Rover
√ turns right properly from any of the starting direction (1 ms)
한 테스트 케이스 안에 여러 테스트 상황을 뭉뚱그려 넣는 것은 좋지 않다고 할 수 있다.
제대로 된 리팩토링:
// src/mars-rover-kata.test.js
const { go } = require('./mars-rover-kata')
describe('Mars Rover', () => {
[
{ startFacing: 'N', endsFacing: 'E' },
{ startFacing: 'E', endsFacing: 'S' },
{ startFacing: 'S', endsFacing: 'W' },
{ startFacing: 'W', endsFacing: 'N' },
].forEach(({startFacing, endsFacing}) => {
it(`turns right from ${startFacing} to ${endsFacing}`, () => {
let rover = {facing: startFacing};
rover = go(rover, 'R');
expect(rover.facing).toEqual(endsFacing);
});
});
})
// =>
PASS src/mars-rover-kata.test.js
Mars Rover
√ turns right from N to E (1 ms)
√ turns right from E to S
√ turns right from S to W
√ turns right from W to N (1 ms)
(덜 영근) 궁금증들
(덜 영근) 궁금증들
1. 클래스가 타입으로 사용될 수 있었나?
// 04.3_nest_practice_with_typeorm/src/app.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
...
let app: TestingModule;
app = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();
⇒ Test도 TestingModule도 둘 다 class인데, 하나는 타입 선언으로 쓰였다.
- 클래스를 타입으로 사용할 수 있는가?? 분명 타입 선언 자리에 올 수 있는 것(’선언 타입군’) 여기에 정리하기로는 “Interface로 선언한 클래스”만 타입 선언 자리에 올 수 있다고 했는데, 저 TestingModule은 아무리 봐도 그냥 클래스이다.
// @nestjs/testing/testing-module.d.ts export declare class TestingModule extends NestApplicationContext {
2. module.exports = 과 그냥 export class …의 차이
3. 클래스에서 declare, protected, readonly, private의 사용 위치
export declare class ValidationPipe implements PipeTransform<any> {
protected isTransformEnabled: boolean;
...
}
4. ES6 그 이전과 이후 - 수집중
여기저기서 나타나는 흔적들:
// tscongif.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"esModuleInterop": true
}
}
⇒ "esModuleInterop": true
: “ES6 모듈 사양을 준수하여 CommonJS 모듈을 가져올 수 있게 한다.”
Uploaded by N2T