티스토리 뷰

JAVA(프로그래밍)

자바스크립트에서 for 루프 고찰

알 수 없는 사용자 2018. 1. 1. 22:19

 자바스크립트에서 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)

 

해당글은

https://hackernoon.com/how-i-rediscovered-my-love-for-javascript-after-throwing-90-of-it-in-the-trash-f1baed075d1b

글을 참고하여 번역한 글입니다.

 


 

댓글