[번역]Typescript 내에 존재하는 '악취나는 코드'를 제거해보자

이관형·2022년 12월 18일
1
post-thumbnail

해당 글은 https://blog.bitsrc.io/what-are-code-smells-and-how-clean-code-can-help-typescript-version-990697a87f46 글을 번역한 글입니다.
저자의 글을 확인하고싶으시면 여기를 클릭해주세요.

코드에서 악취가 난다?

위키피디아에 따르면, 악취는 심각한 문제를 야기할수있는 소스코드를 뜻합니다.
간단하게 정의하자면, 깨끗하지않고 잘못된 프로그래밍의 결과라고 할 수 있습니다.
악취는 참을수 있을정도의 작은 악취부터 프로그램 개발을 더욱더 어렵고 비효율적으로 만드는 악취까지 다양한 범주로 존재합니다.

자바스크립트 와 타입스크립트에 있는 악취

  • 많은 양의 주석
  • 많은 양의 "TODO"
  • 함수에 많은 양의 매개변수
  • ...

이번 글에서 저는 자바스크립트와 타입스크립트에 보편적으로 존재하는 악취에대해 초점을 맞추려고합니다.

불필요한 타입 중복 및 non-null 선언은 피해야합니다.

타입스크립트 컴파일러는 자동으로 변수의 타입을 추론할수있습니다.(typeof, instanceof 등등).
이러한 컴파일러 기능 덕분에 재선언과 non-null 선언은 필요없습니다.

나쁜 예시

function getName(x?:string|UserName){
  	if(x){
      	console.log("Getting name for " + x!) //Noncompliant
      
      if(typeof x === "string")
      	return (x as string) //Noncompliant
      else
        return (x as UserName).name //Noncompliant
    }
  	return "NoName"
}

좋은 예시

function getName(x?:string|UserName){
  	if(x){
      	console.log("Getting name for " + x) //Noncompliant
      
      if(typeof x === "string")
      	return x //Noncompliant
      else
        return x.name //Noncompliant
    }
  	return "NoName"
}

삼항 연산자는 중첩되어서는 안됩니다.

삼항 연산자는 가독성이 뛰어나고 사용하기 쉽기때문에 JavaScript에서 널리 사용됩니다. 그러나 때떄로 우리들은 삼항연산자를 남용합니다. 중첩된 연산을 별도의 문장으로 표현하려면 다른 줄을 사용하는것이 좋습니다.

나쁜 예시

function getReadableStatus(job){
  return job.isRunning() ? "Running" : job.hasErrors() ? "Failed" : "Succeeded"
}

좋은 예시

function getReadableStatus(job){
  if(job.isRunning()){
    return "Running"
  }
  return job.hasErrors() ? "Failed" : "Succeeded"
}

배열을 변환시키는 메소드를 잘못사용해서는 안됩니다.

Javascript의 많은 배열 함수들은 기존 배열은 그대로 둔 채 새로운 배열을 반환시킵니다. reversesort 함수는 이러한 배열 함수들에 포함되지않습니다. 그들은 새로운 배열을 반환시키는것 외에도 기존 배열들을 변경하기도하는데 아마 의도하고 사용하지않았을 가능성이 높습니다.
이 특징은 반환된 배열이 할당될때 문제를 야기하는데 코드를 유지보수할때 원래 값이 변경되었다는 사실을 간과할 수 있습니다.

나쁜 예시

var a = a.reverse()
var d = c.sort()

좋은 예시

var b = [...a].reverse()
a.reverse()

c.sort()

할당이 중첩되어서는 안됩니다.

'a == b 이고 b == c이면 a == c 이다'라는게 추이적 관계입니다. 이러한 상황에서 ac를 할당하는건 좋지않습니다. 이미 동일하기 때문입니다.

나쁜 예시

a = b
b = c
b = a

좋은 예시

a = b
c = a

TypeScript에서 "Any"타입은 남용하지마세요.

이 조언은 당연한거라 별로 할 말이 없습니다. 여러분들은 타입이 안전하지않은 레거시 라이브러리에만 any타입을 써야합니다. 그 외 99%경우에는any 타입을 사용하지않을 수 있을겁니다.

타입 별칭을 사용하세요.

유니온 타입(Union Type)과 인터섹션 타입(Intersection Type)은 사용함에 있어서 편리하지만 가독성과 유지보수에는 힘듭니다. 그렇기떄문에 particular union 또는 intersection이 여러 곳에서 사용된다면, 타입 별칭을 사용해보세요.

나쁜 예시

function foo(x:string|null|number) {
  ...
}
function bar(x:string|null|number) {
  ...
}
function zoo():string|null|number {
  return null
}

좋은 예시

type MyType = string | null | number

function foo(x:MyType){
  ...
}
function bar(x:MyType){
  ...
}
function zoo():MyType{
  return null
}

정규표현식에 많은 공백이 표현되어서는 안됩니다.

정규표현식 내에 많은 공백은 일치해야하는 공간이 몇 개인지 구별하기 어렵게만듭니다. 하나의 공간만 사용하고 수량 한정 기호를 이용하여서 얼마나 많은 공간이 예상되는지 표시하는것이 더 좋습니다.

나쁜 예시

const pattern = /Hello,    world!/

좋은 예시

const pattern = /Hello, {3}world!/

함수에 "delete" 연산자를 사용하지마세요.

delete 연산자를 이용하여 어떠한 object에서 속성을 제거할 수 있습니다. 배열도 object이기때문에 배열에도 delete 연산자를 사용할 수 있다. 그러나 만약 사용하게된다면 삭제 내용을 반영하도록 인덱스/키가 이동되지않기때문에 배열에는 구멍이 나있을겁니다.

특정 인덱스에서 요소를 제거하는 적절한 방법은 다음과 같습니다.

  • Array.prototype.splice - 배열에서 요소를 추가/삭제할 수 있습니다.
  • Array.prototype.pop - 배열의 마지막 요소를 추가/삭제할 수 있습니다.
  • Array.prototype.shift - 배열의 첫번째요소를 추가/삭제할 수 있습니다.

나쁜 예시

var myArray = ['a','b','c','d']

delete myArray[2]
console.log(myArray)
// => myArray = ['a','b',undefined,'d']

좋은 예시

var myArray =['a','b','c','d']

const removedFromMyArray = myArray.splice(2,1) 
console.log(removedFromMyArray)
// => ['a','b','d']

동일한 모듈에서 import하는건 한 곳에 병합하세요

특별한 경우를 제외하고는 가독성을 위해 동일한 모듈에서 import하는건 한 곳에 병합하세요.

나쁜 예시

import { B1 } from 'b'
import { B2 } from 'b'

좋은 예시

import { B1,B2 } from 'b'

결론

Javascript와 Typescript에는 제가 다룬것 외에도 많은 '악취나는 코드'가 많습니다.
만약 Typescript내에 어떤 또다른 '악취나는 코드'가 있는지 알고싶으시면 여기를 클릭하여 확인해보세요!

profile
백엔드개발자🖥

0개의 댓글