Eighteeen / CleanCode_Book_Study

📚 클린코드 북 스터디 📚
4 stars 0 forks source link

[명령과 조회를 분리하라!] - 이 원칙을 우리 백준 풀이 코드에 적용한다면? #7

Closed deepredk closed 3 years ago

deepredk commented 3 years ago

진홍

명령(노드에 번호를 매김)과 조회(트리 사이즈 반환)가 뒤섞여있음

private int numberNodesAndReturnTreeSize(int rootIdx, int startNumber) {
  if (nodes.get(rootIdx) == null) return 0;

  int leftTreeIndex = rootIdx * 2 + 1;
  int rightTreeIndex = leftTreeIndex + 1;

  int leftTreeSize = numberNodesAndReturnTreeSize(leftTreeIndex, startNumber);
  nodes.put(rootIdx, startNumber + leftTreeSize);
  int rightTreeSize = numberNodesAndReturnTreeSize(rightTreeIndex, nodes.get(rootIdx) + 1);

  return leftTreeSize + 1 + rightTreeSize;
}

승빈

명령(단방향 트리로 만듬)과 조회(서브트리 사이즈를 반환함)가 뒤섞여있음

private int setOneWayTreeAndSubTreeSize(Node node) {
    int nodeData = node.getData();

    int descendantSize = node.getAdjacentNodeSize();
    for (Node child : node.getAdjacentNodeList()) {
        child.removeAdjacentNode(node);
        descendantSize += setOneWayTreeAndSubTreeSize(child);
    }

    subTreeSizeArr[nodeData] = descendantSize + 1;
    return descendantSize;
}

수경

명령(각 노드에 대한 최대 깊이를 갱신함)과 조회(최대 깊이를 반환함)가 뒤섞여있음

def calcMaxDepthAbleToDeliver(curNode):
    maxDepth = 0

    for nextNode in tree[curNode]:
        if (visitedNodes[nextNode]): continue
        visitedNodes[nextNode] = True

        maxDepth = max(maxDepth, calcMaxDepthAbleToDeliver(nextNode) + 1)

    maxDepthOfNodeList[curNode] = maxDepth
    return maxDepth

위처럼 우리는 명령과 조회가 뒤섞여있는 코드를 꽤 사용해왔어.

근데 이렇게 할 수 밖에 없던게, 저 코드에서 명령과 조회를 분리하려면 DFS를 2배로 해야되니까 못 했던거고.

이럴때 효율성을 떨어뜨리지 않으면서 명령과 조회를 분리하는 방법이 없을까?

deepredk commented 3 years ago

아무리 생각해도 그런 방법 없는 것 같음. DFS 한 술에 배부르려면 한 함수에서 여러가지(조회+명령) 짬뽕으로 할 수 밖에 없는 듯

근데 실무에서도 이런 상황이 드물진 않을 것 같은데 어떻게 타협들 보실까 싶네

sookyeonghwang commented 3 years ago

저도 @deepredk 말에 동의합니다.

함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야한다

라고 말하고 있지만 알고리즘 문제를 푸는 경우는 효율성이 매우 중요하기 때문에 조회+명령으로 구현할 수 밖에 없을 것 같아요

WinningBean commented 3 years ago

@deepredk , @sukyeongh 두 분의 말에 동의합니다. 특히 DFS를 재귀로 사용하는 경우, return과 함께 로직을 풀어나가야 하기 때문에 조회와 명령이 함께 진행될 수밖에 없는 경우가 많다고 생각합니다.

하지만 이들을 객체로 묶는다면, 해당 객체 외부에서 부르는 명령문과 조회문을 따로 분리시켜 외부에서는 헷갈리지 않도록 정리하는 방법이 있겠네요.

sookyeonghwang commented 3 years ago

결론

조회 + 명령을 써야하는 코드가 있다면 외부적으로 분리하는 방법이 혼란을 잠재울 수는 있지만 내부적으로는 해결할 수 없는 경우도 있을 것이다.