버려진 Linux 시스템 최적화 도구 Stacer의 678개 커밋 분석을 통해 실제 앱 구조 설계 학습 기회 제공
Qt 기반 애플리케이션 아키텍처 분석: GUI 레이어와 OS 상호작용 레이어 분리 및 데이터 격리 아키텍처(Data Isolation Architecture) 적용 사례 확인
`/proc` 파일 시스템을 직접 읽어 시스템 상태를 파악하는 방식과 CPU 사용률 계산의 상태 저장(Stateful) 로직 분석
pkexec를 활용한 권한 상승 및 QSS와 INI 파일을 이용한 테마 변수 처리 등 실용적인 구현 기법 학습
Stacer는 GUI 레이어와 OS 상호작용 레이어를 명확히 분리하여 코드의 응집도를 높이고 재사용성을 확보함. `stacer-core`는 순수 C++ 라이브러리로 Qt의 Core와 Network 모듈만 의존하며, GUI 렌더링 관련 컴포넌트(Widgets, Charts 등)를 전혀 포함하지 않음. 이는 데이터 격리 아키텍처(Data Isolation Architecture)의 좋은 예시로, 링커(Linker) 수준에서 GUI 코드의 핵심 로직 침투를 원천 차단함. 또한, 핵심 로직을 Info, Tools, Utils 세 가지 동사 기반의 서브 디렉토리로 분리하여 각 계층의 책임(Responsibility)을 명확히 함.
시스템 모니터링 도구인 Stacer는 별도의 라이브러리나 데몬 대신 `/proc` 디렉토리 내 텍스트 파일을 직접 읽어 시스템 상태를 파악함. 예를 들어, CPU 코어 수는 `/proc/cpuinfo`의 `processor` 라인 수를 세고, 로드 에버리지는 `/proc/loadavg`의 첫 번째 필드를 파싱함. 이는 Linux 시스템의 기본적인 정보 노출 방식을 활용한 직관적인 접근 방식임. 다만, CPU 사용률 계산은 `/proc/stat`의 누적 티커(Tick) 카운터 간의 변화량을 측정해야 하므로, 상태 저장(Stateful) 로직이 필요하며 이는 동시 호출 시 문제를 야기할 수 있음.
Stacer의 `CpuInfo::getCpuPercent` 함수는 이전 CPU 티커 값을 `static` 변수에 저장하여 사용률 변화량을 계산함. 이 상태 저장(Stateful) 방식은 `top` 명령어와 같이 CPU 사용률을 실시간으로 추적하는 데는 유효하지만, 함수가 두 번 이상 연속으로 호출될 경우 첫 번째 호출에서 이미 변화량이 소진되어 두 번째 호출자는 잘못된 값을 받게 됨. 이는 단일 스레드 환경에서는 문제없으나, 동시성(Concurrency) 환경에서 예측 불가능한 버그를 유발할 수 있는 잠재적 위험 요소임. 해당 로직은 `/proc/stat`의 컬럼 의미를 주석으로 제공하여 후속 개발자의 이해를 도움.
Stacer는 시스템 최적화, 패키지 관리 등 루트(root) 권한이 필요한 작업을 수행하지만, 애플리케이션 자체는 루트 권한으로 실행되지 않음. 대신, `CommandUtil::sudoExec` 함수 내에서 `pkexec` 명령어를 호출하여 필요한 작업마다 개별적으로 권한 상승을 요청함. 이는 `sudo`를 직접 사용하는 것보다 안전하며, `pkexec`는 정책에 따라 권한 상승을 제어할 수 있음. `apt`나 `dnf` 같은 패키지 관리자 실행 시에도 동일한 방식을 적용하여 최소 권한 원칙(Principle of Least Privilege)을 준수함.
Stacer는 Qt Style Sheets (QSS)의 변수 부재 문제를 해결하기 위해, 각 테마별 `values.ini` 파일에 색상 코드 등을 정의하고 이를 QSS 파일에 문자열 치환 방식으로 적용함. `AppManager::updateStylesheet` 함수는 ini 파일의 키-값 쌍을 읽어 QSS 파일 내용에서 `@color01` 같은 플레이스홀더를 실제 색상 값으로 교체함. 이는 CSS 변수와 유사한 기능을 구현한 것으로, 테마 변경 시 단순히 다른 폴더의 리소스를 로드하는 방식으로 동작함. `setAccessibleName`을 QSS 선택자로 활용하는 점도 주목할 만함.
테마 변경과 같이 애플리케이션 전반에 영향을 미치는 상태 변화를 위젯들에게 효율적으로 알리기 위해 Stacer는 `SignalMapper`라는 전역 QObject를 사용함. 이 객체는 단순한 시그널 버스(Signal Bus) 역할을 하며, `sigChangedAppTheme()` 같은 시그널을 통해 테마 변경 사실을 브로드캐스트함. 이를 통해 개별 위젯이 `SignalMapper`를 구독하고 있다가 테마 변경 시 스스로 스타일을 다시 로드하도록 구현함. 이는 N개의 위젯 포인터를 관리하는 것보다 훨씬 깔끔한 이벤트 처리 방식임.