콘텐츠로 건너뛰기

X-Y Problem

X-Y Problem은 다음과 같은 상황에서 발생한다. 어떤 사람이 문제를 풀려고 자신이 생각하는 어떠한 방법을 통해서 그것을 해결하고자하는데 그 방법이 통하지 않아 문제를 해결하지 못하고 다른 사람들에게 도움을 구한다.

그런데 여기서 문제는 다른 사람에게 도움을 구할 때 자신이 풀려고 하는 문제에 대해서 설명하는 것이 아니라 자신이 생각한 방법에 대해서 설명한다는 것이다.

사실 그 사람이 생각한 방식으로 문제를 해결하는 것은 엄청 시간이 많이 걸리고 비효율적인 방식일 수도 있다. 문제를 해결하기 위해 다른 사람들에게 도움을 구할 때 가장 최선의 방법은 자신이 생각한 방법에 대해서 설명하는 것이 아니라 해결하고자 하는 문제에 대해서 설명하는 것이다.

위의 문제를 정리하면 다음과 같다.

  • 어떤 사람이 X라는 문제를 해결하고 싶어한다.
  • 그 사람은 X 문제를 어떻게 해결하는지 모르기 때문에 여러 가지 방법에 대해서 고민하다 Y라는 방법을 떠오른다. 그리고 Y를 마치면 X 라는 문제를 해결할 수 있을 것이라 믿는다.
  • 그런데 그 사람은 Y를 어떻게 할 수 있는지 잘 모른다.
  • 그래서 그 사람은 Y를 어떻게 할 수 있는지에 대해서 다른 사람들에게 도움을 요청한다.
  • 그래서 다른 사람이 Y라는 문제를 어떻게 해결할 수 있는지에 대해서 도움을 주려고 한다. 그런데 도움을 주는 사람이 봤을 땐 Y의 방식이 이상하다.
  • 도움을 주는 사람과 문제를 해결하려고 하는 사람이 좀 더 이야기를 하면서 마침내 사실 해결해야하는 문제가 X라는 것을 알아낸다. 그리고 Y라는 방식은 사실 X라는 문제를 해결하기 위해서는 필요가 없거나 엄청나게 비효율적인 방식이었다.

오늘 리뷰를 부탁받은 코드 중에 다음과 같은 코드가 있었다.

public void doSomething() {
	final AtomicInteger idx = new AtomicInteger(0);
	items.forEach(item -> {
		if (idx.getAndIncrement() == 0) {
			...
		}
		...
	})
}

코드를 보았을 때 가장 먼저 눈에 들어왔던 것은 AtomicInteger이다. 보통 AtomicInteger 는 여러 스레드에서 lock을 걸지 않은 어떤 변수에 접근할 때 각각의 스레드가 잘못된 값을 읽는 것을 막기 위해 쓰는 것으로 알고 있는데 갑자기 평범한 웹 어플리케이션의 한 비즈니스 로직에 등장한 것이다.

리뷰 과정의 문답을 간단하게 정리하면 아래와 같다.

Q: “AtomicInteger를 사용한 의도가 궁금합니다”

A: “getAndIncrement()를 사용하기 위해서 입니다.”

Q: “그렇다면 primitive type을 써도 될 것 같습니다.”

A: “그런데 람다식 안에서는 primitive type을 쓸 수 없습니다.”

이 정도의 문답이 오고가니 이제 문제가 어떤 것이고 왜 AtomicInteger를 사용했는지 이해가 되었다. 바로 items 들을 iterate 하고 싶고 동시에 인덱스 정보값이 필요한 것이다.

사실 AtomicInteger를 사용하면 동작하긴 하는 코드이다. 하지만 AtomicInteger가 만들어진 원래 의도와 맞지 않고 또 중요한 것은 인덱스를 통해서 Iterable에 접근하는 방식 중에 우리가 가장 잘 알고 있는 방법이 있는데, 바로 간단한 for-loop이다. Stream에서 인덱스를 가져오려니 뭔가 어색한 코드가 되는 것이다.

생각해보면 Stream을 통해서는 인덱스를 가져오기 불편하게 설계되었고 애초에 Stream의 의도가 인덱스에 따라서 어떤 로직을 전개하라고 만들어진 것 같지 않다.

그래서 동작하긴하는 코드이지만 다시 한번 답글을 달게되었다.

Q: “인덱스에 따라서 로직을 전개하는 것이 핵심인 것 같은데 람다를 안쓰는 방법도 있습니다. 인덱스를 사용하려면 간단한 for-loop도 있습니다. 굳이 Stream을 써야겠다면 IntStream.range를 찾아보시면 좋을 것 같습니다.”

스택오버플로우에 찾아보니 정말 많은 경우 AtomicInteger를 쓰는 방법을 답란에 쓰는 경우가 정말 많았다. 그 중 하나의 답변에서 XY Problem 이라는 것을 발견했고 이 모든 상황이 이 문제와 맞아 떨어지는 것 같아 포스팅을 하게되었다.

좀 더 X-Y Problem에 대해서 자세하게 알고 싶다면 여기의 글을 읽어보면 좋을 것 같다.

Leave a comment