스트림은 왜 사용해야 하는가.
오늘 부트캠프에서 스트림에 대해 배웠다. 람다와 스트림은 정말 아예 문외한이던 영역이기 때문에, 일단은 기본적인 내용을 받아들이는데 가장 힘을 썼던 것 같다. 이 스킬들을 사용하고 체득하는 데는 직접 문제 풀이나, 프로그래밍에 사용해보면서 익숙해지는 방법 밖에 없다. 결국 나의 노력에 스트림을 얼마나 잘 사용하는지가 달려있다.
그런데 스트림은 왜 사용해야 할까? 사실 처음 스트림을 접했을 때는 이걸 도대체 왜 쓰나 싶었다. 지금 알아가는 것도 양이 너무나 방대한데, 새로운 메서드들을 배우고 익혀야 한다는 것이 두렵기도 했고, 스트림을 사용하기 위해선 필연적으로 람다식도 익혀야 하는데 람다식은 학교에서 배울 때 무슨 말인지 도저히 이해를 못했던 부분이라 두려움이 배가 되었다.
그럼에도 오늘 람다식과 스트림을 배우면서 든 생각은, '스트림의 사용법을 반드시 익혀야 겠다' 였다. 이유는 간단하다. 스트림은 '클린 코드와 너무나도 닮아있다.' 스트림을 사용하면, 내부적인 동작은 내가 알 바 아니지만, 원하는 결과를 알려준다. 내가 귀찮게 여러 코드를 칠 필요 없이, 내가 원하는 결과를 알려준다. 그것도 '명시적인 이름'으로 말이다.
수업 내용 중에 이런 말이 있었다.
아직 스트림에 대한 구체적인 내용을 배우지는 않았고, “어떻게”에 해당하는 각 함수의 내부 동작을 전혀 알 수 없지만 한 눈에도 어떤 흐름으로 어떤 일들이 일어나고 있는 지 파악하는 일이 어렵지 않습니다. 이처럼 스트림을 사용하면 보다 직관적이고 간결한 코드 작성이 용이합니다.
이 말을 보자마자 '이게 클린 코드의 핵심 아닌가?' 라는 생각이 들었다. 내가 작성한 코드가 내부적으로 어떤 일을 하는지는, 코드를 깊이 들여다보지 않으면 당연히 알 수 없다. 물론 코드를 정말 너무너무 잘 짜고, 기능과 책임을 완벽하게 분배하면 코드의 내용도 쉽게 볼 수 있겠지만, 대부분 그렇게까지 완벽하게 개발을 하지는 못한다. 그럼에도 우리가 좋은 코드라고 칭하는 것들은 '명시적인 이름을 통해 기능이 무슨 일을 하는지 알 수 있다.'
오늘 스트림이 내장하고 있는 여러 함수들을 다시 보니, 이름만으로도 그 기능을 유추 가능한 것들이 너무 많았다. filter()라던지, forEach()라던지 뭐 여러 메서드들이 그 이름만으로도 어느 정도 기능을 유추할 수 있었다. 그렇다면, 이 기능들을 사용한 코드 역시 당연히 코드를 슥 보면 글처럼 읽히는 아름다운 코드가 되지 않을까.
예를 들어 보자, 리스트에 담긴 숫자들 중에 짝수만 담긴 숫자들을 만들기 위해 우리는 이런 방법을 선택할 수 있다.
public int makeEvenNumbersSum(List<Integer> numbers) {
int sum = 0;
for(int number : numbers) {
if(number % 2 == 0) {
sum += number;
}
}
return sum;
}
int evenNumbersSum = makeEvenNumbersSum(list);
함수와 메서드의 이름은 명시적이지만, 메서드도 따로 만들어야하고 그 메서드를 사용할 객체도 만들어야한다. 짧은 기능을 구현했기에 망정이지, 해당 기능이 여러 조건을 지니고 있고 복잡한 기능을 한다고 생각하면 메서드 바디를 작성하는 과정 역시 지나치게 귀찮을 것이다. 그럼 스트림으로 evenNumbersSum을 구한다면 어떻게 작성할 수 있을까.
int evenNumbersSum = list.stream()
.mapToInt(number -> number)
.filter(number -> number % 2 ==0)
.sum();
가독성을 높이기 위해 기능마다 공백을 넣었음에도 단 4줄로 짝수들의 합을 구했다. 그러면서도 저 네 줄에 각 메서드 내에서 무슨 일이 일어나는지가 명확하게 드러난다. 물론 람다식을 이해하지 못 한다면 위의 코드는 이해할 수가 없다. 그러나 최소한의 람다식에 대한 공부만으로도 스트림에는 기본적으로 사용할 수 있다.
아이러니하게도 나 역시 람다식을 공부하기를 꺼려했고, 스트림을 공부하기를 꺼려했다. 왜 저런 식으로 코드를 작성해야하는지, 뭐가 좋아서 저렇게 작성하는지를 이해하지 못했다. 어쩌면 게으름이 불러온 재앙이었을 것이다. 막상 공부해보니 람다식은 딱히 어려운 문법이 아니었고, 스트림은 '내 기준과 원칙에 정확하게 부합하는 코드 작성법' 이었다.
모든 생각이 거의 같은 결과로 귀결되는 것 같은데, 아무튼 우리는 '읽기 쉬운 코드를 작성해야 한다.' 다른 부분에서는 생각이 계속됨에 따라 어느 정도씩 생각이 바뀔 수도 있을 것 같지만, 저 생각만큼은 아마 절대 바뀌지 않을 것이다. 저 생각은 '현재의 내가 세운 가장 핵심 원칙이며 동시에 좋은 개발의 변치 않을 핵심'이다. 스트림은 그러한 핵심 기준과 꼭 알맞다. 그래서 우리는 스트림을 공부하고 사용해야한다.