하마
6k
2017-09-26 15:39:56 작성 2017-09-27 09:35:27 수정됨
23
6068

[번역] 자바스크립트에서 for 루프를 다시 생각해보자


저는 자바스크립트로 잃어버린 웹어플리케이션의 재미를 타입스크립트와 angular4 로 되찾고 있는 중 인데요. "자바스크립트에 대한 애정을 언어의 90%를 쓰레기통에 버리면서 다시 발견했던 과정" 의 저자는 아직 끈을 잡으려 노력하는 모습이 재밌습니다. 아래 내용은 저 글을 번역한 글을 보고, 번역이 안된 중요 부분 하나를 추가 번역 한 것임을 알려드립니다.

원문링크

번역글링크 



[번역] 자바스크립트에서 for 루프를 다시 생각해보자 

JavaScript 의 for  루프는 나름 그 역할을 잘 해주었지만, 이제는 쓸모가 없어졌으며 새로운 함수형 프로그래밍 기술에 의해 은퇴 해야 할 때로 보입니다.걱정은 하지 마세요 굳이 함수형 프로그래밍 마스터가 될 필요는 없습니다. 그저 현재의 프로젝트에서 바로 시작 해 볼 수 있는 간단한 (하지만 쿨한) 녀석입니다.

JavaScript for loop의 문제점은 무엇일까요?

for 루프는 상태 변이와 부수효과을 조장합니다. 그 결과  각종 버그와 예측할 수없는 코드의 잠재적인 원인이 되곤 합니다. 우리는 모두 전역 상태가 나쁘다는 말을 들었습니다. (지역상태도 전역상태와 같이 악을 공유하고 있지만, 규모가 작기 때문에 큰 문제가 되진 않았습니다.) 하지만 우리는 실제로 문제를 해결하지 못했으며 단지 그것을 최소화 하는데 주력 하였지요.

가변적인 상태에서 - 알 수 없는 특정 시점에 - 변수가 알려지지 않은 이유로 - "변경" 되어, 그  값이 변경된 이유를 디버깅하고 검색하는 데 몇 시간을 소비하게됩니다. 뭐 머리 좀 쥐어 뜯으면 되겠지요. 하지만 머지않아..머리카락이 그리워질 거에요.

이제 그 부수효과에 대해 재빠르게  이야기해 보죠. 이 단어가 별로 와닿지 않는다면 그냥 끔찍한 부작용으로 생각하는게 좋을거 같습니다. 혹시 당신의 몸에 부작용이 생기길 바랍니까? 아니죠?  마찬가지로 프로그램에 부작용이 있기를 원하십니까? 역시 아니겠죠?  네 저는 제 프로그램에 부작용이 생기는 것을 원하지 않습니다! 따라서 이 문제에 대해서 좀 적극적으로 행동 했습니다.

그럼 부수효과가 무엇일까요?

함수가 함수 범위 밖의 어떤 것을 수정할 때 부수효과가 있는 것으로 간주합니다. 멤버 변수의 값을 변경하거나, 키보드 입력을 읽거나, API 호출을하거나, 디스크에 데이터를 쓰고, 콘솔에 로깅하는 등의 작업등이 그것 들이죠.

부수효과은 강력하고 효율적인것 처럼 보이기도 하지만  그 만큼 큰 책임이 따릅니다.  

자기도 모르게 떠 안을 수 있는 큰 책임을 줄이기 위한 방법은 가능한 경우 부수효과를 제거하거나 캡슐화하여 관리해야 합니다. 부수효과가 있는 기능은 테스트하기가 어렵고 추론하기도 더 어렵습니다. 가능한 한 제거 하십시요. 그렇다면 우리는 부작용에 대해 걱정하지 않게 될  것입니다.

좋습니다.  
썰은 그만 풀고 개발자 답게 코드로 봅시다. 아마 수천 번 이상 본 전형적인 for 루프를 살펴 보겠습니다.

const cats = [
  { name: 'Mojo',    months: 84 },
  { name: 'Mao-Mao', months: 34 },
  { name: 'Waffles', months: 4 },
  { name: 'Pickles', months: 6 }
]
var kittens = []
// typical poorly written `for loop`
for (var i = 0; i < cats.length; i++) {
  if (cats[i].months < 7) {
    kittens.push(cats[i].name)
  }
}
console.log(kittens)

