글을 시작하며 먼저 이야기하고싶은 것은 이번 글이 자바의 Iterator
나 Iteratable
인터페이스에 대해서 동작 원리에 다루지 않는다.
단지 자바가 왜 이러한 용어를 채택하였는지를 내가 배웠던 객체지향을 통해서 알아본다.
객체지향의 캡슐화와 메시지에 대해서 초점을 맞추어 이야기해보도록 하겠다
들어가며
java 나 kotlin 에는 iterator 라는 인터페이스가 존재한다.
iterator 는 특정 컬렉션이나 엔티티의 순서를 나타낼 수 있으며, 순차적 접근을 할 수 있도록 하는 책임을 수행하는 인터페이스이다.
실제 구현된 코드를 봐보자.
이 글을 이해하는데 중요한 것은 아니지만 아래의 코드는 int type 의 iterator, IntIterator
의 구현체 중 하나인 ArrayIntIterator
클래스를 가져온 것이다
private class ArrayIntIterator(private val array: IntArray) : IntIterator() {
private var index = 0
override fun hasNext() = index < array.size
override fun nextInt() = try {
array[index++]
} catch (e: ArrayIndexOutOfBoundsException) {
index -= 1; throw NoSuchElementException(e.message)
}
}
앞서 이야기하였듯이 nextInt()
를 통해서 순차적인 접근 을 구현하고 있다. 즉, 원소에 대해 반복을 수행할 수 있도록 하는 것이다\
위의 내용에 대해서는 구현 코드가 어떻게 되었든 java/kotlin 을 이용해서 개발을 하는 개발자라면 Iterator 에 대해서 잘 알고 있을 것이다.
이러한 Iterator 는 그 구현체 가지수도 정말 다양하다.
하지만.
우리는 반복 이라는 또 다른 용어를 생각할 수 있다. 바로 repeat
이라는 단어이다
반복이라는 뜻은 동일한데 왜 객체 지향의 대표라고 할 수 있는 java 와 kotlin 에서 repeat 이라는 단어대신 iterate 라는 용어를 쓸까?
실제로도 동일한 뜻임에도 불구하고 각 구현체의 수는 확연히 다르다. repeat 은 거의 없다싶이 구현체가 적다
이를 객체 지향의 관점으로 바라보고 내 생각을 떠들어보겠다.
Repeat 과 Iterate 의 뜻
Repeat 과 Iterate 는 단어적으로 무슨 차이가 있을까?
요즘 자주 사용하는 chatGPT 에게 이들의 차이점에 대해서 물어보았다
이 둘의 공통점은 앞서 이야기했듯 무언가를 반복(act of repeating) 한다는 것이다. 하지만 미세한 차이가 있는데,
차이점을 정리하고 개인적인 의견을 조금 첨부하면 다음과 같다
- repeat
- performing a certain action multiple times -> 행위의 무언가의 반복
- 행위 자체에 집중하며 동일한 프로세스의 반복으로
- iterate
- larger algorithm 이나 연산의 일부로 수행되는 반복
- 더 커다란 목적을 가진 larger process 의 목적 달성을 위한 repeatation
- 결과에 집중하며 동일하지 않을 수 있는 프로세스의 반복
이렇게 repeat 과 iterate 의 단어적 차이에 대해서 알아보았다. 이제 다음과 같이 repeat 과 iterate 의 차이에 대해서 정의할 수 있다.
repeat 은 행위 자체에 집중하며 동일한 프로세스의 반복이고 iterate 은 결과에 집중하며 동일하지 않을 수 있는 프로세스의 반복이다.
객체지향 관점으로 해석하기
자, 이제 이 글의 본론인 객체 지향적으로 왜 java 에서는 repeat 이라는 용어 대신 iterate 라는 용어를 채택하였는지 나의 주장을 할 차례이다
내 주장을 이해하기 위해서는 객체지향의 다음과 같은 몇가지 핵심 특징에 대해서 이해해야 한다
- 1, 메세지와 메서드
- 2, 캡슐화
하나씩 가볍게 이야기해보자
1, 메시지와 메서드
중요한 것은 메시지다.
객체지향을 공부하다보면 이러한 이야기를 자주 듣게된다. 그렇다 중요한 것은 메시지다.
클라이언트는 메시지를 전달함으로써 그가 원하는 목적을 달성한다. 그러한 클라이언트의 기대를 충족시켜주기 위해서 객체는 내부적으로 메서드를 호출하게 된다.
다시 말하자면 클라이언트는 객체에게 메세지를 전달하고 메세지를 수신받은 객체가 적절한 메서드를 호출하게 되는 것이다
메서드를 호출하는 방법은 다양하다. static dispatch 를 사용할 수도, 다형성을 이용한 double dynamic dispatch 를 사용할 수도 있다.
하지만 클라이언트의 관점에서는 중요하지 않다. 클라이언트는 단지 메시지를 전달할 뿐이다.
2, 캡슐화
앞서서 중요한 것은 메시지를 전달할 뿐이라고 했다.
클라이언트는 메시지를 전달해서 원하는 목적을 달성한다. 목적 달성을 위해서 내부적으로 무엇이 사용되고 어떤 프로퍼티를 참조하는지는 클라이언트 입장에서 전혀 중요하지 않다. 과장해보자면 전혀 알 바가 아니다
캡슐화가 지켜지지 않은 사례를 현실 세계에서 한 번 보여주겠다.
- 공업 현장에서 기술자 A 와 조수 B 가 있다고 해보자. 아래의 대화를 통해 문제점을 찾아보아라
- 기술자 A: 너도 보이다싶이 큰 대못이 있어. 이제 난 못질을 해야해, 너 옆에 있는 선반 위에 세로 30cm 망치를 나에게 왼손으로 줘. 왼손이 가깝네
- 조수 B: 네, 왼손으로 드리고싶은데 어제 제가 운동해서 알이 베겼어요. 오른손으로 망치 드릴게요. 근데 망치 목이 곧 부숴질것 같아요. 온전한거 드릴게요
이 둘의 대화에서 무엇을 하고싶은지 그 의도가 꽁꽁 숨겨있고, 심지어 기술자 A는 조수 B의 자율성을 무시하며 어떤 손으로 망치를 받을지 까지 결정한다.
전혀 캡슐화가 지켜지지 않았기에 절차적이며 문맥간의 합이 맞지 않는다
캡슐화를 지킨 다음 대화를 봐보자
- 기술자 A: 이제 못질 해야해, 망치좀 줘
- (속으로: 내가 못질을 해야하는 context 에 너가 보고있으니까 30cm 망치를 주겠지?)
- 조수 B: 네, 망치 드릴게요
- (속으로: 어제 운동해서 왼손이 아프네, 오른손으로 드려야겠다. 어? 근데 망치 목이 곧 부숴질것 같네? 다른걸 드려야지)
이렇게 본다면, 기술자와 조수의 대화는 전혀 이상하지 않고 오히려 합이 잘 맞는다는 생각까지 든다.
이것이 캡슐화다.
기술자 A 는 못질을 하는 컨텍스트
내에서 망치좀 줘
라는 메시지를 조수 B 에게 전달하고 조수 B 는 적절한 방법
으로 망치를 건네준다.
좀 더 추상화 수준을 높여서 설명해보자면,
클라이언트는 메시지를 전달하여 원하는 목적을 달성하고, 내부 사정에 대해서는 신경쓰지 않는다
이제 다시 용어의 차이에 대해서 알아보자
왜 java 는 반복에 대해서 repeat 이라는 용어 대신에 iterate 라는 용어를 사용하였는가
에 대한 답을 이제 객체지향적으로 해볼 수 있다
iterate 의 정의를 다시 봐보자
iterate: 결과에 집중하며 동일하지 않을 수 있는 프로세스의 반복
결과에 집중하며
(iterate 을 희망하는 클라이언트의 관점에서 메시지를 전달하면) 동일하지 않을 수 있는
(행위 자체가 캡슐화 될 수 있는) 프로세스의 반복
이라는 결론에 도달할 수 있다
특정 목적을 달성하기 방법 자체는 변할 수 있다. 다형적일 수 있다. 하지만 요청에 대한 결과 는 변하지 않는, 특정 목적을 달성할 것이라는 책임(클라이언트의 기대) 는 변하지 않는다.
내 주장이 맞다면 용어 하나만으로도 java 가 언어의 identity 그리고 객체지향을 얼마나 고려하고 만든 언어인지 엿볼 수 있다.
하지만 repeat 이라는 용어가 자주 사용되는 곳이 있다
나는 잘 모르는 분야이긴 하지만 numpy 나 pandas 와 같이 데이터 처리가 매우 중요한 분야는 repeat 이라는 용어가 자주 보인다.
이는 객체를 지향하는것 보다 데이터의 순수 처리와 반복, handling 즉, 작업 수행에 대해 관심이 있기 때문이다.
또한 우리는 iterate 라는 용어를 많이 사용하는 분야가 있다.
> 나는 어떤 이터레이션에서는 환불 로직을 고도화했고 어떤 이터레이션에서는 알림 시스템을 만들었다.
애자일 방법론에서 작업에 대한 수행 단위를 iteration, 이터레이션이라고 표현한다.
왜 repeatation, 리피테이션이라는 말을 쓰지 않을까?
이에 대한 답도 나는 동일하다. 결국 작업의 최종 목적인 소프트웨어로 가치 전달하는 목적은 하나지만 방법은 여러가지로 나뉠 수 있기 때문이 아닐까 생각한다.
마치며
이러한 생각의 소스는 최근 받았던 한 카카오톡 메시지였다.
어? 아무리 뒤져봐도 class 또는 interface 의 method 로 repeat 을 본 적이 없네? Iteratable 이나 Iterator 는 있는데.. 제 생각은 ... 해요, 당신의 생각은 어때요?
나에게 메시지를 전달하신 분은 퇴근 후 개인적인 무언가를 하면서 의문을 가지셨다고 한다.
그리고 이 재미난 궁금증이 침대에 누워있던 나를 일으켜세웠다. 그리곤 다시 책을 펼치며, 검색을 하며 내 논리를 지지할 문장들을 가져왔고 오늘 이렇게 스스로 정리를 할 수 있게 되었다.
사실 가까이서도 조금만 더 들여다본다면 왜 이런 이름을 사용하지? 에 대한 의문을 찾을 수 있다.
왜 junit 에서 동일성 비교에 isSameAs() 를 사용하는지, 왜 동등성에는 isEqualTo() 를 사용하는지도 그러하다.
이를 통해서 알아볼 수 있는 중요한 것이 하나가 있다.
바로 관심인것 같다. 사실 repeat, iterate 누군가는 별 대수롭지 않게 넘어간다. 나역시도 그렇다.
하지만 누군가는 대수롭게 생각하며 가진 여러 지식들을 동원해서 끝장낸다. 당연한 것을 당연하게 받아들이지 않고 계속해서 의문을 갖는 자세를 엿볼 수 있다.
내가 경험한 프로그래밍에서는 '그래 그럴 수도 있지' 라는게 마냥 좋은것 같지도 않다.
실력은 어떤 집요함과 집착이 만들어낸다
'더 좋은 개발자 되기 > 나의 개발론' 카테고리의 다른 글
책임 주도 설계(RDD) 와 단일 책임 원칙(SRP) 에서 말하는 책임은 다르다 (3) | 2023.01.08 |
---|---|
백엔드 개발자로 밥벌이 1년을 축하하며 2022년의 회고를 (16) | 2022.12.29 |
나는 개인적으로 CQRS 를 이렇게 정의내리고 이렇게 생각한다. (9) | 2022.12.06 |
[Testing] Test Double, 테스트 더블-테스트 환경을 제어하는 다양한 방법 (4) | 2022.09.25 |
오버엔지니어링 하지 않기 (2) | 2022.08.29 |
댓글