CleanCode JS - 변수

pds·2022년 11월 25일
0

Cleancode

목록 보기
1/5

클린코드 자바스크립트 강의를 듣고 얻은 정보를 참고하여 기록한 내용입니다.


클린코드를 위한 자세

타인의 답을 의심한다. (맹목적으로 믿지 마라)

늘 열린 태도로 배울 것

직접 생각하고 고민하고 고민하기

널리 알려진 js 코드 스타일 탐구하기 (에어비엔비 등 왜 있고 왜 쓸까 같은?)


왜 클린코드

자바스크립트는 매우 유연해서 어디에서든 사용될 수 있는 범용적 언어임

유연하기 때문에 많은 것들이 코드에 드러나져 있지 않고 많은 실수를 할 수 있는 환경임

클린코드 를 준수해 다양한 곳에서 동작하는 안전한 앱을 만들자!



global area 사용을 최소화 하자!

브라우저 기준 전역 공간(최상위 위치)은 Window이다.


의도치 않은 동작을 유발한다

<html>
  <head><title>hi</title></head>
  <script src="./h.js"></script>
  <script src="./h2.js"></script>
  <body>
  </body>
</html>
// h.js
const a = "hello";
console.log(a):
// h2.js
const a = "hell";  // Uncaught SyntaxError: Identifier 'a' has already been declared (at h2.js:1:1)

여러 스크립트 파일을 사용하기에 보기에는 격리되어있는 것 처럼 보이지만 런타임 환경에서는 그렇지 않으며 같은 스코프를 가진다.

같은 생명주기를 가지게 되어 전역 공간에 위치한 상수, 변수 같은 것들이 겹칠 경우 동작하지 않거나 재할당되어 의도치 않은 동작을 유발할 수 있음


var를 쓰면...

전역 공간에 var를 사용한다는 것은 window 객체의 속성에 해당 변수를 추가하는 것 이라고 생각하면 된다.

이미 존재하는 원도우 객체의 속성을 재정의 해버린다던가 하여 의도치 않은 동작을 유발할 수 있음

또한 어디에서든 전역 변수에 쉽게 접근할 수 있어

저 변수의 값으로 뭔가 유의미한 동작을 하려던 속셈이라면 보안적으로도 위험함

var 는 함수 스코프로 생명주기를 가짐을 알아야 한다.

전역 공간에 함수가 아닌 블럭스코프에 var 를 사용해도 되겠지 싶어서 사용했다가는 window 객체를 오염시키게 된다!


해야할 것

(1) 애초에 스크립트에 전역 변수를 만들지 않는다.

(2) const,let으로만 사용하고 변수는 반드시 지역변수로만 만들어 사용한다.

(3) window 객체를 직접 조작하는 것을 지양한다.

(4) 즉시실행함수, 모듈, 클로저 등을 이용해 전역 공간으로부터 스코프를 분리한다.



임시변수 사용 유혹에서 벗어나자

임시변수?

스코프 하나에서 무언가 로직을 처리하기 위해 선언되고 사용되는 변수

해당 스코프 관점에서 바라보면 이 임시변수는 전역변수나 마찬가지이다.


변화 예측이 힘들고 디버깅이 어려운 함수가 된다

function isStar(currentValue, x, y, array) {
  let currentStatus = true;
  for (let i = 0; i < X.length; i++) {
    if (
      x + X[i] >= 0 &&
      x + X[i] < array.length &&
      y + Y[i] >= 0 &&
      y + Y[i] < array[0].length
    ) {
      currentStatus =
        currentStatus & (currentValue > array[x + X[i]][y + Y[i]]);
    }
  }
  return currentStatus;
}

본인이 알고리즘 풀다가 작성한 함수로

2차원 배열의 특정 값을 상하좌우 좌표와 비교해 별이 되어야 하는지 여부를 리턴해주는 함수이다.


currentStatus 라는 임시변수가 있고 이 변수는 내부에서 특정 로직을 수행하여 변경되거나 하는 과정을 거쳐 그대로 리턴되는 형식이다.

currentStatus가 내부에서 어떤 과정을 거쳐서 변화하는지 알아채기 힘들고 무언가 의도되지 않은 결과가 나왔을 때 잘못된 지점을 파악하기 어려워진다.



단일 책임 원칙 위반 유혹의 근거가 된다

위의 함수는 단일책임원칙을 위반하고 있다.

상하좌우 좌표로부터 현재 좌표가 별인지 여부를 얻어라 라는 역할인데

상하좌우 좌표가 유효한 좌표인가 라는 검증 로직 코드도 같이 포함되어있다.