앞으로 이 코드를 단계별로 리팩터링하여 좀 더 아름답게 변형하는 것이 얼마나 쉬운지 확인 시켜 드릴 것입니다.

1. 첫 번째로 변경하고자 하는 것은 if 문을 자체 함수로 추출하는 것입니다.

const isKitten = cat => cat.months < 7
var kittens = []
for (var i = 0; i < cats.length; i++) {
  if (isKitten(cats[i])) {
    kittens.push(cats[i].name)
  }
}

일반적으로 if 문을 추출하는 것은 가독성에 매우 좋습니다. 즉 마법수 같은 느낌의 "7 개월 미만" 이라는  표현보다는 "새끼 고양이" 로 필터링을 변경하는 것은 생각보다 매우 중요한 일이죠. 이제 코드를 읽을 때 의도가 명확 해집니다. 왜 태어난지 7개월 미만의 고양이를 구하는거야? 우리의 의도는 새끼 고양이를 찾는 것입니다, 그래서 코드가 그렇게 말하게 만드십시오! 읽는 사람도 매우 편해 할 것입니다.

또 다른 이점은 isKitten이 이제 재사용이 가능하다는 것입니다.

코드를 재사용 가능하게 만드는 것이 항상 우리의 목표 중 하나가되어야합니다.

2. 다음 변경은 cat 형식의 개체에서 이름으로 변환하는 부분을 추출하는 것입니다. 이 변환의 목적은 나중에 자세히 이해할 수있게 될 것이므로 지금 당장은  그냥 믿어 봅시다.

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
var kittens = []
for (var i = 0; i < cats.length; i++) {
  if (isKitten(cats[i])) {
    kittens.push(getName(cats[i]))
  }
}

필자는 filter 와 map의 메커니즘을 설명하기 위해 몇 단락을 작성하는 것을 고려했지만 그것들을 설명하지 않고서도 그냥 이 코드를 읽고 이해할 수 있다는 것을 보여 주기 위해 건너 뛸 것입니다. filter 문은 조건문과 매칭되고, map 은 변환과 매칭된다는것을 알 수 있을 것 입니다. 반복해서 보세요. 
많은 경우 이해 안되는것도 반복해서 보면 이해가 되기 마련입니다. 

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
const kittens = cats.filter(isKitten).map(getName)

우리는 for 문과 kittens.push (...)를 제거했으며 더 이상 var이 사용되지 않게 됩니다.
즉 상태의 변경이 없어 졌습니다. const 세상이 되었습니다.

const (var와 let보다)를 사용하는 코드는 섹시합니다.

3. 필자가 제안 할 마지막 리팩토링은 필터링과  매핑을 자체 함수로 추출하는 것입니다. 모두 함께 묶어 보시죠. (역주: for 문에서 i 변수를 쫒아가며 남이 짠 혹은 자신이 예전에 짠 코드를 이해할 필요가 없이 자연스럽게 소설 읽듯이 변화 되었습니다.)

const isKitten = cat => cat.months < 7
const getName = cat => cat.name
const getKittenNames = cats =>
  cats.filter(isKitten)
      .map(getName)
const cats = [
  { name: 'Mojo',    months: 84 },
  { name: 'Mao-Mao', months: 34 },
  { name: 'Waffles', months: 4 },
  { name: 'Pickles', months: 6 }
]
const kittens = getKittenNames(cats)
console.log(kittens) 

추가 시리즈) 

- if 문을 다시 생각해보자. 
- switch 문에게 마지막 인사를 
- 악의 축이던 this 없는 자바스크립트 프로그래밍 

p.s
다른 사람의 경험 및 지식이 항상 옳지는 않습니다. 유튜브나 SNS 상에서 유명하다고 하는 사람들이 말하는 것 또한 마찬가지입니다. 대부분 case by case 인 경우가 많으며, 읽고 느끼고 비판하며 자기것으로 만들어야 겠지요. 다만 정보 공유에 대한 존중과 감사는 있어야 할 거 같습니다.

