함수 선언문으로의 회귀

Dev.Jo·2023년 3월 26일
post-thumbnail

1. 시작하며

트위터에서 자바스크립트 함수 작성 방법에 관한 흥미로운 트윗을 보았습니다.

여러분은 어떤 방법을 선호하나요? 저는 주로 const f = () => {} 방법으로 함수를 작성해왔습니다. 그런데 꽤나 많은 비율의 개발자들이 function f() {} 을 사용한다는 사실과 우리가 잘 아는 오픈소스 개발자들도 function을 선호한다는 사실이 흥미로웠습니다.

사실 Tab vs Space 논쟁처럼 정답이 없는 논쟁입니다. 그런데도 function을 사용하는 이유에 대해서 궁금해졌고, 조사하면서 몇몇 깨달음을 얻었습니다. 그 결과를 공유하고자 합니다.

1.1 function 키워드의 다양한 쓰임새

먼저, 자바스크립트 function 키워드를 어떤 경우 사용하는지 알아보겠습니다. ES6 이전 function 키워드는 다양한 쓰임새로 사용되었습니다.

// 1. 생성자 함수
function Person(name){
	this.name = name;
}

// 2. 객체 메서드
user = {
  sayHi: function() {
    alert("Hello");
  }
};

// 3. inline 함수
arr.map(function(x){ return x+1 })

하지만 ES6 문법이 출시되면서 위와 같은 function 키워드는 대부분 대체가능 해졌습니다. (어느 방법이 우월하다거나, 100% 상위 호환이라는 의미가 아닙니다)

// 1. Class
class Person{
	constructor(name){
		this.name = name;
	}
}

// 2. 객체 메서드 축약형
user = {
	sayHi(){
		alert("Hello");
	}
}

// 3. inline 화살표 함수
arr.map(x => x+1);

새로운 문법이 출시되면서 위와 같은 경우 function 키워드를 사용해야할 이유는 없어보입니다.

그렇다면 일반 함수를 작성할때는 어떤가요? 반드시 화살표 함수를 사용해야할까요?

// 함수 선언
function add(a, b) {
  return a + b;
}

// 화살표 함수 표현식
const add = (a, b) => a + b;

1.2 자바스크립트 일반 함수 작성 방법

자바스크립트 함수는 일급 객체 이기 때문에 다양한 방법으로 함수를 작성할 수 있습니다.

// 1. 함수 선언식 (function declaration)
function multiply(x, y){
	return x * y;
}

// 2. 익명 함수 표현식 (anonymous function expression)
const multiply = function (x, y) {
  return x * y;
};

// 3. 기명 함수 표현식 (named function expression)
const multiply = function multiplyTwoNumber(x, y) {
  return x * y;
};

// 4. 화살표 함수 표현식
const multiply = (x, y) => x * y;

// 5. Function 생성자
const multiply = new Function('x','y','return x * y')
  • Function 생성자 , 익명 함수 표현식로 작성된 코드를 살면서 본적이 없습니다.
  • 기명 함수 표현식airbnb 스타일 가이드에서 추천하는 스타일입니다. (저는 장황하다고 생각합니다)

대부분 함수 선언문 또는 화살표 함수 표현식 으로 작성할것입니다.

이미 함수 선언문과 함수 표현식의 차이 에 대해서는 정리가 잘 된 블로그들이 많기 때문에 이 글에서는 생략하겠습니다. 저는 조금은 다른 관점에서 차이점을 바라보겠습니다.

2. 함수 선언문을 사용해야하는 이유

2.1 가독성

2.1.1 함수 선언문은 스캔하기 쉽습니다.

프로그래머는 코드를 읽을 때 스캔을 먼저 합니다. - 프로그래머의 뇌

다른 사람이 작성한 코드를 읽는 것은 괴로운 일입니다. 수백~수천줄의 코드를 마주치면 읽기도 전에 두통을 일으킵니다.

우리는 다른 사람의 코드를 읽을 때 위에서 아래로 변수 하나하나, 함수 하나하나를 꼼꼼히 읽지 않습니다. 우선적으로 전체적인 구조를 파악하기 위해 코드를 스캔 합니다.

함수 선언문은 시각적으로 변수와 함수를 쉽게 구분하게 해줍니다.

const veryLongLongName = new Map()
// 수십줄~수백줄의 코드가 있다고 상상해봅시다
function veryLongLongName2(){
	return new Map();
}

const로만 이루어진 코드는 코드가 복잡해질 수록 스캔하기 어렵습니다.

const veryLongLongName = () => new Map();
// 수십줄~수백줄의 코드가 있다고 상상해봅시다
const veryLongLongName2 = new Map();

2.1.2 함수 선언문의 형태는 단순합니다.

함수 선언문의 형태는 단순합니다. function 키워드, 함수의 이름, 함수에 전달할 인수, 함수 본문으로 이루어집니다. return값이 존재한다면 return 키워드로 명시적으로 작성해야합니다.

function 함수이름(인수){
	본문
	return 리턴값
}

그에 반해 화살표 함수 표현식 은 암시적 반환 , 코드 포매팅에 따라 다양한 형태를 가집니다.


const foo = (a,b) => {
	return a+b;
}

// 암시적 반환은 return을 생략할 수 있습니다.
const foo = (a,b) => a+b;

// 파라미터가 하나라면 괄호를 표기할 수도, 생략할 수도 있습니다.
const foo = a => a;
const foo = (a) => a;

// 반환값이 객체라면 ( )로 감싸줘야합니다.
const foo = (a,b) => ({a,b});

만약 커링과 같이 함수를 반환하는 함수라면 복잡도는 더욱 증가합니다.
(커링의 경우 함수형 프로그래밍 기법에 맞는 화살표 함수가 훨씬 가독성이 좋다고 생각합니다.)

2.2 함수 호이스팅은 의도되었습니다.

자바스크립트 공부를 시작할 때 var, let, const의 차이 에 대해 필수적으로 공부합니다. let, const는 TDZ로 인해 선언 전에 사용을 금지되기때문에 안전 하고 var는 선언 전에 사용할 수 있기 때문에 위험하다고 배웁니다.

변수 호이스팅은 분명 나쁩니다. 그런데 함수 호이스팅은 나쁜건가요?

자바스크립트를 만든 Brendan Eich는 자바스크립트 호이스팅에 대해서 다음과 같이 얘기했습니다.

정리하면 다음과 같습니다. (정확한 트윗은 여기서 확인하세요)

  • 함수 호이스팅은 Top-Down 프로그래밍을 가능하게 하고 선언전 호출을 가능하게 해준다.
  • 변수 호이스팅은 의도하지 않았던 결과이다. var 대신 ES6에서 도입된 let을 쓰는것이 도움이 될것이다

자바스크립트 함수 호이스팅은 의도된 언어 디자인입니다.

Top Down 방식 코드

다음과 같이 리액트 컴포넌트에서 사이드 이펙트틀 일으키기 위해 useEffect 훅을 사용해야한다고 생각해봅시다. 요구사항이 꽤나 복잡해져 함수가 커지기 시작합니다.(함수를 이펙트 훅 안으로 옮길 수 밖에 없다고 가정해봅시다)

화살표 함수 표현식Down-Top 방식으로만 코드를 작성하고 읽을 수 밖에 없습니다. 메인 로직에 대해 한번에 파악하기 쉽지 않습니다.

  useEffect(() => {
	  const helperFunction1 = () => {
			// ...
			// 수십줄의 코드라고 상상해봅시다
	  }

		const helperFunction2 = () => {
			// ...
			// 수십줄의 코드라고 상상해봅시다
	  }
	
	  const mainFunction = async () => {
	    // ....
			helperFunction1();
			helperFunction2();
	  }
	
		
		// 화살표 함수 표현식을 사용하면 코드를 Down Top 방식으로만 작성하고 읽을 수 밖에 없습니다.
		// 해당 useEffect이 어떤 역할을 하는지 맨 아래를 찾아가면서 숨은그림찾기하듯이 찾아야만합니다.
		mainFunction()
}, []);

그에 반해 함수 선언문Top Down으로 함수를 읽고 작성하게 해줍니다. 불필요한 정보는 아래로, 중요한 정보는 위로 보내어 읽는 이로 하여금 코드를 두괄식 으로 읽게 합니다.

useEffect(() => {
  mainFunction()
  // 우리는 Top Down 방식으로 코드를 읽자마자 메인 동작을 파악할 수 있습니다.
  // 부가적인 helperFunction에 대한 파악은 필요할 때 나중에 하면 됩니다.

  async function mainFunction(){
    // ....
    helperFunction1();
    helperFunction2();
  }

  function helperFunction1(){
    // ...
    // 수십줄의 코드...
  }

  function helperFunction2(){
    // ...
    // 수십줄의 코드...
  }
}, []);

