목차
◦ 책 소개
◦ 구성과 관리에 관한 이슈
◦ 디자인 스타일
◦ 코딩 스타일
◦ 함수와 연산자
◦ 생성과 파괴 그리고 복사
◦ 네임스페이스와 모듈
2023-01-11
책 소개
◦ 원제 : c++ coding standards
◦ 저자 : Herb Sutter, Andrei Alexandrescu
2023-01-11
구성과 관리에 대한 이슈
◦ 작은 것에 연연하지 말라
◦ 쓸데 없는 규칙 만들지 말라
Ex) 라인의 길이 제한, 함수의 정확한 줄 수 제한, 빡빡한 명명 규칙 등
◦ 오랫동안 사용한 규칙이라고 해서 잘못된 규칙을 유지하지 말것
◦ 사소한 경고 메시지를 무시하지 말라
◦ 경고 수준을 항상 최상위로 설정하라
◦ 빌드 될 때 하나의 오류도 없이 이루어져야 한다
2023-01-11
구성과 관리에 대한 이슈
◦ 자동화된 빌드 시스템을 사용하라
◦ 중간에 사용자 개입 없이 전체 프로젝트의 빌드가 이루어지도록 하자
◦ 원액션 빌드 시스템은 반드시 필요하다
◦ 현재 CI / CD (젠킨스 등)를 이용해서 자동화된 빌드 시스템을 제공하고 있음
◦ 없으면 생기는 문제들
1. 프로그래머가 직접 배포하느라 시간이 많이 뺏긴다.
2. 프로그래머가 실수할 여지를 준다
◦ 버전 컨트롤 시스템을 사용하라
◦ SVN, 소스트리, Git
◦ 같은 파일을 작업하거나, 잘못된 코드를 되돌릴 때 유용하다
◦ 해외에 서비스를 하는데 버전에 차이가 난다면 도움이 된다.
◦ 하지만 항상 안 좋은 사용법은 존재한다.
Ex) 깃 로그를 운영 중심으로 작성되고, 로그를 정리해서 운영팀에게 넘겨주는 방식
2023-01-11
구성과 관리에 대한 이슈
◦ 코드 리뷰에 시간을 투자하라
◦ 장점은 다음과 같다
◦ 동료의 조언을 통해 코드 질이 높아진다
◦ 버그를 찾아내고, 적절하지 않은 부분이나 호환/ 확장성 문제를 찾아낼 수 있다.
◦ 아이디어를 공유하는 과정에서 보다 나은 디자인을 찾을 수 있다.
◦ 새로운 팀 동료나 아직 코드에 익숙하지 않은 사람은 보다 빨리 팀의 업무에 익숙해질 수 있다.
◦ 팀의 커뮤니티에 도움을 주며, 일관된 목표를 향해 나아갈 수 있게끔 해준다.
◦ 서로에 대한 신뢰, 동기 부여, 전문성 확보에 도움이 된다.
◦ 단점은 다음과 같다
◦ 이상한 동료가 있으면 이상한 피드백을 받는다.
Ex) get함수에 함수 const를 붙이면 상위 버전에서는 빌드가 안된다.
◦ 제대로 도입되지 않으면 효용성이 떨어진다
왜 최근 들어온 신입 두 명만 코드 리뷰를 받는가?
2023-01-11
디자인 스타일
◦ 디자인 스타일 챕터의 주 요점
1. 언제, 어떻게 만들지 파악해두고
2. 명확하고 간결하게 디자인하라
3. 최적화는 앞의 조건이 만족하면 진행이 되야 한다.
2023-01-11
디자인 스타일
◦ 적절한 규모 유지를 위해서는 ‘언제, 어떻게’를 아는 것이 중요하다.
◦ 여기서는 최적화 이슈에 집중되서 설명되어 있다.
◦ 이른 최적화를 피하고, 복잡함의 정도(Big-O 복잡성)를 분명하게 지켜봐야 한다.
◦ 미래를 대비하고 싶다면 데이터 베이스, 처리량, 전송량, 더 많은 픽셀과 창 등을 고려해야 한다.
◦ 데이터의 크기가 처리에 문제가 생길 정도로 늘어날 것을 확신하지 않는 이상 그에 따른 알고리즘 사
용하지 마라
◦ 규모가 작은 알고리즘을 사용하는데 얻을 수 있는 이익(명확성, 간결성)이 없다면 크기를 늘리는데
주저하지 말 것
◦ 최적화 이외에도 ‘언제, 어떻게’를 사용할지 파악하는 것은 중요하다.
◦ 미래를 대비하기 위해 불필요하게 기능이 커지면 안된다.
2023-01-11
디자인 스타일
◦ 하나의 엔티티에는 하나의 역할만을 부여하자
◦ 한번에 하나에만 집중하자. 잘 정의된 하나의 역할만 부여하라.
◦ 여러 역할을 가진 엔티티는 사용하기에 힘들다.
◦ 디자인, 구현이 힘들어진다.
◦ 유지보수하는데도 어려움이 생긴다.
◦ 저수준의 추상화 단계로부터 고수준의 추상화로 빌드하는 것이 좋다.
◦ 여러 저수준의 추상 엔티티를 모아 큰 저수준 엔티티로 만드는 것은 피해야 한다.
◦ 정확성, 간결성, 명확성을 먼저 생각하라
◦ KISS(Keep It Simple Software)
◦ 변경하기 쉽게, 명확하며 관리가 쉽게 하는 것
◦ 빠른 프로그램을 정확하게 만드는 것보다 정확한 프로그램을 빠르게 만드는 것이 쉽다.
2023-01-11
디자인 스타일
◦ 이른 최적화를 피해라
◦ 코드가 복잡해지고 읽기 힘들게 만든다.
◦ 깔끔한 코드는 수정도 쉽고, 읽기도 쉽고, 이해하기도 쉽고, 최적화하기도 쉽다.
◦ 최적화한다고 무조건 빨라지지 않는다.
1. 코드의 속도와 크기만 따지고 병목 현상을 찾는 것은 힘들다
2. CPU의 경계 외부에서 이루어지는 작업이 많다
◦ 최적화를 한다고 판단했을 때 다음과 같은 순서로 이루어져야 한다.
1. 알고리즘의 최적화
2. 모듈화와 캡슐화
3. 최적화의 이유가 무엇인지, 어떤 알고리즘을 사용할지
◦ 미리 최적화할 부분도 필요하다
◦ 데이터가 크기가 큰데 값 복사로 전달
◦ 접두 ++, --연산자가 아닌 접미 ++, --연산자를 사용하는 경우
◦ 값의 할당 부분을 초기화 목록에 넣지 않고 생성자 함수에 넣는 경우
◦ 이동 생성자 문제
2023-01-11
디자인 스타일
◦ 전역 데이터와 공유 데이터를 최소화 하라
◦ 공유는 분쟁을 불러일으킨다. 공유 데이터, 특히 전역 데이터를 줄여야 한다.
◦ 각 코드 조각의 정확도를 떨어뜨리기 때문에 단위 테스트를 어렵게 만든다.
◦ 데이터의 변화에 따라 다른 부분에 영향을 주기 때문에 안정성 또한 좋지 못하다.
◦ 전역, 네임스페이스 범위, 또는 정적 클래스 개체가 필요한 경우에는 각 개체의 초기화를 신중하게 수행
해야 한다.
◦ 초기화가 컴파일 단위에 따라 달라진다.
◦ 평생성을 해치고, 성능과 확장성 부분의 병목 현상을 일으킬 가능성이 있다.
◦ 위험성 기준
◦ 전역 변수(객체) > 싱글턴 > 힙메모리
2023-01-11
디자인 스타일
◦ 정보를 숨겨라
◦ 추상화를 제어하는 호출 코드와 추상화의 임플리먼테이션 사이의 의존성을 최소화 하기 위해서는 내부
데이터를 숨겨야한다.
◦ 정보를 숨기면서 얻는 이득
◦ 변경 내용이 내부에 국한된다.
◦ 외부의 접근을 방어한다.
◦ 반대의 경우
◦ 해당 변수 혹은 속성의 예외처리, 변경이 힘들어진다.
2023-01-11
디자인 스타일
◦ 안전한 공유를 위한 코딩 시기와 방식을 결정하라
◦ 다중 스레드나 프로세스를 이용한다면, 공유 개체를 최소화 할 수 있는 방법과 올바르고 안전한 공유를
위한 시기를 알아야 한다.
◦ 타겟 플랫폼의 문서를 참고하라
◦ 플랫폼의 기본 기능들을 자체적인 추상체에 포함시켜라
◦ 사용하고 있는 타입이 멀티스레드 프로그램에서 안전한지 확인하라
◦ 자체적인 타입을 만든다면 다음 두가지를 해줘야 한다.
◦ 잠금 메커니즘 없이 서로 다른 스레드가 그 타입의 개체를 사용할 수 있어야 한다.
◦ 서로 다른 스레드에서 같은 개체를 사용할 경우에 어떤 과정이 필요한지 명시해두어야 한다.
2023-01-11
디자인 스타일
◦ 자원을 개체가 가지게끔 하라. RAII와 스마트 포인터를 활용하라
◦ RAII(Resource acquisition is initialization, 자원 획득은 곧 초기화이다.)
◦ 각 대칭되는 기능을 생성자 소멸자에 넣음으로서 완벽히 관리할 수 있게 해준다.
◦ 스코프 락
◦ 스마트 포인터
◦ RAII를 구현할 때 복사와 할당 과정에 유의해야 한다.
◦ 모든 자원은 객체가 가지고 있게 하자
2023-01-11
코딩 스타일
◦ Const를 사용하라
◦ Const를 붙임으로서 함수 내에서의 용도가 명확해진다.
◦ Const를 붙이기 시작하면 const로 지정되지 않은 부분과의 함수 호출 교루가 있을 때에는 그 부분을 const로 만들어버리는 상황이 발생한다.
◦ 다만, 반대로 const를 안 붙이는 경우면 붙이기가 힘들어진다.
Ex) const 객체로 받았는데 값이 안 바뀌는 함수임에도 함수 const가 안 붙었을 경우
◦ 값에 의한 전달에는 const를 붙이지 말도록 하자.
◦ 매직 넘버를 사용하지 말자
◦ 프로그램의 이해도를 떨어뜨리고 관리를 힘들게 한다.
◦ 나중에 const, enum으로 변경하기 힘들어진다.
◦ PutUI(x + 32 + 11, y + 20 + 1);
◦ 너무 긴 함수와 많은 중첩 구조는 피하라
◦ 이해하기 힘들고, 관리를 힘들게 하는 주범
◦ 해결 방안
◦ 묶기를 선호하라
◦ 반복하지 말라
◦ &&을 활용하라
2023-01-11
코딩 스타일
◦ 가능하면 로컬 변수를 선언하여 사용하라
◦ 컴파일 단위 사이의 초기화 의존성을 없애라
◦ 전역, 공유 데이터 최소화 해야 되는 이유와 같다
2023-01-11
함수와 연산자
◦ 값, 포인터, 참조 중 적절한 방식으로 인자를 얻어라
◦ 입력 인자
◦ 입력의 용도로만 사용되는 인자의 경우는 포인터와 참조에 대해 const 속성을 부여하는 것이 좋다.
◦ 값에 의한 복사가 용이한 기본 타입과 값 개체를 사용하는 것이 좋다.
◦ 다른 사용자가 정의한 타입을 받아들일 때는 const로의 참조 방식을 사용하자.
◦ 함수에서 인자의 복사가 이루어지는 경우에는 참조보다는 값에 의한 전달을 사용하자.
◦ 이러한 방식은 컴파일러가 임시본을 최적화하는데 도움을 준다.
◦ 출력, 입력/출력 인자
◦ 선택적으로 사용되는 인자, 함수가 포인터의 복사본을 저장 혹은 인자의 소유권을 관리하는 경우에는 포인
터에 의한 전달
◦ 인자가 반드시 필요한 경우, 함수가 포인터를 저장하지 않고 소유권이 아무런 영향을 미치지 못할 때는 참
조에 의한 전달이 적절하다.
◦ 함수 인자의 처리 순서에 좌우되는 코드는 좋지 않다.
◦ 어떤 값이 넘어오는지 파악하기 힘들거나 못할 수 있다.
2023-01-11
생성과 파괴 그리고 복사
◦ 생성자 내에서 할당 대신 초기화를 사용하라
◦ 멤버 초기화 리스트에서 초기화 하는 것이, 보다 명확하게 의도를 드러내주고, 더 간결하고 빠르다.
◦ 생성자 함수 내에서 하는 초기화는 초기화가 아닌 값 할당이다.
◦ 디자인에 따라서 사후 생성자(초기화 함수)가 필요한 경우도 있다. 그에 대한 대처 방법은 다음과 같다
◦ 차례를 알린다
◦ 늦은 사후 초기화
◦ 가상의 기반 클래스 사용
◦ 팩토리 함수 사용
◦ 일관된 방식으로 복사하고 제거하라
◦ 복사 컨스트럭터나 복사 할당 연산자 중 하나를 만든다면, 다른 하나 역시 만들어야 한다.
◦ 복사 함수를 직접 만든다면 디스트럭터 역시 만들어야 한다.
◦ 디스트럭터를 직접 만든다면 복사 기능 역시 만들어야 한다.
◦ 복사 허용 여부는 명확하게 지정하라
◦ 사용을 안 할 경우
◦ 11 이전 : 복사 생성자를 private로 선언 후 미구현
◦ 11 이후 : delete 키워드 사용
◦ 직접 만들 경우
◦ 컴파일러가 만들어지는 암시적인 복사 생성자를 사용할 경우
2023-01-11
네임스페이스와 모듈
◦ 타입과 그의 비멤버 함수는 같은 네임스페이스 내에 넣어라
◦ 공용 멤버 함수와 비멤버 함수는 함께 클래스의 공용 인터페이스를 형성한다. 인터페이스의 정의는 이
렇다. X라는 클래스가 있을 때, X에 대해 ‘진술하는‘ 모든 함수와 X와 같은 네임 스페이스에서 X와 ‘함께
제공되는’ 모든 함수는 X의 인터페이스를 이루는 것이기 때문에 논리적으로 X의 일부라는 것이다.
2023-01-11