10
  • 댓글 23

  • 초코쪼꼬
    6k
    2017-09-26 15:54:41

    요즘 관심을 두고 자주 사용하는 방법을 글로 보니 재밌네요.

    잘 읽었습니다.

  • 구구구구우
    1k
    2017-09-26 16:13:53

    좋은 글 감사합니다. 

    개발 시작을 java 8로 처음 사용한 저에게는 참 적극적으로 사용을 많이 한 표현(java 에서는 Stream)이긴 한데, 자바의 경우 일반적인 for loop과 비교하여 인스턴스 생성이 늘어나기 떄문에 속도가 느린 단점이 있는데, 자바스크립트에서는 어떤가여

    그리고 염치없지만 저 this에 대해서도 번역을 부탁드리면 안될까요?.(영어를 못해서 ㅠㅠ)

    자바스크립트를 잘몰라서 this가 왜 악에 축인지 궁금하네요 

  • 앙앙이
    4k
    2017-09-26 16:16:03

      For문이 악의축인듯 말하면서

    내부적으로 루프문 도는 filter 사용하고선

    루프  없앴다고 뿌듯하다 말하는 이에 대해서

    무슨 말을 해 줘야 할까요.

  • 니플
    2017-09-26 16:18:42

    함수형을 좋아하나봅니다.ㅎㅎ

  • 초코쪼꼬
    6k
    2017-09-26 16:21:19

    @구구구구우


    call과 apply쪽을 사용해보시면.. this가 왜 악의 축인지 이해가 되실거에요.

  • 구구구구우
    1k
    2017-09-26 16:32:24

    앙앙이 

    저기서 말하는 for문이 악의축의 근거는 cats라는 배열(제가 자바스크립트를 몰라서 어떠한 명칭등에 문제가 있을수 있어여, 솔직히 cats가 배열인지 아닌지 모르겠습니다.)로부터 미리 정의된 비교문을 통해 걸러 내어 name을 추출하는 과정에서 cats 배열에 데이터가 변할수 있음을 항상 내포하기 때문입니다.

    즉 cats[2] = {name :  "aaa" , months: 84}; 이러한 코드가 for문에 있다면  cats의 내용은 변하겠죠.  하지만 저기서 제시한 방법은 cats를 변화시킬 코드를 작성할거라는 가능성을 내포하지 않는다는 의미입니다.


  • 구구구구우
    1k
    2017-09-26 16:37:28

    수송대원 

    자바스크립트를 해본적도 없고, 자바스크립트를 공부한다고 해서, 그게 왜 악의 축인지 제가 감지 해낼수 있을까 싶은데.... 그냥 속 시원히 가르쳐 주시면 안돼나요??

    아니면 C언어 처음공부할때 처럼 책에 goto는 악의 축입니다 라고 소개하는것 처럼 자바스크립트에서 this가 악명이 높아서, 어떤 책을 읽던간에 문제점을 소개해주나요??

  • 니플
    2017-09-26 16:41:03

    구구구구우님

    제가 생각할때는

    성능 이슈같습니다.


    this를 찾는 성능이 너무 큰것같네요

  • 구구구구우
    1k
    2017-09-26 16:50:45

    신입 

    그런가요 답변 감사합니다.

  • 마사키군
    1k
    2017-09-26 17:02:40 작성 2017-09-26 17:14:59 수정됨

    @구구구구우 )

    자세한건 찾아보시면 되겠지만-_-
    간단하게 말씀드리면 this 가 C++이나 Java 에서 쓰이는 것과 다르게(그리고 우리가 의도한 것과 다르게) 동작하기 때문입니다.

    저도 자세하게 아는게 아니라서 명확하게 말씀드리진 못하지만, 자바에서의 this는 생성된 인스턴스 내부에서 자기 자신의 인스턴스를 가리키는 지시자이지만,
    자바스크립트에서는 객체와는 관계 없이 현재 코드가 실행되는 스코프의 함수를 가리킬 겁니다. 그래서 보통 상위의 함수 스코프에서 this를 재정의해서 쓰죠.

    자세한건 다른 고수분들의 댓글을 기다려봅니다 =3==3
  • isNotEmpty
    2017-09-26 17:09:05

    그놈의 익스플로러 11이 발목을 잡네요.

    실제 업무에서 개발하고 싶은데, 할 수가 없네... ㅠ


  • 구구구구우
    1k
    2017-09-26 17:13:11

    좀 찾아 보니까 완벽히 이해한건 아닌데 Javascript에서 this의 모호함? 이 문제가 되는거 같네요. 

    코드를 봤을 때 this가 누구인지에 대해서 모호함이 문제인거 같습니다. 특히 콜백의 경우 호출하는 오브젝트의 메소드에서 호출이 이뤄진 오브젝트가 this가 아니라 root인 Window인 예를 들고 있는거 같은데 이러한 문제에 대해 해결책이 있지만, 이것이 개발자로 하여금 실수할수 있는 여지를 줄수 있는 부분에 대해서 문제를 삼는거 같네요

  • 초코쪼꼬
    6k
    2017-09-26 17:15:57

    @구구구구우


    제가 아는 선에서 간단한 예제를 설명드릴게요.

    var func = function(){
      console.log(this);
      return function(){
       console.log(this); 
      }
    }


    위의 예제에서 첫번째 오는 this는 func 의 object를 가르키는 this입니다. 다만 클로져로 리턴받는 function(){console.log(this)} 의 this의 경우 func의 함수안에 있음에도 불구하고 this가 window 를 가르키는 증상이 있습니다.


    이에 오류를 바로 잡기위해선.. -_-...


    var func = function(){
      console.log(this);
      var that = this;
      return function(){
       console.log(this); 
       console.log(that);
      }
    }

    이와 같이 수정을할경우 클로저로 리턴받는
    function(){
      console.log(this);   // window object
      console.log(that);  // func object
    }

    로 사용할 수 있습니다.

    같은 this이지만.. 이런 케이스가 다른곳에도 많이 있어서 악명이 높다고 합니다.


    부족한 설명이 었지만.. 답변이 되었으면 좋겠네요.


  • 구구구구우
    1k
    2017-09-26 17:22:35
  • 하마
    6k
    2017-09-26 17:33:09 작성 2017-09-26 17:45:46 수정됨

    앙앙이 //  말해주지 마세요 ;;  결국 모두 0,1 입니다. 문제는 "추상" 입니다.

    구구구구우//  맞습니다. '모호성' 에 관한 이야기입니다.. :-) 



  • 박종복
    677
    2017-09-26 18:04:18

    이런 this~


    const obj = { func1: function(){ return this; } };

    const func1 = obj.func1;

    console.log(obj.func1() !== func1());

  • silqwer
    91
    2017-09-27 08:41:58

    잘 보았습니다 ^^

  • 앙앙이
    4k
    2017-09-27 11:03:44 작성 2017-09-27 22:53:29 수정됨

      내용 빼고 아래 리팩토리 최종 결과 코드는 분명히 클린 코드로 저 개인적으로 꼭 닮고 싶어 지향하고 있다는것을 밝히고 싶네요.


    const isKitten = cat => cat.months < 7
    const getName = cat => cat.name
    const kittens = cats.filter(isKitten).map(getName)


  • Courage
    2k
    2017-09-28 09:22:47

    설명을 들으면서 보니 가독성은 정말 좋아지네요..

    요즘 sm하면서 가독성 똥망인 소스코드만 보다가 이 글을 접하니 눈이 정화되는 기분입니다.

    가독성 똥망인 소스코드는 유지보수 비용을 높인다는걸 왜 윗선은 모를까요...

    그 윗선도 개발자 출신이면서 말이죠...

  • 하아하아
    1k
    2017-09-28 09:46:05

    별거 있나요. ref 인지 val 인지는 실행해보고 체크하는 수밖에 없지요.

    익숙해지면 구분해서 쓰면됨.

  • 0x0a
    164
    2017-10-01 07:06:13
    잘봤습니다~ JS가 가진 함수형 언어의 개략적 특징을 잘 설명하고 있는것 같아요!

     

  • 실력과연봉은비례하는가
    515
    2017-10-01 15:45:52

    좋은글 잘 읽었습니다~  

  • [개발자]
    50
    2017-10-11 08:23:53

    수송대원 '-'ㆀ 

    님 댓글 개인적으로 저도 이해하는 데 도움이 많이 되었습니다 !

    추상적으로만 알고있던 부분을 설명으로 보니까 더 확 와닿네요 ㅎㅎ

    감사합니다.

  • 로그인을 하시면 댓글을 등록할 수 있습니다.