이럴 경우 해당 함수의 로직이 틀렸을 때 디버깅이 힘들어 변경이나 확장도 어려워지고

함수의 정확한 의도를 파악하기 힘들어 무엇보다 읽기가 힘들다.


저 문제 풀 때도 저 함수에 실수하나를 했었는데

functional test를 만들어서 돌렸지만 함수 자체가 길고 하나의 변수가 긴 생명주기를 가지게 되어있어서

테스팅으로는 유의미한 힌트를 얻지 못했고 결국 하나하나 디버깅하며 오류지점을 찾았던 것 같다.

함수 책임을 잘 분리해두면 그 함수 하나하나만 기능 테스트를 수행하여

내 의도대로 잘 동작이 된다 라는 것을 확신하고 사용할 수 있어

오류 발생 시 찾기가 수월해지는 것 같다.

그래서 함수는 하나의 의도한 역할만을 수행하는 것이 좋다고 생각한다.



예시?

간단한 예로 사용자가 자기 정보를 form에 입력했다고 치고

다음과 같은 요구사항을 처리해야 한다고 생각해보았다.

입력으로부터 회원정보 객체를 만들어 보여줘야 해요. 회원정보 객체를 리턴하는 함수를 만들어주세요

function getUser() {
  const name = document.getElementById('id-name');
  const age = document.getElementById('id-age');
  const job = document.getElementById('id-job');
  return {name, age, job};
}

여기서 매우 억지긴 하지만 만약 다음과 같은 요구사항이 추가된다면 어떻게 해야할지 생각해보자

사람들이 본인 이름이 모두 나오는 것을 꺼려해요 성만 나오게 해주세요

function getUser() {
  let name = 
        document.getElementById('id-name');
  name = name[0] + " 모씨"; // 여기를 변경해야할까?
  const age = document.getElementById('id-age');
  const job = document.getElementById('id-job');
  return {name, age, job};
}

임시 변수의 사용은 이렇게 기존의 역할을 가지고 있던 함수의 수정에 대한 여지를 준다.

getUser() 는 사람들에게 보여질 뿐 아니라 db에 저장한다던가 등 다양한 곳에 사용되고 있었을 수도 있고

또 서비스 정책이 바뀌어서 사용자가 이름 필터링 여부를 선택할 수 있게 된다고 하면

기존의 회원객체 리턴 함수는 파괴되었기 때문에 결국은 또 만들어야 한다.

임시 변수 지양이 함수의 책임을 제한할 수 있다고 한다.

function getUser() {
  return { name: document.getElementById('id-name'), 
           age: document.getElementById('id-age'), 
           job: document.getElementById('id-job'),
         };
}

솔직히 위 예제에서 수정이야 어디서든 할 수 있고 큰 차이는 없다고 생각하지만

이르게 리턴시킴으로써

이 함수는 더 이상 조작하지 않을 본인의 역할을 끝낸 함수다

라는 것을 명시해주기 위해 임시변수를 사용하지 말라는 것이 아닐까?

라고 이해하였다.


물론 서비스에서 입력 자체가 추가된다던가 하면 저 함수의 결과에 속성이 추가되어야겠지만

추가적인 스펙이나 부가적인 기능 같은걸 넣지 말라는 것이 아닐까 싶다.

되도록 임시변수를 사용하지 않음으로 함수의 책임을 늘릴 여지를 주지 말라는 뜻으로 생각하였다.


추가적인 스펙에 대한 요구사항이 있다면 기존 함수의 직접적인 수정이 아니라 기존 함수를 이용한 확장 방식을 이용할 수 있을 것 같다.

function getUser() {
  return { name: document.getElementById('id-name'), 
           age: document.getElementById('id-age'), 
           job: document.getElementById('id-job'),
         };
}

function getFilteredNameUser() {
    const user = getUser();
	return {...user, name: user.name[0] + " 모씨"};
}

임시변수 사용 지양 이유 요약

임시변수를 선언해 명령형으로 crud 하는 복잡한 로직을 구성하면 테스트, 디버깅 추적 힘들다.

추가적 코드 작성 환경이 조성되어 함수의 기존 책임이 파괴되어 사이드이펙트가 발생할 수 있고 유지보수가 어려워질 수 있다.


해결책

함수를 분리한다.

가능하다면 임시변수 없이 즉시 리턴시킨다.

고차함수를 사용한다.

선언형 프로그래밍 지향


Reference

profile
강해지고 싶은 주니어 프론트엔드 개발자

0개의 댓글