sungyup's.

becoming_a_better_programmer / you.write(code); / 1.9 예상하지 못한 것을 예상하기

1.9예상하지 못한 것을 예상하기

예상하지 못한 상황은 반드시 일어나니, 모든 단계에서 발생할 가능성이 있는 특이 사항들을 고려해라.

TL;DR

코드를 작성할 때 비정상적인 상황을 고려하지 않는 사람들은 낙천주의자가 아니라, 무시하는 자(ignore-ists)일뿐이다.

코드 작성 시 벌어질 것으로 예상되는 상황에 대한 대비만으로는 부족하다. 모든 단계에서, 조금이라도 발생할 가능성이 있는 특이 사항들은 모두 고려해야 한다.

오류

모든 함수는 예상되로 작동하지 않을 수 있는 위험이 있다.

  • 운이 좋으면, 오류 코드를 전달 받을 수 있다. 이 경우 반드시 값을 확인하자.
  • 코드가 예외 발생을 대처할 수 있도록 하자. 직접 예외를 처리하든 스택 호출을 통과하게 놔두든, 코드가 정확히(리소스 누수가 없게) 작동하도록 하자.
  • 함수가 반환 코드나 예외 등을 돌려주지 않으면서 기능도 수행하지 않을 수 있다. 함수는 항상 메시지를 출력하는가? 아니면 때때로 기능 수행에 실패한 채 매개 변수로서 전달한 메시지를 먹어버리는가?

항상 오류를 고려한 코드를 작성하여 그로부터 복구할 수 있도록 하자.

스레딩

각 코드들 간의 비정상적 상호 작용은 해결하기 몹시 어렵다. 문제가 되는 특정 상호 작용을 재현해내는 것도 어렵고, 모든 코드 경로들 사이에서 발생 가능한 조합을 다 생각하기도 어렵다.

이런 예측 불가능을 다루기 위해서는 스레드 간의 결합도를 완화하여 위험하게 상호 작용하지 않도록 하는 방법을 이해해야 한다.

셧다운

어떻게 모든 객체가 생성되고 모든 톱니바퀴가 돌아가게 할지는 생각했어도, 리소스의 누출이나 데드락, 충돌 없이 코드를 우아하게 중단시킬 수 있는지에 대해서는 생각하지 않는 경우가 많다.

특히 다중 스레드 시스템에서는 애플리케이션이 종료되면서 작업자 객체(worker object)를 파기하므로, 그 과정에서 이미 파기한 객체를 사용하면 안 된다. 목표 객체가 이미 다른 스레드에 의해 제거된 콜백을 작업 큐에 넣으면 안 된다.

교훈

예상치 못한 것은 결코 이상한 것이 아니다. 코드를 작성할 때는 반드시 이를 고려해야 한다. 다만, 개발 초기에 고려해야지 나중에는 해당 이슈를 적절하기가 훨씬 어려워진다.


🥸 생각해보기

1. 예상치 못한 상황을 적절히 다루지 못한 코드에서 어떤 문제들을 발견하였는가?

개인적으로 만난 예상치 못한 상황들은 주로 한계값을 잘 설정하지 못했을 때 발생하였다. 로그인하면서 크레딧을 불러오는데, 그 짧은 찰나(사실 인터넷이 느리면 충분한 시간일 수도 있다는 점을 간과했다)에 크레딧 이상으로 생성을 하며 생기는 문제라던가 최대 10초 제한인데 어떤 케이스에는 해당 제한이 적용되지 않아 60초까지 생성을 한다거나 하는 경우들이 있었다.

인풋 값이나 상황을 충분히 고려하지 못했던 것이다.

2. 모든 코드는 자신 속에 항상 견고한 오류 처리를 포함하고 있는가?

아마 많은 코드가 그렇진 않을 것이다. 특히나 비동기 요청이나 유저 입력 등의 요소가 들어가면 경우의 수가 복잡해지고, 네트워크 지연 같은 문제는 놓치는 경우가 많을것 같다.

3. 어떤 상황에서 엄격한 오류 처리를 포기할 수 있는가?

정말 말 그대로 내부 개발용으로, 프로그램을 잘 아는 사람들끼리 굳이 이상한 행동을 하지 않고 정해진대로 쓰는 경우라면 굳이 엄격한 오류 처리를 할 필요는 없다고 생각한다. 다만 가급적 이런 경우에도 실수는 할 수 있으므로 alert 같은 요소로 경고를 띄울 수는 있을것 같다.

4. 코드의 품질과 견고함에 영향을 줄 수 있는 다른 놀라운 시나리오로는 어떤 것이 있다고 생각하는가?

검색해보니 이런 경우들이 있다고 한다:

  • 사용자 입력이 예상보다 훨씬 길거나 빈번할때(너무 빠른 클릭, 너무 많은 리퀘스트 등)
  • 네트워크 속도나 디바이스 성능이 아주 낮을때
  • 서버 응답은 유효한데 의미가 이상함(상태코드는 200인데 내용이 null)
  • 캐시나 로컬 스토리지에 저장된 오래된 설정값이 코드 흐름을 꼬는 경우가

이런 경우 디버깅이 아주 어려워질 수 있다.