jtwjs Dev Wiki
  • DEV_ROAD
    • 💪🏻 생존하기
    • Week 1
      • 개발 환경 세팅
      • 타입스크립트
      • 리엑트
      • Testing Library
      • Parcel & ESLint
    • Week 2
      • JSX
      • Virtual DOM
    • Week 3
      • React Component
      • React State
    • Week 4
      • Express
      • Fetch API & CORS
      • React Hook
      • useRef & Custom Hook
    • Week 5
      • TDD
      • React Testing Library
      • MSW
      • Playwrite
      • Snapshot
    • Week 6
      • Separtion of Concerns
      • Principle
      • DI, (Dependency Injection)
      • Reflect-metadata
      • TSyringe
      • External Store
      • Follow Redux
      • usestore-ts
      • useSyncExternalStore
    • Week 7
      • Routing
      • Routes
      • Router
      • Navigation
    • Week 8
      • Design System
      • Style Basics
      • CSS-in-JS
      • Styled-Components
      • Global Style & Theme
    • Week 9
      • 개발하기 전 준비
      • 상품 목록 페이지
      • 상품 상세 페이지
      • 장바구니 페이지
    • Week 10
      • 로그인
      • 로그아웃
      • 회원가입
      • 주문 목록 & 주문 상세
    • Week 11
      • 배송 정보 입력
      • 포트원 결제 요청
      • 배송 및 결제 정보 전달
    • Week 12
      • 관리자 웹사이트개발시작
  • DEV_NOTE
    • TypeScript
      • 기본적 문법
        • Enum
        • 다형성
          • Untitled
        • 구조적 타이핑
        • 제너릭 타입
        • 컨디셔널 타입
        • 함수 메서드 타이핑
        • infer로 타입스크립트의 추론 직접 활용
        • 재귀 타입
        • 템플릿 리터럴 타입
        • 추가적인 타입 검사 satisfies 연산자
        • 타입스크립트 건망증
        • 원시 자료형에도 브랜딩 기법 사용 가능
        • 타입 좁히기
        • 유용한 타입 만들기
        • 데코레이터 함수
        • 앰비언트 선언도 선언 병합이 된다.
        • 앰비언트 선언도 선언병합이 된다.
    • Testing
      • Unit Testing
      • 단위 테스트의 두 분파
      • 좋은 단위 테스트를 구성하는 4대 요소
      • 테스트 대역과 식별할 수 있는 동작
      • 단위 테스트 스타일
      • 가치 있는 단위 테스트를 위한 리팩토링
      • 통합 테스트
      • Cross Browsing Testing
      • 기능 테스트 종류
      • React Testing Pattern
      • 프론트엔드 테스트 입문
        • 테스트 범위
        • 단위 테스트 검증
        • Mock
        • UI 컴포넌트 테스트
        • 테스트 커버리지
        • 웹 통합 테스트
        • MSW
        • 스토리북
        • 시각적 회귀 테스트
        • E2E 테스트
        • Github Actions 설정
        • 깃허브 액션에서 E2E
      • 시프트 레프트
        • 테스트 기본중의 기본
        • 단위 테스트
        • 코드 복잡도
        • 리팩터링
        • 코드 리뷰
        • 통합 테스트 패턴
        • 시스템 테스트의 자동화
        • 탐색적 테스트
      • Test Tip
      • vitest
      • playwright
      • Test Data Generator
      • MSW
    • Algorithm
      • coding test
      • Data Structure
    • Next.js
      • Data Fetching
      • Hydration
      • Next 13
      • Optimization
      • Next 15
    • Tailwind
      • Tailwind CSS
      • Theme
      • Directives
      • Tool
      • Design System
    • Storybook
      • Storybook
      • CSF3
      • CDD
      • Headless Component
    • Funtional Programming
      • 함수형 프로그래밍
      • 참조 투명성
      • 부수효과
      • 함수 합성
      • 제너릭 타입 활용하기
      • 암묵적 입출력
      • 액션과 계산, 데이터
      • 계층형 설계
      • 호출 그래프
      • 함수형 설계
      • 불변성
      • 일급 함수
      • 함수형 도구
    • Git
      • Github Actions
      • Conflict
      • Branch 전략
    • Contents Format
      • Audio
    • 3D Graphic
      • 3D keyword
      • Three.js
      • Geometry
      • Material
      • Light
      • Camera
      • Decal
      • Rotation
      • Text
      • Shadow
      • Fog
      • Post Processing
      • Animation
      • Math
        • Vector Space
        • 벡터의 연산
        • 회전 계산
      • 3D 컨텐츠가 만들어지는 과정
      • R3F
      • Env
      • Scene
      • Transform
      • R3F
      • Interaction & Raycast
      • Rendering Algorithnm
      • Blender
      • Blender
    • Accessibility
      • 접근성이란
    • Interactive Web
      • Parallax
      • Canvas
      • requestAnimationFrame
      • Effect
      • HSL
      • React.js + Canvas
      • Matter.js
    • AWS
      • DevOps
      • Amplify
      • S3
      • 클라우드 컴퓨팅
        • 온프레미스와 클라우드
        • 클라우드 도입효과
        • 클라우드 컴퓨팅의 범위
        • 컴퓨팅 옵션
          • EC2 - Virtual Machin
          • ECS, EKS - Container
          • Lambda - Serverless
        • 네트워크 가상화
        • 스토리지
        • 데이터베이스
        • 데이터 수집
        • 머신 러닝 영역
        • IoT 영역
        • 블록체인 영역
      • 클라우드 아키텍처 설계
    • Network
      • Web Server & WAS
    • System Design
      • System Design
      • Component
      • 의존성을 배제한 개발
      • Error Handling
      • Architecture
        • 모노로틱 아키텍처
        • Clean Architecture
        • Layered Architecture
        • 이벤트 기반 아키텍처
      • 상황을 파악하는 메타인지
      • 중복 문제 해결하기
      • Monorepo Arhitecture
        • 모노레포 운영과 트러블슈팅
        • Module Federation
      • 코드 병목지점
      • API 대응
      • 공통 코드
      • Infra 구축
      • 모듈 기반의 개발 방식
      • Design System
        • 최소 수준의 아키텍처 설정
        • 더 효율적인 디자인시스템 만들기
        • 디자인 시스템과 UI 라이브러리 목적
        • 디자인 토큰
      • 효율적인 업무
        • 업무 프로세스 병목 파악
      • Clean Code
      • Design Pattern
        • CQRS Pattern
        • Strangler Fig Pattern
        • 데코레이터 패턴
        • 커맨드 패턴
        • 전략 패턴
        • 옵저버 패턴
      • A/B 테스팅
      • 대규모 리엑트 웹앱 개발
        • 복잡성 관리
        • 모듈성
        • 성능
        • 디자인 시스템
        • 데이터 패칭
        • 상태 관리
        • 국제화
        • 코드 조직화하기
        • 개인화 A/B 테스팅
        • 확장 가능한 웹 아키텍처
        • 테스팅
        • 툴링
        • 기술적 마이그레이션
        • 타입스크립트
        • 라우팅
        • 사용자 중심 API 디자인
        • 리액트 미래
    • Performance
      • React DevTools
      • Component 최적화
      • Page Load
      • API
    • MFA
      • MSA
      • MFA 도입하기
      • Monorepo
        • Monorepo Tool
        • Yarn Berry Workspace
        • Turborepo
      • MFA Composition
      • SPA 통합
      • Design System
      • Package Manager
        • Yarn
        • pnpm
      • Transpiler & Bundler
        • Babel
        • Rollup
        • esbuild
        • swc
        • Webpack
        • Vite
      • 분해와 통합을 위한 여러 기술 비교
    • State Management
      • Zustand
    • React v18
      • Automatic batching
      • Suspense
      • Transition
    • SEO
      • Search Engine Optimization
      • Open Graph Element
      • Metadata
    • FE Develop
      • Scrubbing
      • Clipboard
    • Refactoring
      • 리팩토링 깊게 들여다보기
      • 긴 코드 조각내기
      • 타입 코드 처리하기
      • 유사한 코드 융합하기
      • 데이터 보호
      • 코드 추가 및 제거
    • OAuth 2.0
    • Analytics
      • Mixpanel
    • ETC
      • VSCode
    • React Hook In Action
      • useContext & Provider
      • 커스텀 훅
      • 코드 분할하기 with Suspense, lazy
      • Suspense와 이미지 적재하기
      • useTransition, uesDeferredValue
      • SuspenseList
