You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
프로덕션 소프트웨어는 지속적으로 동작해야 한다. 따라서 운영 가능한 코드를 작성해야 예상하지 못한 상황에 대처할 수 있다. 운영 가능한 코드란 보호 장치, 분석 장치, 제어 장치가 내장된 코드를 말한다. 안전하고 회복성 있는 코딩 기법을 이용해 방어적으로 프로그래밍해서 시스템을 보호해야 한다.
장애에 대비하기 위한 방어적 프로그래밍 방안
방어적 코드는 코드를 운영하는 모두를 위한 배려다. 방어적 코드는 장애가 발생하는 빈도가 낮으며, 장애가 발생하더라도 대부분 복구가 가능하다. 코드를 안전하고 회복성 있게 즉, **안정한 코드(safe code)**는 컴파일 타임의 유효성 검사를 통해 런타임 장애를 최소화한다.
불변 변수, 접근 제어자로 범위 제한, 정적 타입 검사를 통한 버그 최소화
null값 사용은 피하자
대부분의 언어는 값이 할당되지 않은 변수의 기본값으로 null을 할당하여 빈번하게 NullPointerException이 발생한다. 변수에 대한 널 체크나 널 객체 패턴을 통해 예외를 방지하자.
코드로 전달되는 입력값은 절대로 신뢰해선 안 된다. 사전 조건 및 사후 조건을 이용해서 메소드에 전달되는 입력 변수의 유효성을 검사해야 한다.
예외를 활용하자
매직값을 통한 리턴으로 예외를 표한하는 것은 금물이다. 최신 개발 언어는 예외나 표준 예외 처리 패턴을 제공한다. 특정한 리턴값은 메소드 시그니처에 명확하게 드러나지 않는다. 따라서 개발자는 리턴값이 에러를 의미한다는 점을 모를 수 있다.
따라서 예외를 통해 명확하게 나타내자.
예외는 구체적으로 사용하자
예외를 구체적으로 정의하면 코드를 더 쉽게 사용할 수 있다. 예외를 직접 정의할 때는 너무 포괄적인 의미가 담기지 않게 하자.(추상적인 예외보다 직접적이고 명확한 예외)
예외는 일찍 던지고 최대한 나중에 처리하자
'일찍 던지고 늦게 잡는' 원칙을 따르자.
일찍 던진다는 말은 개발자가 관련 코드를 신속하게 찾을 수 있도록 에러가 발생한 지점으로부터 최대한 가까운 지점에서 예외를 던진다는 뜻이다. (실제 에러 위치를 파악하기 위해서) 예외를 늦게 잡는다라는 말은 예외를 처리할 적절한 위치에 도착할 때까지 계속 호출 스택을 통해 전파시킨다는 뜻이다.
정리하면 호출하는 코드가 예외를 던지면 예외를 완전히 처리하거나 혹은 상위 스택으로 전파하자.
재시도는 현명하게
에러를 적절하게 처리하는 방법 중 하나는 단순히 다시 시도하는 것이다. 여러 차례 재시도하려는 시도는 주로 원격 시스템을 호출할 경우에 나타난다.
예외에서 재시도는 현명해보일 수 있어도 재시도의 시기와 빈도를 판단하려면 노하우가 필요하다. 가장 손쉬운 방법은 단순히 예외를 잡아서 그 즉시 작업을 다시 시도하는 것이다. 하지만 이런 방법은 재시도를 무한정 반복할 수 있기 때문에 위험하다.
따라서 **백오프(backoff)**라는 전략을 사용하는 것이 좋다. 백오프는 비선형으로 대기 시간을 늘려 시간의 상한까지 재시도에 대한 빈도를 제어한다.
모든 클라이언트가 이런 알고리즘을 사용한다면 무수히 많은 요청으로 인해 천둥떼 현상을 겪을 수 있다. (지터를 사용해서 해결)
시스템에 멱등성을 부여하자
재시도를 처리하는 가장 좋은 방법은 멱등성이 있는 시스템을 구현하는 것이다. 멱등성이란 동일한 작업을 여러 번 실행해도 같은 결과가 출력됨을 의미한다. (어떤 값을 해시셋에 추가하는 것은 멱등 작업이다.)
리소스를 해제하자
장애가 발생하면 모든 리소스를 해제해야 한다. 더 이상 필요하지 않은 메모리, 데이터 구조, 네트워크 소켓, 파일 핸들 등을 모두 해제하자.
C#은 Dispose 패턴을 사용해서 리소스를 해제한다. C++은 직접 메모리를 해제해야 한다.
문제 원인을 찾기 위한 로깅 방안
로깅은 간단하게 로그를 찍어 확인하는 편리한 방법으로 어떤 로그를 기록할지 제어하는 것이 중요하다.
로그 레벨을 사용하자
로깅 프레임워크는 운영자가 중요도에 따라 메시지를 필터링할 수 있도록 로그 레벨을 지원한다. 로그 레벨을 활용하면 매우 세세한 디버깅 로그부터 정상적인 운영 상화에서 주기적으로 기록되는 로그까지, 주어진 상황에 맞춰서 로그의 양을 조정할 수 있다.
로그는 원자적으로 작성하자
만일 데이터화 결합했을 때만 정보가 유용하다면 한 메시지에 모든 정보를 원자적으로 저장하자.
로그는 신속하게 기록하자
로그를 너무 많이 기록하면 성능에 영향을 미친다. 로그는 디스크나 콘솔, 원격 시스템 등 어딘가에 반드시 기록돼야 하며, 기록되기 전에 올바른 형태의 한 문자열로 결합해야 한다.
유니티에서도 잘 활용되는 듯 하다.
애플리케이션 동작 측정을 위한 지표 활용 방안
Unity는 따로 프로파일링을
지표는 숫자로 표현한 로그와도 같아서 애플리케이션 동작을 측정한다.
표준 지표 라이브러리를 사용하자
이미 구현된 라이브러리를 사용하라.
모든 것을 측정하자
측정은 비용이 적게 드는 작업이므로 가급적 많은 지표를 수집해야 한다. 다음과 같은 데이터 구조, 작업, 동작은 모두 측정하자.
리소스 풀
캐시
데이터 구조
CPU 집약적 작업
IO 집약적 작업
데이터 크기
예외와 에러
원격 요청 및 응답
오늘날 분산 환경에서 더욱 중요해진 추적
RPC 클라이언트는 추적 라이브러리를 이용해서 요청마다 호출 추적 ID를 붙인다.
설정으로 런타임 동작을 손쉽게 조정하려면
설정정보등을 Json, TAML처럼 일반 텍스트이면서 읽을 수 있는 형식, 환경변수, 명령줄 플래그 등등으로 설정값을 관리한다.
지나치게 창의적인 설정은 금물이다
이는 그냥 개발에서도 적용되는 모호하거나 오용될 수 있는 설정값을 사용하지 말라는 것이다.
모든 설정을 로그에 기록하고 검증하자
애플리케이션이 어떤 설정값을 사용하는지 알 수 있도록 시작 시점에 즉시 설정값을 로그에 기록하자.
기본값을 제공하자
대부분의 사용자가 시스템을 곧바로 사용할 수 있도록 적절한 기본값을 제공하자.
관련된 설정을 그룹화하자
애플리케이션 설정은 특히 중첩된 설정을 지원하지 않는 키-값 형식인 경우 금새 크기가 커져서 관리가 불가능해진다.
설정도 코드처럼 테스트하자
코드로서의 설정은 설정도 코드처럼 취급해야 한다는 철학이다. 설정을 안전하게 변경하려면 설정도 버전 제어로 관리하고 리뷰하고 테스트하고 배포한다.
설정 파일은 깔끔하게 유지하자
설정 파일이 깔끔하면 다른 사람이 이해하고 변경하기가 쉽다. 사용하지 않는 설정은 지우고 표준 형식과 공백을 사용해야 하며, 잘 모르면서 다른 파일에서 설정을 복사해 붙여넣는 일은 금하자.
배포된 설정은 변경하지 말자
특정 머신의 설정을 수작업으로 수정하는 일은 금하자.
개발자의 필수 체크리스트
이것만은 지키자
이것만은 피하자
런타임 에러보다는 컴파일 타임에 에러를 검출하자
예외를 이용해 애플리케이션의 로직을 결정하면 안된다
가능하면 불변 변수를 사용하자
리턴 코드로 예외를 처리해서는 안 된다
입력과 출력을 검증하자
처리할 수 없는 예외는 잡지 말자
10대 애플리케이션 취약점을 숙지하자
로그를 여러 줄로 나누지 말자
버그 확인도구는 물론 타입 또는 타입 힌트도 사용하자
보안 정보나 민감한 데이터를 로그에 기록하지 말자
코드에 지표를 추가하자
비밀번호나 보안 정보를 설정 파일에 기록하지 말자
애플리케이션 설정을 추가해두자
커스텀 설정 형식은 채택하지 말자
모든 설정을 검증하고 로그에 기록해하자
불필요한 동작 설정은 사용하지 말자
The text was updated successfully, but these errors were encountered:
4장 운영 환경을 고려한 코드 작성
프로덕션 소프트웨어는 지속적으로 동작해야 한다. 따라서 운영 가능한 코드를 작성해야 예상하지 못한 상황에 대처할 수 있다. 운영 가능한 코드란 보호 장치, 분석 장치, 제어 장치가 내장된 코드를 말한다. 안전하고 회복성 있는 코딩 기법을 이용해 방어적으로 프로그래밍해서 시스템을 보호해야 한다.
장애에 대비하기 위한 방어적 프로그래밍 방안
방어적 코드는 코드를 운영하는 모두를 위한 배려다. 방어적 코드는 장애가 발생하는 빈도가 낮으며, 장애가 발생하더라도 대부분 복구가 가능하다. 코드를 안전하고 회복성 있게 즉, **안정한 코드(safe code)**는 컴파일 타임의 유효성 검사를 통해 런타임 장애를 최소화한다.
불변 변수, 접근 제어자로 범위 제한, 정적 타입 검사를 통한 버그 최소화
null값 사용은 피하자
대부분의 언어는 값이 할당되지 않은 변수의 기본값으로 null을 할당하여 빈번하게 NullPointerException이 발생한다. 변수에 대한 널 체크나 널 객체 패턴을 통해 예외를 방지하자.
불변 변수를 사용하자
C#에선 레코드라는 불변을 보장할 수 있는 타입이 있다.
타입 힌트와 정적 타입 검사를 활용하자
변수를 선언할 때는 가장 구체적인 타입을 사용한다.
입력값을 검사하자
코드로 전달되는 입력값은 절대로 신뢰해선 안 된다. 사전 조건 및 사후 조건을 이용해서 메소드에 전달되는 입력 변수의 유효성을 검사해야 한다.
예외를 활용하자
매직값을 통한 리턴으로 예외를 표한하는 것은 금물이다. 최신 개발 언어는 예외나 표준 예외 처리 패턴을 제공한다. 특정한 리턴값은 메소드 시그니처에 명확하게 드러나지 않는다. 따라서 개발자는 리턴값이 에러를 의미한다는 점을 모를 수 있다.
따라서 예외를 통해 명확하게 나타내자.
예외는 구체적으로 사용하자
예외를 구체적으로 정의하면 코드를 더 쉽게 사용할 수 있다. 예외를 직접 정의할 때는 너무 포괄적인 의미가 담기지 않게 하자.(추상적인 예외보다 직접적이고 명확한 예외)
예외는 일찍 던지고 최대한 나중에 처리하자
'일찍 던지고 늦게 잡는' 원칙을 따르자.
일찍 던진다
는 말은 개발자가 관련 코드를 신속하게 찾을 수 있도록 에러가 발생한 지점으로부터 최대한 가까운 지점에서 예외를 던진다는 뜻이다. (실제 에러 위치를 파악하기 위해서)예외를 늦게 잡는다
라는 말은 예외를 처리할 적절한 위치에 도착할 때까지 계속 호출 스택을 통해 전파시킨다는 뜻이다.정리하면 호출하는 코드가 예외를 던지면 예외를 완전히 처리하거나 혹은 상위 스택으로 전파하자.
재시도는 현명하게
에러를 적절하게 처리하는 방법 중 하나는 단순히 다시 시도하는 것이다. 여러 차례 재시도하려는 시도는 주로 원격 시스템을 호출할 경우에 나타난다.
예외에서 재시도는 현명해보일 수 있어도 재시도의 시기와 빈도를 판단하려면 노하우가 필요하다. 가장 손쉬운 방법은 단순히 예외를 잡아서 그 즉시 작업을 다시 시도하는 것이다. 하지만 이런 방법은 재시도를 무한정 반복할 수 있기 때문에 위험하다.
따라서 **백오프(backoff)**라는 전략을 사용하는 것이 좋다. 백오프는 비선형으로 대기 시간을 늘려 시간의 상한까지 재시도에 대한 빈도를 제어한다.
모든 클라이언트가 이런 알고리즘을 사용한다면 무수히 많은 요청으로 인해 천둥떼 현상을 겪을 수 있다. (지터를 사용해서 해결)
시스템에 멱등성을 부여하자
재시도를 처리하는 가장 좋은 방법은 멱등성이 있는 시스템을 구현하는 것이다. 멱등성이란 동일한 작업을 여러 번 실행해도 같은 결과가 출력됨을 의미한다. (어떤 값을 해시셋에 추가하는 것은 멱등 작업이다.)
리소스를 해제하자
장애가 발생하면 모든 리소스를 해제해야 한다. 더 이상 필요하지 않은 메모리, 데이터 구조, 네트워크 소켓, 파일 핸들 등을 모두 해제하자.
C#은 Dispose 패턴을 사용해서 리소스를 해제한다. C++은 직접 메모리를 해제해야 한다.
문제 원인을 찾기 위한 로깅 방안
로깅은 간단하게 로그를 찍어 확인하는 편리한 방법으로 어떤 로그를 기록할지 제어하는 것이 중요하다.
로그 레벨을 사용하자
로깅 프레임워크는 운영자가 중요도에 따라 메시지를 필터링할 수 있도록 로그 레벨을 지원한다. 로그 레벨을 활용하면 매우 세세한 디버깅 로그부터 정상적인 운영 상화에서 주기적으로 기록되는 로그까지, 주어진 상황에 맞춰서 로그의 양을 조정할 수 있다.
로그는 원자적으로 작성하자
만일 데이터화 결합했을 때만 정보가 유용하다면 한 메시지에 모든 정보를 원자적으로 저장하자.
로그는 신속하게 기록하자
로그를 너무 많이 기록하면 성능에 영향을 미친다. 로그는 디스크나 콘솔, 원격 시스템 등 어딘가에 반드시 기록돼야 하며, 기록되기 전에 올바른 형태의 한 문자열로 결합해야 한다.
유니티에서도 잘 활용되는 듯 하다.
애플리케이션 동작 측정을 위한 지표 활용 방안
Unity는 따로 프로파일링을
지표는 숫자로 표현한 로그와도 같아서 애플리케이션 동작을 측정한다.
표준 지표 라이브러리를 사용하자
이미 구현된 라이브러리를 사용하라.
모든 것을 측정하자
측정은 비용이 적게 드는 작업이므로 가급적 많은 지표를 수집해야 한다. 다음과 같은 데이터 구조, 작업, 동작은 모두 측정하자.
오늘날 분산 환경에서 더욱 중요해진 추적
RPC 클라이언트는 추적 라이브러리를 이용해서 요청마다 호출 추적 ID를 붙인다.
설정으로 런타임 동작을 손쉽게 조정하려면
설정정보등을 Json, TAML처럼 일반 텍스트이면서 읽을 수 있는 형식, 환경변수, 명령줄 플래그 등등으로 설정값을 관리한다.
지나치게 창의적인 설정은 금물이다
이는 그냥 개발에서도 적용되는 모호하거나 오용될 수 있는 설정값을 사용하지 말라는 것이다.
모든 설정을 로그에 기록하고 검증하자
애플리케이션이 어떤 설정값을 사용하는지 알 수 있도록 시작 시점에 즉시 설정값을 로그에 기록하자.
기본값을 제공하자
대부분의 사용자가 시스템을 곧바로 사용할 수 있도록 적절한 기본값을 제공하자.
관련된 설정을 그룹화하자
애플리케이션 설정은 특히 중첩된 설정을 지원하지 않는 키-값 형식인 경우 금새 크기가 커져서 관리가 불가능해진다.
설정도 코드처럼 테스트하자
코드로서의 설정은 설정도 코드처럼 취급해야 한다는 철학이다. 설정을 안전하게 변경하려면 설정도 버전 제어로 관리하고 리뷰하고 테스트하고 배포한다.
설정 파일은 깔끔하게 유지하자
설정 파일이 깔끔하면 다른 사람이 이해하고 변경하기가 쉽다. 사용하지 않는 설정은 지우고 표준 형식과 공백을 사용해야 하며, 잘 모르면서 다른 파일에서 설정을 복사해 붙여넣는 일은 금하자.
배포된 설정은 변경하지 말자
특정 머신의 설정을 수작업으로 수정하는 일은 금하자.
개발자의 필수 체크리스트
The text was updated successfully, but these errors were encountered: