회사 '낡은' 컨벤션 vs 인터넷의 '신규' 트렌드

회사 '낡은' 컨벤션 vs 인터넷의 '신규' 트렌드

출근길에 본 글

지하철에서 Reddit 봤다. “Modern Embedded C Programming in 2024” 같은 제목. 클릭했다.

댓글에 누가 적어놨더라. “왜 아직도 헝가리안 표기법 쓰냐”, “typedef 남발은 90년대나 하던 거”.

웃겼다. 우리 회사 코드가 정확히 그거다.

회사 도착. 컴퓨터 켰다. 어제 푸시한 코드 리뷰가 떠 있다.

“변수명 규칙 지켜주세요. g_u8DataBuffer 이런 식으로요.”

헝가리안 표기법이다. 타입까지 변수명에 적는 거. C++이나 모던 C에서는 이미 안 쓴다는 게 정설인데.

10년 전 코드베이스

우리 회사 메인 프로젝트는 2014년에 시작됐다. 벌써 11년째다.

그때 정한 코딩 컨벤션을 아직도 쓴다. 파일 하나 열면 이런 식이다.

/******************************************************************************
 * File Name    : drv_uart.c
 * Description  : UART Driver Module
 * Author       : Kim XX
 * Date         : 2014.03.15
 * Version      : v1.0
 ******************************************************************************/

typedef unsigned char   UINT8;
typedef unsigned short  UINT16;
typedef signed char     INT8;

static UINT8 g_u8RxBuffer[256];
static UINT16 g_u16RxIndex = 0;

주석 박스. typedef로 타입 재정의. 전역변수에 g_ 접두사. 타입까지 변수명에.

2014년이면 이게 맞았다. 당시 임베디드 책들이 다 이렇게 가르쳤다.

문제는 2025년에도 이걸 쓴다는 거다.

신입이 작년에 들어왔다. 코드 보더니 물었다.

“왜 stdint.h 안 쓰고 typedef로 다시 정의하나요?”

답은 간단했다. “원래 그렇게 해왔어요.”

인터넷에서 본 트렌드

점심시간. Reddit r/embedded 들어갔다.

누가 올린 글. “Stop using global variables in embedded C”.

내용 읽어봤다. 전역변수 대신 구조체로 컨텍스트 만들고, 함수에 포인터로 넘기라는 거다. 테스트하기도 쉽고 재사용성도 좋다고.

댓글도 다들 동의한다. “2024년에 전역변수는 레거시”, “static 남발은 유지보수 지옥”.

맞는 말이다. 우리 코드 전역변수 천지다.

static uint8_t g_u8SensorData[10];
static bool g_bIsConnected = false;
static uint32_t g_u32Timestamp = 0;

파일 하나에 전역변수 30개 넘는 것도 있다. 어디서 바뀌는지 추적하려면 전체 검색 돌려야 한다.

GitHub에서 최신 프로젝트들 봤다. Zephyr, FreeRTOS 예제 코드들.

struct sensor_context {
    uint8_t data[10];
    bool is_connected;
    uint32_t timestamp;
};

void sensor_read(struct sensor_context *ctx) {
    // ...
}

깔끔하다. 컨텍스트 구조체 하나로 상태 관리. 함수는 순수하게 로직만.

개선 제안서 작성

저녁 먹고 돌아왔다. 생각했다. 제안서 써볼까.

PPT 켰다. 제목 적었다. “코드 컨벤션 개선 제안”.

슬라이드 3장 만들었다.

  1. 현재 문제점: typedef 중복 정의, 전역변수 과다, 헝가리안 표기법
  2. 개선안: stdint.h 사용, 구조체 기반 컨텍스트, 모던 C 네이밍
  3. 기대효과: 가독성 향상, 유지보수성 개선, 신규 인력 적응 빠름

레퍼런스도 달았다. NASA C Style Guide, Google C++ Style Guide, Linux Kernel Coding Style.

다음 날 팀장한테 보여줬다.

5분 봤다. 말했다.

“취지는 좋은데요.”

여기서 끝나면 좋겠는데.

“지금은 여유가 없어요.”

지금은 여유가 없다

팀장 말을 정리하면 이렇다.

“지금 프로젝트 일정 빡빡합니다. 양산 2달 남았어요. 코드 스타일 바꾸다가 버그 생기면 어떻게 할 건데요. 제품 나간 다음에 생각해봅시다.”

맞는 말이다. 양산 앞둔 시점에 대규모 리팩토링은 위험하다.

그런데.

2년 전에도 들었다. 그때도 “양산 끝나고”.

1년 전에도 들었다. 그때는 “다음 프로젝트 시작할 때”.

지금 또 들었다. “제품 나간 다음에”.

결국 안 바뀐다. 영원히.

이유는 간단하다. 임베디드는 항상 바쁘다. 양산 끝나면 다음 제품. 다음 제품 끝나면 또 다음.

여유라는 게 없다.

선배한테 물었다. 7년차.

“형, 우리 코드 스타일 언제부터 이랬어요?”

“내가 입사했을 때도 이랬어. 그때도 바꾸자는 얘기 나왔는데.”

“안 바뀐 거네요.”

“응. 계속 바쁘다고.”

실무와 이상의 간극

퇴근길. 생각했다.

인터넷에서 보는 건 이상적이다. 깨끗한 코드, 모던한 기법, 최신 트렌드.

실제 회사는 다르다. 레거시 코드, 빡빡한 일정, 리스크 회피.

누구 잘못도 아니다. 구조적인 문제다.

웹 개발자들 부럽다. 걔네는 배포하고 A/B 테스트하고 롤백한다. 실험할 수 있다.

우리는 못한다. 한 번 양산 나가면 끝이다. 펌웨어 업데이트 구조 없으면 그냥 그대로 간다.

리스크가 크니까 보수적이 된다. 보수적이니까 안 바뀐다.

악순환이다.

신입이 물어봤다. 어제.

“선배님, 학교에서 배운 거랑 너무 달라요. 전역변수 쓰지 말라고 배웠는데 여기는…”

할 말이 없었다.

“그냥… 익숙해져.”

작은 개선이라도

포기는 안 한다. 큰 개선은 안 돼도 작은 건 된다.

새로 작성하는 파일에는 stdint.h 썼다. uint8_t, uint32_t 이런 식으로.

리뷰에서 지적 안 들어왔다. 팀장도 그냥 넘어갔다.

“기존 코드랑 다른데요.”

“새 모듈이라 따로 뺐습니다.”

“음… 뭐 돌아가면 되지.”

승인 떨어졌다.

다음 파일도 그렇게 했다. 조금씩.

전역변수도 줄였다. 새 기능은 구조체로 만들었다.

struct ble_context {
    uint8_t rx_buffer[256];
    uint16_t rx_index;
    bool is_connected;
};

함수도 컨텍스트 받게 수정했다.

기존 코드는 못 고친다. 건드리면 테스트 다시 해야 한다. 시간 없다.

새로 짜는 것만이라도 깨끗하게. 이게 현실적이다.

10년 후엔

생각해봤다. 10년 후.

2035년. 나도 11년차가 돼 있다.

신입이 들어온다. 코드 보고 물어본다.

“왜 이렇게 작성했어요?”

나는 뭐라고 답할까.

“원래 그렇게 해왔어.” 이러고 싶지는 않다.

그렇다고 지금 당장 전부 바꿀 수는 없다. 현실이 그렇다.

타협점을 찾아야 한다. 레거시는 유지. 신규는 개선. 천천히.

10년 걸려서 바뀔 수도 있다. 어쩌면 안 바뀔 수도 있다.

그래도 시도는 한다. 포기하면 영원히 안 바뀐다.


회사 코드는 박물관이다. 신입은 적응한다. 나도 그랬다.