Powered by GitBook
On this page
  • 긴 코드 조각 내기
  • 다섯 줄 제한
  • 함수 분해하기 & 함수 추출하기
  • 추상화 수준을 맞추기 위한 함수 분해
  • 좋은 함수 이름의 속성
  • if 문은 함수의 시작에만 배치
  1. DEV_NOTE
  2. Refactoring

긴 코드 조각내기

너무 많은 역할을 하는 함수를 식별하고 리팩토링 해보자!

  • 다섯 줄 제한으로 지나치게 긴 함수 식별하기

  • 세부 사항을 보지 않고 코드 작업하기

  • 함수 추출로 긴 함수 분해하기

    • 함수 추출을 통해 변수명을 변경해서 가독성을 높이자.

  • 호출 또는 전달, 한 가지만 할 것으로 추상화 수준 맞추기

  • if 문은 함수의 시작에만 배치로 if 문 분리하기

긴 코드 조각 내기

DRY (Don't Repeat Yourself, 똑같은 일에 두 번 반복하지 말 것), KISS (Keep It Simple, Stupid, 단순함을 지킬 것), 지침을 따르더라도 코드는 쉽게 지저분해진다.

이 경우 주 원인은 다음과 같다.

  • 함수가 여러 가지 다른 일을 수행

  • 낮은 수준의 원시 연산(배열 조작, 산술 연산 등)을 사용

  • 주석과 적절한 메서드와 변수명 같이 사람이 읽을 수 있는 텍스트가 부족

다섯 줄 제한

어떤 함수도 다섯 줄 이상을 가질 수 없다 (함수는 {, } 를 제외하고 5줄 이상이 되어서는 안된다.)

다섯 줄 제한은 궁극의 목표!!

  • 문장이라고 하는 코드 한 줄은 하나의 if, for, while 또는 세미콜론으로 끝나는 모든 것을 말함

    • 즉, 할당, 함수 호출, return 같은 것들이다. 공백과 중괄호는 제외한다.

단순히 코드가 수치상으로 5줄 이상을 말하는 것은 아님!

코드의 라인은 린트 또는 프리티어 규칙에 의해 달라질 수 있기 때문에 코드 상에 한줄이 아닌 위 규칙에 따른 한 문장을 의미한다.

function isTrue(bool: boolean) { //총 4줄(문장)
  if (bool) // if - 1문장
    return true; // return - 2문장
  else return false; // else - 3문장, return - 4문장
}

스멜

  • 함수가 길다는 것 자체가 스멜

    • 길다는건 메서드는 한 가지 작업만 해야 한다는 다른 스멜을 생각해 볼 수 있다.

  • 한 번에 긴 메서드의 모든 논리를 머릿속에 담아야해서 작업하기 어렵다.

의도

  • 관심을 가지지 않으면 시간이 지남에 따라 더 많은 기능이 추가되면서 메서드가 커지는 경향이 늘 생김

    • 그로 인해 코드를 점점 더 이해하기 어렵게 된다.

  • 각각 5줄의 코드가 있는 4개의 메서드가 20줄인 하나의 함수보다 훨씬 빠르고 이해하기 쉽다.

    • 각 함수의 이름으로 코드의 의도를 전달할 수 있기 때문

  • 또한 작은 함수에 적절한 이름을 붙이면 큰 함수의 이름을 정하는 데도 도움이 된다.

함수 분해하기 & 함수 추출하기

다섯 줄 제한 규칙은 이해하기 쉽지만 항상 지킬 수 있는 것은 아님

함수 전체를 소화하려 하지 말고, 작게 잘라서 이해하기 쉽게 하나씩 처리!

  • 코드를 이해하기 위한 첫 번째 단계는 항상 함수명을 고려하는 것

  • 각 줄을 모두 이해 하려다 보면 시간이 많이 걸리고 비생산적이게 된다.

  • 그래서 코드의 '형태'를 살펴보는것으로 시작

Step

  1. 동일한 작업을 하는 데 필요한 줄들을 그룹으로 묶어 주석달기

  2. 식별된 그룹의 모든 줄을 선택한 다음 잘라내어 별도 함수로 추출

  3. 추출한 함수를 호출하는 코드를 추가 및 주석 제거

  4. 추출한 함수에서 1~3 동일한 절차 반복

함수 분해하기는 단순히 코드 줄만 이동하는것이기 때문에 비교적 리팩터링 위험도가 낮다.

if의 일부 분기만 return 문을 가지고 있을 경우 함수를 추출하는 데 방해가 될 수 있으므로 함수의 끝에서 시작해 위로 작업해가는 것이 좋다. 이는 return 문을 가진 조건을 메서드의 앞쪽에 배치하게 해서 결과적으로 모든 분기에서 return 할 수 있게 한다.

자신감이 떨어지는 예쁜 코드를 만드는 것보다 특이하게 생긴 안전한 코드를 만드는 편이 더 낫다.

추상화 수준을 맞추기 위한 함수 분해

함수 내에서는 객체에 있는 함수를 호출하거나 객체를 인자로 전달할 수 있지만 둘을 섞어 사용해서는 안된다.

호출 또는 전달, 한 가지만 할 것! 함수의 내용은 동일한 추상화 수준에 있어야 한다.

  • 더 많은 함수를 도입하고 여러 가지를 매개변수로 전달하기 시작하면 결국 책임이 고르지 않게 된다.

  • 예를 들면, 함수에서 배열에 인덱스를 설정하는 것과 같은 직접적인 작업을 수행하거나 동일한 배열을 더 복잡한 함수에 인자로 전달할 수 있다.

    • 그러면 코드는 직접 조작하는 낮은 수준의 작업과 다른 함수에 인자로 전달하는 높은 수준의 호출이 공존해서 함수 이름 사이의 불일치로 가독성이 떨어지게 된다.

  • 동일한 수준의 추상화를 유지하는 편이 코드를 읽기 훨씬 더 쉽다.

// 높은 수준의 추상화 sum(arr)와 낮은 수준의 arr.length 모두 사용한 케이스
function average(arr: number[]) {
  return sum(arr) / arr.length
}

// 추상화 동일하게 refactoring
function average(arr: number[]) {
  return sum(arr) / size(arr);
}

스멜

함수의 내용은 동일한 추상화 수준에 있어야 한다.

  • 전달된 인자의 메서드가 어떻게 사용되었는지를 식별하는 것은 간단한 일

  • 인자로 전달된 변수 옆의 .로 쉽게 찾을 수 있다.

의도

  • 함수에서 몇 가지 세부적인 부분을 추출해서 추상화를 도입할 때 이 규칙은 연관된 다른 세부적인 부분도 추출하게됨

  • 이렇게 하면 메서드 내부의 추상화 수준이 항상 동일하게 유지된다.

좋은 함수 이름의 속성

함수를 추출할 때 마다 함수의 이름을 지어 코드를 더 읽기 쉽게 만들 수 있다.

함수명을 지을 때는 항상 나중에 함수가 더 작아졌을 때 이름을 개선할 수 있는지를 평가해봐야 한다.

좋은 함수 이름이란?

  • 정직해야한다. -> 함수의 의도를 설명해야함

  • 완전해야 한다. -> 함수가 하는 모든 것을 담아야 한다.

  • 도메인에서 일하는 사람이 이해할 수 있어야 한다. -> 작업 중인 도메인에서 사용하는 단어를 사용

// Before
function draw() {
  let canavs = document.getElementById("GameCanvas") as HTMLCanvasElement;
  let g = canavs.getContext('2d');
  
  // 추상화 수준이 다르다.
  g.clearRect(0, 0, canvas.width, canavs.height); // 객체의 메서드 호출 (저수준)
  drawMap(g); // 객체를 인자로 전달 (고수준)
  drawPlayer(g);
}

// After
function createGraphics() {
  let canavs = document.getElementById("GameCanvas") as HTMLCanvasElement;
  let g = canavs.getContext('2d');
  g.clearRect(0, 0, canvas.width, canavs.height);
  
  return g;
}

function draw() {
  const g = createGrpahics(g);
  drawMap(g);
  drawPlayer(g);
}

만약 g.clearRect 줄만을 추출한다면 결국 canvas를 인자로 전달하면서 canavs.getContext를 호출하게 돼서 다시 규칙이 위반된다.

함수 네이밍으로 자주 사용되는 접두사 키워드들

handle, update, contain, get, delete

if 문은 함수의 시작에만 배치

if 문이 있는 경우 해당 if 문은 함수의 첫 번째 항목 이어야 한다.

  • 함수는 한가지 일만 해야 한다.

  • 무언가를 확인하는 것은 한 가지 일이된다.

  • 따라서 함수에 if가 있는 경우 함수의 첫 번째 항목 이어야 한다.

  • 또한 그 후에 아무것도 해서는 안된다는 의미에서 유일한 것이어야 한다.

  • if 문이 함수가 하는 유일한 일이어야 한다는 말은 곧 그 본문을 추출할 필요가 없고, 또한 else 문과 분리해서는 안된다는 말이다.

  • 본문과 else는 모두 코드 구조의 일부이며, 이 구조에 의존해서 작업하므로 코드를 이해할 필요가 없다.

동작과 구조는 밀접하게 연결되어 있으며, 리팩터링할 때 동작을 변경해서는 안되므로 구조도 변경해선 안됨

// Before
// 두 가지 분명한 작업 존재
// 1.숫자를 반복, 2.숫자가 소수인지 확인
function reportPrimes(n: number) {
  for (let i=2; i<n; i++) {
    if (isPrime(i)) console.log(i);
  }
}

// After
function reportPrimes(n: number) {
  for (let i=2; i<n; i++) {
    reportIfPrime(i)
  }
}

function reportIfPrime(n: number) {
  if(isPrime(n)) {
    console.log(i)
  }
}

[remind] 무언가를 확인하는 것은 하나의 작업이며, 하나의 함수에서 처리해야 한다.

스멜

다섯 줄 제한과 같이 이 규칙은 함수가 한가지 이상의 작업을 수행하는 스멜을 막기 위해 존재

의도

  • 이 규칙은 if 문이 하나의 작업이기 때문에 이를 분리할 때 이어지는 else if, if 문과 분리할 수 없는 원자 단위로 본다.

  • 이것은 if 문이 else if와 함께 문맥을 형성할 때 함수 추출로 수행할 수 있는 가장 작은 단위가 if 문과 이어지는 else if 까지 포함된다는 것을 의미

if와 else if를 분리할 수 없기 때문에 다섯 줄 제한을 지키기 위해 메서드 추출을 적용할 수 없지만 우아한 해결책이 따로 존재함 (링크 예정)

Previous리팩토링 깊게 들여다보기Next타입 코드 처리하기

Last updated 1 year ago