Top Down 방식이 항상 정답이고 Down Top 방식은 틀렸어! 라고 말하고 싶은건 아닙니다. 함수 호이스팅이 자바스크립트 설계 의도이기 때문에 반드시 언어의 의도에 맞게 코드를 작성해야한다고 주장하는것도 아닙니다.

다만

화살표 함수 표현식만을 사용하면 우리는 Down Top 사고방식만으로만 코드를 작성할 수 밖에 없습니다.

(+ eslint 설정등으로 화살표 함수 표현식도 Top Down으로 작성할 수 있습니다. 하지만, 플랫폼의 도움없이 동작하는 Vinila 자바스크립트에는 불가능합니다.)

이에 반해 함수 선언문은 순서에 상관없이 자유로운 사고방식으로 코드를 작성하는 것이 가능해집니다. (코드 일관성과는 다른 이야기일것입니다)

3. 결론

함수 선언문을 사용해야하는 이유를 가독성과 클린코드 관점에서 소개드렸습니다.

ES6가 나오기전 function 키워드는 다양한 역할을 했습니다. ES6 출시하면서 Class 문법, 메서드 축약형, 화살표 함수가 등장하면서 functoin 키워드는 어깨의 부담을 덜어내기 시작했습니다.

이제 function을 function 답게 사용해야할 때입니다.

그러나 누군가는 function 키워드는 생성자 함수로도 사용될 수 있고, this 바인딩 문제등으로 혼란 을 줄 수 있기때문에 의도적으로 제한해야한다고 주장하기도 합니다.

개발염려증

지금은 종영되었지만 위기탈출 넘버원이라는 TV 프로그램이 있었습니다.

"수박을 먹으면 죽는다거나", "치즈와 피클을 함께 먹으면 죽는다거나"하는 억지스러운 설정으로 모든 것을 걱정하게 만드는 건강염려증 을 불러일으킨다는 비판을 받았었습니다.

제게는 function 키워드에 대한 비판도 개발염려증 처럼 보입니다.

class가 등장하면서 생성자 함수를 사용하는 개발자는 많지 않을것입니다. (불안하다면 eslint의 도움을 받을 수도 있습니다). 만약 생성자 함수를 사용할 수 밖에 없는 환경이라면 화살표 함수 표현식을 사용하면 됩니다. 이것은 환경, 상황, 팀에 따라 올바른 규칙을 정해야하는 것입니다.

어떤 개발자는 가독성과 Top Down 방식의 코드를 가치있게 생각할 수 있습니다. 반대로 문제가 일어날만한 코드를 처음부터 원천봉쇄하고 Down Top 방식의 코드를 가치있게 생각하는 개발자도 있을 수 있습니다. 우열은 없습니다. 선호도의 문제입니다.

결국 팀의 컨벤션에 따라, 프로젝트의 성격에 따라, 상황에 따라 맞는 코드를 작성하는 것이 정답일 것입니다.

끝으로 자료를 조사하면서 봤던 마음에 드는 글귀를 소개하면서 글을 마치겠습니다.

Expand your code vocabulary, don’t deliberately limit it! (코드 어휘를 확장하고 의도적으로 제한하지 마세요!)

profile
소프트웨어 엔지니어, 프론트엔드 개발자

4개의 댓글

comment-user-thumbnail
2023년 4월 28일

좋은 글 감사합니다. 저는 프로토타입 객체 하나 더 생길거 같은 생각에 화살표 함수를 사용하긴 하지만
역시 코드는 읽기 좋은게 가장 중요하다는 생각이 드네요. (확실히 function 키워드로 표현한 함수 식이 읽기 편하니깐요!)

Top Down으로 함수를 읽고 작성하게 된다에 대해서는.... 코드를 읽을 때 자연스럽게 위-아래로 읽게 되기 때문에 함숫 선언이 밑에 있고 함수 실행이 위에 있으면 조금은? 혼란스러울 것 같다는 생각도 드네요ㅋㅋㅋ... 물론 ide나 github의 확장기능을 잘 사용하면 해결할 수 있는 부분이지만요.

1개의 답글
comment-user-thumbnail
2023년 7월 15일

개발염려증 이라는 말이 너무 웃기고..공감가네요 ㅋㅋㅋ
좋은 글 감사합니다~!

1개의 답글