3. 다른 개발자와 코드 계약
소프트웨어 개발은 대개 팀 단위로 이루어진다. 작성한 코드를 다른 사람이 작업하거나, 자신이 다른 사람의 코드를 작업해야 할 때가 있다.
자신의 코드와 다른 개발자의 코드
여러 하위 문제를 해결하고 추상화 계층으로 분리하면, 다른 개발자들은 여러분이 생각하지 못한 다른 문제에서 코드를 재사용할 수 있다.
요구사항이 변하고 우선순위가 변경되면서, 개발자들이 코드 베이스에서 계속 수정을 가하면 코드 베이스는 활발한 코드 베이스가 된다.
코드의 품질을 유지하기 위해서는 다른 개발자가 변경하거나 코드와 상호작용할 때 발생할 수 있는 문제를 미리 예측하고, 선제적으로 조치해야 한다.
코드를 작성할 때 다음 세 가지를 고려하는 것이 유용하다.
1) 자신에게 분명하다고 해서 다른 사람에게도 분명한 것은 아니다.
자신의 로직에 너무 익숙하면, 모든 것이 분명해 보이기 때문에 왜 그런 방식으로 문제를 해결하고 있는지에 대해서는 거의 생각하지 않아도 된다. 하지만 어느 시점에 다른 개발자가 여러분이 작성한 코드와 상호작용하거나, 여러분의 코드를 변경하거나, 여러분의 코드가 의존하고 있는 코드를 변경해야 할 수도 있다는 것을 기억해야 한다.
이것을 항상 고려하고 코드가 어떻게 사용되어야 하는지, 무엇을 하는지, 그리고 왜 그 일을 하고 있는지 설명하는 것이 유용하다.
2) 다른 개발자는 무의식중에 여러분의 코드를 망가뜨릴 수 있다.
여러분이 작성한 코드는 다른 코드로부터 전혀 영향을 받지 않은 채 독립적으로 있는 것이 아니라, 끊임없이 변화하는 코드 위에 놓여 있고, 여러분의 코드를 기반으로 계속해서 변화하는 코드 역시 끊임없이 작성된다.
다른 개발자들은 여러분의 코드를 접할 때 그 코드가 왜 존재하고, 무슨일을 수행하는지 모를 수 있다. 이 경우 의도치 않게 잘 실행되던 코드를 작동하지 않게 하거나 오용하는 방식으로 코드를 수정할 가능성이 있다.
3) 시간이 지나면 자신의 코드를 기억하지 못한다.
여러분이 작성한 코드의 사용법을 다른 사람들은 어떻게 아는가?
1) 이름 확인
자신의 코드를 다른 개발자가 어떻게 사용해야 하는지에 대해 가장 잘 전달할 수 있는 방법 중 하나는 이름을 잘 짓는 것이다.
2) 데이터 유형 확인
데이터 유형을 확인하는 것 역시 다른 개발자로 하여금 자신의 코드를 올바르게 사용하도록 하기 위한 매우 신뢰할 만한 방법이다. 유형 시스템을 사용하는 언어에서는 코드를 오용하거나 오작동할 수 없도록 방지하기도 한다.
3) 문서 읽기
코드를 사용하는 방법에 관한 문서는 두 가지 이상의 형태로 존재할 수 있으며 다음을 포함한다.
- 함수 및 클래스 수준의 비공식적인 주석문
- JSDoc과 같은 좀 더 공식적인 코드 내 문서
- 외부 문서(readme 등)
매우 유용하지만 다른 개발자가 코드를 올바르게 사용하도록 하기 위한 방법으로 어느 정도까지만 신뢰할 수 있다.
- 다른 개발자가 이 문서들을 읽을 것이라는 보장이 없으며, 실제로 읽지 않을 때가 많다.
- 설령 읽더라도 잘못 해석할 수 있다.
- 문서의 업데이트가 제대로 안 될 수 있다.
4) 직접 물어보기
코드를 작성한 지 얼마 안 된 상황이면 이 접근법이 효과적이지만, 다음과 같은 이유로 신뢰하기 어려운 방법이다.
- 코드를 많이 작성할수록 질문에 답하는 데 더 많은 시간을 써야 할 것이다.
- 코드 작성자가 2주간 휴가를 간다면 코드에 대해 물어볼 사람이 없다.
- 1년이 지나면 자기 자신도 그 코드를 기억하지 못한다.
- 당사자가 퇴사할 수 있다.
5) 코드 살펴보기
코드 사용 방법에 대한 가장 확실한 답을 얻을 수 있는 방법은 코드의 자세한 구현 세부 사항을 살펴보는 것이다. 하지만 이 접근법은 실용적이지 않고 코드의 양이 많으면 효과를 얻기 힘들다.
따라서 추상화 계층을 만드는 것이 중요합니다. 추상화 계층을 만드는 데 있어 요점은 개발자가 한 번에 몇 가지 개념만 처리해야 하고, 그 문제가 어떻게 해결되었는지 정확히 알지 못하더라도 하위 문제에 대한 해결책을 사용할 수 있어야 한다. 코드를 사용하는 방법을 알기 위해 개발자가 구현 세부 사항을 읽어야 한다면 이는 분명히 추상화 계층의 많은 이점을 부정하는 것이 된다.
코드 계약
계약에 의한 프로그래밍은 이전 절에서 논의한 개념들 중 일부를 공식화하는 원칙으로, 다른 사람들이 코드를 사용할 때 어떻게 사용해야 하는지, 그리고 그 코드가 무엇을 할 것으로 기대할 수 있는지에 대한 것이다. 이 철학에서는 서로 다른 코드 간의 상호작용을 마치 계약처럼 생각한다.
코드의 계약에 대한 용어를 다음과 같은 세 가지 범주로 나누면 유용하다.
- 선결 조건 : 코드를 호출하기 전에 사실이어야 하는 것, 예를 들어 시스템이 어떤 상태에 있어야 하는지, 코드에 어떤 입력을 공급해야 하는지와 같은 사항
- 사후 조건 : 코드가 호출된 후에 사실이어야 하는 것
- 불변 사항 : 코드가 호출되기 전과 후에 시스템 상태를 비교해야 변경되지 않아야 하는 사항
의도적으로 계약에 의한 프로그래밍을 하지 않고 이 용어에 대해 한 번도 들어본 적이 없다 해도, 여러분이 작성하는 코드는 어떤 종류의 계약을 맺는 것이라고 봐도 무방하다.
개발자가 계약의 일부 혹은 모든 조건을 알지 못하면 코드 계약에 문제가 발생한다. 코드를 작성할 때, 만들어지는 계약의 내용이 무엇이며 어떻게 하면 코드를 사용하는 사람이 계약을 파악하고 따라갈 수 있을지에 대해 생각하는 것이 중요하다.
1) 계약의 세부 조항
코드에서 계약을 정의할 때 명확한 부분과 세부 조항이 있다.
명확한 부분
- 함수와 클래스 이름: 사용자가 모르면 사용할 수 없다.
- 인자 유형: 인자의 유형을 잘못 사용하면 코드는 컴파일되지 않는다.
- 반환 유형: 함수의 반환 유형을 알아야 한다.
- 검사 예외
세부 조항
- 주석과 문서: 실제 계약의 세부 조항에 대해 꼼꼼하게 읽어야 하지만, 실제로는 잘 읽지 않는다. 개발자는 이 사실을 실용적인 관점에서 봐야 한다.
- 비검사 예외
코드 계약에서 조건을 명확하게 하는 것이 세부 조항을 사용하는 것보다 훨씬 낫다. 사람들은 세부 조항을 읽지 않는 경우가 매우 많으며, 심지어 읽더라도 대충 훑어보기 때문에 잘못 이해할 수 있다.
문서화는 업데이트가 제때 되지 않기 때문에 세부 조항이 항상 정확한 것도 아니다.
2) 세부 조항에 너무 의존하지 말라
주석과 문서 형태의 세부 조항은 간과하고 넘어갈 때가 많아서 다른 개발자들이 해당 코드를 사용할 때 모든 세부 조항을 알지 못할 가능성이 크다.
따라서 코드 계약을 전달할 때 세부 조항을 사용하는 것은 신뢰할 수 없는 방법이다. 세부 조항에 너무 의존하면 오용하기 쉬운 취약한 코드가 될 가능성이 크고, 예상과 다르게 동작하기 쉽다.
피치 못할 상황으로 문서화가 필요한 경우도 있지만 너무 많이 의존하지 않는 것이 최선의 방법이다.
다른 개발자가 코드를 올바르게 사용하기 위해 세부조항에 의존하기보다 잘못된 일을 하는 것을 처음부터 불가능하게 만드는 것이 좋다. 코드 계약의 세부 조항에 있는 어떤 항목에 대해 발생 자체가 불가능하도록 명백한 항목으로 바꾸는 것이 가능한 경우가 있다. 코드가 오용되거나 잘못 설정되면 컴파일조차 되지 않도록 하는 것이 목표.
체크 및 어서션
컴파일러를 사용하여 코드 계약을 확인하는 것에 대한 대안으로 런타임 검사를 사용할 수 있다. 컴파일러를 사용하는 것이 더 강력한 수준의 방지책이지만, 계약을 강제할 실질적인 방법이 없는 상황에서는 런타임 검사라도 사용하는 것이 좋다.
체크와 어서션은 비슷하지만, 배포를 위해 빌드할 때 어서션은 컴파일에서 제외된다는 점이 다르다.