Language/TypeScript

선언형 프로그래밍을 알아보자

SambaLim 2021. 1. 10. 19:51

코드리뷰를 받던 도중, 명령형인가 선언형인가를 생각하고 가능하면 코드를 선언형으로 생각하고 작성하는 편이 좋다는 코멘트를 받아 이를 정리해보려고 합니다.

코드리뷰

file_array: Array<FileType> 을 받아 file_array 에 값이 들어가 있는지 확인하는 코드를 아래와 같이 작성하였었습니다.

const validateRequiredFile = (file_array?: Array<FileType>) => {
  const hasFile =!!file_array ? file_array.length !== 0 : false;
  return hasFile;
};

이를 해석해보자면, 'file_arrayundefined 라면 false 를 출력하고 file_array 의 크기가 0 일때는 false 아니면 true 를 리턴한다.'가 됩니다.

뭐가 문제지?

사실 해석도 결과도 원하던대로 잘 작성이 되었습니다. 하지만 이 코드는 선언형이 아닌 명령형으로 프로그래밍이 되어있어 이를 수정할 필요가 있어보입니다.

선언형, 명령형 프로그래밍을 이해하기 앞서 저의 소스코드가 무엇이 문제인지 먼저 알아봅시다.

제가 작성한 코드를 다른 사람에게 설명을 해준다고 생각을 해봅시다. 예시를 두 가지 들어보겠습니다.

  1. file_array 의 배열 크기가 0보다 크면 true 를 아니면 false 를 리턴할거야. 근데 file_arrayundefined 일수도 있어.
  2. file_arrayundefined 라면 false 를 출력하고 아니면 file_array 의 크기가 0 일때는 false 아니면 true 를 리턴할거야.

앞서 저의 소스코드와 같은 2번은 무엇을 하는지에 집중하는게 아닌 어떻게 결과에 도달하는지에 집중이 되어있습니다.

약간 과장된 예시지만 우리가 식당에 갔을 때 "식사할게요. 4명이요." 하고 자리를 안내받지 "혹시 빈지라기 없다면 저희는 나갈거고 있으면 4자리가 있으면 자리에 가서 식사할거고 아니면 나갈거에요."라고 이야기하지는 않습니다. 우리는 일상생활에서도 어떻게 결과에 도달할건지에 집중하지 않고 무엇을 할지 추상화하여 이야기합니다.

우리는 우리가 원하는 것이 "어떻게" 수행되는지 보다는 "무엇을" 수행하는지 더 관심을 가지고 있습니다.

선언형 프로그래밍

선언형 프로그래밍

선언형 프로그래밍에 대한 많은 정의가 있지만, 이 글에서 이해해보고자 하는 정의는 '프로그램이 어떤 방법으로 해야 하는지를 나타내기보다 무엇과 같은지를 설명하는 경우에 "선언형"이라고 한다.'입니다.

앞서 코드리뷰에서 이야기가 나온 코드를 어떻게 선언형으로 바꿀 수 있는지 생각해보려 합니다.

선언형으로 수정

선언형 프로그래밍을 이야기할때 계속 "무엇"이 강조되고 있는데, 위의 코드에서 "무엇"을 알아봅시다.

const validateRequiredFile = (file_array?: Array<FileType>) => {
  const hasFile =!!file_array ? file_array.length !== 0 : false;
  return hasFile;
};

이 코드는 file_array 의 길이가 0 이상 인지를 확인하고자 합니다. 길이가 0 이 아닌 것에 집중하여 수정해봅시다.

const validateRequiredFile = (file_array?: Array<FileType>) => {
  return file_array.length !== 0;
};

수정한 후에 이 함수가 무엇을 하려는지가 명확히 보입니다. 하지만 이 함수는 오류의 여지가 있습니다. 바로 file_arrayundefined 일 수 있다는 것인데, 이를 보완하기 위해서 file_array 가 항상 Array 일 수 있게 하려합니다.

const validateRequiredFile = (file_array: Array<FileType>) => {
  return file_array.length !== 0;
};

첫 번째 방법으로 file_array 인수의 Optional Chaining을 제거하였습니다. 이렇게 함수를 만들었을 경우 validateRequiredFile 를 사용하는 많은 코드에서 인수가 undefined 일 수 있다며 오류를 보여줄 것입니다. 이를 수정하기 위해 함수 내에서 file_arrayundefined 라면 빈배열([])로 수정되도록 만들어봅시다.

const validateRequiredFile = (file_array?: Array<FileType>) => {
  return (file_array ?? []).length !== 0;
};

이로써 처음 validateRequiredFile 함수보다 선언형인 코드를 작성해보았습니다. 물론 더 좋은 방법들도 많을 수 있다고 생각합니다. 조금씩 더 나은 코드를 작성할 수 있을거라 생각합니다.

마무리

기존에 작성했던 코드를 보다 선언형으로 작성하는 과정을 담았습니다.

이전에 내 코드가 나자신 그리고 다른 사람들에게도 잘읽히는 코드가 되기 위해서는 어떻게 해야할까를 고민해본적이 있었습니다. 이에 대한 해답으로 선언형으로 코드를 작성하는 것 이라는 하나의 답변을 얻었다고 생각합니다.리액트, 뷰 등에서 컴포넌트 단위로 작성하는 것, 함수형프로그래밍에서 map 또는 reduce 가 함수를 인자로 받아 어떻게 되는지보다 무엇을 하는지에 집중하는 것 모두 선언형 프로그래밍의 요소들이 녹아져 있다라고 생각이됩니다. 앞으로 코드를 작성하며 내가 어떻게 구현해야하지에만 너무 집중한 코드를 생성하고 있지는 않은지 생각을 해야겠습니다. 🙏

추가적으로 선언형으로 작성하는 코드 즉, "무엇"을 의도하는 코드인지를 보여주는 방법으로 변수명, 함수명과 같이 이름을 잘 지을 수도 있고 함수를 기능단위로 나누어 추상화시켜 코드를 읽기 좋도록 만들수도 있습니다.

참고자료