"최근에 장비 제어 개발 및 코딩에 대한 조언 몇가지"라는 제목으로

http://ictlab.tistory.com/304 에 글이 게시되었다.

트위터에서 @ofalv (SungRyoul Lee, 이성열) 님이 올려주셨다.

대부분 동의가 되는 훌륭한 tip이다.

하지만, 몇가지는 동의가 안되어 내 의견을 말하고,
동의가 되는 부분에도 일부 첨언을 하고자 한다.

==== 아래 원본 글은 굵은 검정색, 첨언한 부분은 ==> 빨강색이다. ===

●●● 장비 제어 개발 및 코딩에 대한 조언 몇가지 ●●●

장비 제어 SW 개발과 관련된 특수한 환경이 있기 때문에 , 일반적인 소프트웨어 개발과는 다른 점이 있을 수 있습니다.

◆  디버거의 사용은 최소화 하고 로그를 적극 활용하라 . 장비가 동작중일때는 디버거를 사용할 수 없고 문제 생길때마다 디버거에 의존하다 보면 소스 코드 분석 능력이 떨어지게 된다.

==> 로깅은 디버깅 방법이 아니며, 시스템을 관찰하기 위한 방법이다. 로깅을 디버깅을 위한 (보조) 도구로 사용하면 소스가 지져분해셔서 읽기 어렵고, 읽고 싶지 않은 소스가 되기 쉽상이다.
==> 디버거는 언제나 우리의 친구이다. 일단 가능한 모든 범위의 테스트와 디버깅은 가상 환경에서 디버거를 사용해서 진행한다. 실제 환경에서는 현실적으로 디버거를 이용할 수 없는 경우도 많은데, 가능하면.. 타겟시스템의 하부에 디버깅 모듈을 담아 원격 SW 디버깅이 가능한 환경을 구축해야 한다. 또 JTAG (BDM), ICE를 사용할 수 있다면 주저없이 사용하여 생산성을 높혀야 한다.
==> 디버거와 소스코드 분석 능력과는 상관이 없다. 소스코드는 '정갈하게' 유지해야하는 회사의 자산이므로, 완전 심하게 관리하고 Inspection을 하여 깨끗한 코드를 만들어야 한다.

◆  구조를 잡거나 조건을 생각할때는 나무를 보지 말고 숲을 보라. 코딩을 할때는 숲을 보지 말고 나무를 보라.

◆  고객사 담당자가 원하는것을 얘기하면 원하는대로 해주려고 하지 말고, 그 기능을 원하는 진짜 이유를 먼저 생각해 보고 근본적인 원인을 찾으려고 노력하라

◆  고객사 담당자가 원하는 조건을 얘기하면 그 조건만 생각하지 말고 기존의 조건과 그것을 포함하면서  핵심을 관통할 수 있는 가장 단순하고 공통된 조건을 찾아서 적용하라

◆  한가지를 수정하면 10가지의 문제가 생긴다. 한가지 기능을 추가하면 기존의 10가지 기능에서 문제가 발생할 수 있다.  CheckBox 옵션 한가지는 모든 경우의 수를 2배로 늘어나게하고 버그의 가능성을 2배로 늘린다.

==> 설계와 코딩은 분리된 것이 아니다. 기본적으로 요구사항에서 실제 구현까지 위의 관찰은 매우 유용하며, 그 대책은 언제나 전체를 보면서, 모듈 단위의 또 통합한 상태의 TEST 계획을 올바르게 만드는 것이다.
==> TEST 방법이 없는 요구사항은 요구사항이 아니며, 요구 사항의 증가에 대한 걱정이 TESTing 방법이 고려된 기능으로 정의되는 것이 매우 중요하다.

◆  같은 장비의 실행파일이 고객사 요구에 따라  2개로 분리되고 소스 코드를 개별 관리하기 시작하면 코딩 업무량은 1.5배로 늘고, 유지보수비와 버그는 2배로 늘어난다.

==> 소스의 개별 관리는 언제나 큰 도전이다. 하지만 적절한 버전 관리, 형상 관리 도구를 이용한 소스 브랜치 관리를 사용하고, 모듈의 변경에 따른 단위 테스트(실제 장비가 아닌 환경에서)를 자동화하는 방식으로 그 비용을 최소화 할 수 있다.

◆  신규 드라이버는 처음 설치 후 바로 양산 장비에 적용하지 말고 , 1대에서 충분한 테스트를 하라.

◆  프로그램을 배포할때는 실행파일만 배포하지 말고 , 버전 업 되면서 필요한 파일이 추가 되었는지 한번 더 생각하고 배포 하라.  고객사 담당자가 프로그램을 받아서 장비PC에 복사까지 했는데.. 실행조차 안되는 문제가 발생하는것은 가장 짜증나는 일 중에 하나이다.

==> Deliverables를 만드는 방식은 반드시 수동이 아닌 스크립트 또는 적절한 도구를 이용하여 TEST하고, 그 스크립트 또는 Configuration도 버전 관리의 대상이다.

◆  핵심적인 조건, 시퀀스, 데이터는 반드시 로그를 남길수 있도록한다. 특히 예외 상황으로 빠지는 조건에서는 무조건 로그가 남아 있게 한다. 동시에 로그 데이터는 최대한 적게 남도록 쓸데 없는 로그는 항상 정리하는 습관를 들이자

◆  UX 디자인의 기본은 사용자에 대한 배려심이다.

◆ 조건문을 만들때는 조건의 내용을 읽어가면서 이해가기 쉬운 어순으로 배열하라.

◆ 조건문은 조건들 중에서 가장 큰 대전제가 되는 조건을 우선 배열하고, 비슷한 레벨이면 가장 참(true) 이 되기 어려운 조건을 먼저 배열하라.

◆  전체 부정 !을 사용하는 조건문은 만들지 않는다.

GOOD : if( A==false && B==false && C==false)
BAD : if( ! (A || B || C ) )  : 코드는 짧지만 읽기가 어렵다.

◆  조건문의 비교식에서는 앞쪽에서 가변값(비교항목)을 넣고 뒷쪽에 상수(또는 기준값)을 넣는다.

GOOD : if ( A > 2 )
BAD  : if ( 2 < A ) :   조건문 읽기가 부자연스럽다.

==> 위의 조건문과 관련된 내용은 아주 옳은 말씀이다. 이런 내용을 포함한 소스 작성 방식은 회사의 Coding Convention으로 정리되어야 하며, 가능하면 모든 소스가 Static Code Analysis 도구에 의해 commit 될 때마다 분석되어야 하고, 반드시 주기적인 소스 리뷰로 걸러지고, 사내의 convention으로 유지되어야 한다.

◆  포인터를 리턴하는 함수에서 에러의 경우에는 NULL을 리턴하지 말고 , Dummy 데이터의 포인터를 리턴하라 . 프로그램 죽는것을 방지할수 있다. 대신 로그 기록은 필수 !  (Dummy데이터는 글로벌 더미 데이터 )

==> 함수의 리턴값에 대한 확인 등은 Source Inspection(리뷰) 과정에서의 필수 check item이다. 함수 내에서 발생한 에러는 그 안에서 인지되고 함수를 호출한 쪽에서 반드시 함수의 결과를 확인하고 처리해야하는 것이다.
==> 제시한 방식은 TEST의 부실을 cover하는 방법으로 제시된 듯하지만, 절대 정답이 아니다. 철저한 리뷰와 TEST가 우선이다. 더미데이터가 시스템을 죽게하지는 않지만 결국 대형사고를 만든다. 우선 소스 리뷰를 하고 assert()를 이용한 단위 TEST, 통합 TEST를 사전에 심하게 해야한다.
==> 통상 임베디드 시스템에서 이런 일의 발생이 로그에 기록된다해도 시스템이 죽거나 고객의 요구가 있기 전까지 로그를 확인할 가능성은 없으며, 로그는 원래 완벽한 정보를 제공하지 않기 때문에, 그 문제가 발생한 상황에 대한 인지는 시스템의 로그저장 공간 크기에 따라, 가능할 수는 있지만, 사후 디버깅에도 충분하지 않는 경우가 많다.

◆ XEdit를 추가할때는 항상 적당한 기본값(Default Value) 을 설정한다.

◆ 저장 하지 않고 화면을 빠져 나올때는 항상 데이터가 원상복귀 하도록 한다.

◆  고객사 담당자의 요구를 너무 쉽게 들어주다 보면 , 그것을 당연한 것으로 생각하게 된다.

==> 고객사의 요구를 들어줄 때는 항상 그에 대한 작업을 수행하는데 어떤 절차와 시간이 소요되는지, 어떤 다른 기능의 구현이 그것 때문에 늦어질 예정인지, 전체 일정이 어떻게 바뀔지를 반드시 데이터를 가지고 설명해야 한다. 어떤 고객은 그런 데이터에 기반한 설명을 무시하기도 하지만, 요구가 어떤 비용을 발생하는지는 알고 있는 것은 고객사에게도 가능한 RISK를 준비할 수 있도록 할 뿐만 아니나 개발사에게도 중요한 역량이다. 따라서 기능과 그 기능의 구현 시간, 개발자들의 코드 생산 능력을 항상 모니터링을 해야 하며, 그 능력은 결국 고객을 설득하고 갑을 관계에 긍정적인 영향을 끼친다.

◆  중복 코드가 만들어지는 순간 바로 함수로 만들어라! ( CTRL+C , CTRL+V를 하기 전에 함수로 모듈화 할수는  없는지 다시한번 생각하라 )

==> 당연하다. 지금 업계의 많은 임베디드 시스템 소프트웨어 개발자들은 소프트웨어 전공자(차근히 소프트웨어를 배운 사람)이 아니다. 우선 중복해서 사용하는 기능이 있다면, 표준 함수나, 라이브러리가 있는 것인지 먼저 확인해야 한다.

◆  Include Path 옵션은  C++빌더 전체 옵션에 넣지 말고 개별 프로젝트 옵션으로 넣어라

==> 당연하다. 중요한 것은 프로젝트 옵션도 버전관리의 대상이라는 점이다.

◆  모든 개발 프로젝트는 중반 이후에는 출구 전략을 생각하라 . 언제까지나 한 프로젝트에만 매달리면 그 프로젝트는 완벽해질지 모르지만 회사는 망한다.

==> 출구라는 것이 뭔지 잘 모르겠지만, 고객이 원하는 것을 만족시키지 못하면 출구는 없고 다른 입구도 없다. 고객을 만족시키거나, 고객이 만족하도록 설득해야한다. 우리가 하고 있는 일이 뭔지를 고객이 알도록 해야하며, 그 알리는 방법은 고객사와 프로젝트 초기에 협의가 있어야 한다. 소프트웨어 개발에 있어 개발 프로세스라 함은 우리 내부 그리고 고객과의 통신 방법을 의미한다.

◆  로그 내용  자체에 함수이름을 쓸때는 괄호()를 사용하지 말자. 코드중에서 함수를 검색하고 싶을때 로그 내용까지 너무 많이 검색되서 불편한 경우가 있다

GOOD  : LOG_PRINTF(“”, “DoFunc함수 실행 ")
BAD: LOG_PRINTF(“”, “DoFunc() 실행 ")

==> 함수이름, 파일이름, 라인 번호 등을 로그에 남기고 싶을 때가 많은 데, 그 이름/번호를 직접 사용하면 이식성이 심하게 떨어지고, 나중에 보면 잘못된 정보가 로그에 남게된다. 위 방식은 일견 의미있는 관찰이다. 소스를 작성할 때 에디터의 기능을 효과적으로 이용할 수 있도록 하는 것은 반드시 고려해야할 내용이다. 하지만 위의 특정한 예에서는 ... C 컴파일러의 표준에 따라, 컴파일러에 따라 조금씩 다르지만, __FILE__, __LINE__, __FUNCTION__  또는 __func__ 매크로가 있다. 이런 predefined 매크로는 소스의 이식성이 매무 높혀준다. 함수이름이 바뀌거나, 파일명이 바뀌거나, 라인이 바뀌어도..

◆ 기능을 추가할때는 항상 기존의 데이터와 호환이 가능한지를 먼저 생각해보고, 이미 납품되어 양산중인 장비에 적용했을때 문제가 없을지를 항상 생각하라

◆ 시퀀스 동작에 문제가 발생했을때는 그 문제가 발생할수 있는 명확한 타이밍과 시나리오를 찾을때까지는 만족하지 마라

* 이상

반응형
Posted by hl1itj
,