전체 글 26

On Golang: 구글이 만들면 다릅니다. - Things Are Different When Google Makes It -

On Golang: Things Are Different When Google Makes ItGo는 만능이 아닙니다. "Go는 백엔드 개발의 과도한 복잡성을 줄이는 선택지"를 '복잡성이 사라진다' 라고 "잘못" 받아들이는 경우가 있습니다.복잡성 보존 법칙https://en.wikipedia.org/wiki/Law_of_conservation_of_complexity [복잡성 보존의 법칙]https://pi-store.tistory.com/229 [테슬러의 법칙: 복잡성은 사라지지 않는다] 복잡도는 사라진 것이 아니라, 표현 위치가 바뀐 것입니다 과도한 복잡성이 아니라 현실 비즈니스 복잡성을 표현하기 어렵다는 것이 더 적절합니다. 따라서 Go언어는 복잡도를 없애는 게 아니라 프로세스, 패키지, DB, 외부..

카테고리 없음 2026.05.09

Zero-cost 추상화: C++17 if constexpr을 활용한 lock guard

요약TPSMeter에서 락 사용 여부를 런타임 bool로 판단하던 걸 → Non-type template parameter로 바꿔서 컴파일 타임에 결정되게 함if constexpr로 분기해서 런타임 오버헤드를 완전히 제거근데 중복 코드가 생기니까 → constexpr_lock_guard를 11줄로 만들어서 중복 제거std::monostate + RVO + 타입 추론 활용한 제로 코스트공수와 오용(misuse)을 줄이고 가독성을 높이면서도 기존 방식 대비 약 5.1배의 성능향상 시작C++17에 도입된 if constexpr은 기존의 const 보다 더 나은 퍼포먼스를 제공합니다. constexpr은 컴파일 타임에 평가를 보장합니다. 따라서 constexpr로 사용된 if문으로 분기되는 런타임 오버헤드를 없..

카테고리 없음 2026.03.19

C++17: 스레드 안전한 자동 플래그: toggler-atomic

생각보다 현업에서 많이 사소하게 사용하는 게 bool flag입니다. 단순한 상태 저장용으로 쓰기 시작하지만 복잡한 루프나 멀티스레드 환경을 만나면 간단했던 플래그가 만만치 않게 됩니다. 또 상태 하나를 체크하기 위해 이전값과 같은지 수동으로 비교하고 값을 업데이트해주어야 합니다. 일반적인 Flag 사용bool is_active = false; // 이전 상태 저장용void on_receive_signal(bool status){ // 켜지는 시점 감지: "현재는 true인데, 이전엔 false였나?" if (status == true && is_active == false) { is_active = true; // 상태 수동 갱신 std::cout 생각보다 현업에서 사소하게 사용되는..

카테고리 없음 2025.12.23

OOP 언어가 아니다 ≠ 설계 원칙을 안 지켜도 된다

OOP는 객체지향 언어에서 출발한 설계철학이자 개념이겠지만, 십수 년 전부터는 모든 언어뿐 아니라 아키텍처 또한 OOP와 함수형 프로그래밍(FP) 등 여러 패러다임에서 공유되는 근본 원칙 [[경계 정의, 복잡도 격리, 명확한 계약]] 을 중심으로 발전되어 왔으며 클린아키텍처, DDD, DB설계 등 대부분의 소프트웨어/시스템 아키텍처에서 절차지향적 언어라도 동일한 개념으로 사용되어 왔습니다. 적용 범위(스케일)만 다르지 근본 원칙은 동일하다고 보는 것입니다.컨테이너 개념 또한 OOP와 유사한 원칙 위에 세워져 있습니다. (MSA 또한 OOP의 SRP를 시스템 레벨로 확장한 것이라 볼 수 있습니다.)OOP의 캡슐화, 추상화, 다형성 같은 원칙들은 "레벨"만 다를 뿐 본질은 동일소프트웨어 레벨: 클래스, 모듈..

카테고리 없음 2025.12.21

C++17로 진화하기: std::condition_variable의 안전한 랩핑

이전에 아래 내용을 C++11로 랩핑 하였는데요, std::condition_variable의 안전한 시그널링앞서 소개한 위 코드를 C++17로 다시 랩핑 하려 합니다. 특히 std::condition_variable에서의 C++11의 복잡했던 템플릿식이 C++ 17의 if constexpr문으로 훨씬 간결해지며, 덕분에 이해도 또한 월등히 쉬워졌습니다.아래 내용들은 이전 글에서도 다루었던 내용으로 이미 아는 내용이라면 아래 구현으로 이동하실 수 있습니다. std::condition_variable(pthread_cond계열 함수도 포함하여)은 OS에 관계없이 시그널 놓침(Lost wakeup)과 가짜 깨움(Spurious wakeup)이라는 동일한 문제를 가지고 있습니다. 이 두 가지를 해결하지 않..

카테고리 없음 2025.12.21

C++ 간결하고 안전한 숫자변환: to_number: 위험한 atoi 버리기

여기서 사용된 C++ 기법들더보기템플릿 관련- 함수 템플릿: `template` 로 타입별 함수 자동 생성- 템플릿 특수화: `template struct parser` 처럼 특정 타입에 대한 별도 구현- 비타입 템플릿 파라미터: `std::ios_base &(*in_type)(std::ios_base &) = std::dec` - 함수 포인터를 템플릿 인자로 사용컴파일 타임 기법- `static_assert`: 컴파일 타임에 잘못된 타입 사용 차단- `if constexpr` (C++17): 컴파일 타임 분기, 조건에 맞지 않는 코드는 아예 컴파일 안 됨- `std::conditional_t`: 조건에 따라 타입 선택 (메타프로그래밍)타입 트레이트 (Type Traits)- `std::is_arithm..

카테고리 없음 2025.12.16

C++ std::mutex보다 빠른 RCU(Lock-free) 라이브러리: cppurcu

C++ Lock-free library faster than std::mutex: cppurcu 읽기 작업이 많은 프로세스std::mutex멀티스레드 환경에서 특정 자료는 거의 읽기가 대부분 마스터 데이터와 같은 자료를 읽으려 할 때마다 단순하게는 std::mutex 또는 pthread mutex를 사용하여 다루는 데이터의 오염이나 크래시를 피해야 합니다. 간혹 생기는 업데이트 때문에 자료 접근 시의 모든 경우 lock을 사용해야 하는 것은 자원 낭비일 수 있습니다. thread_local이를 간단히 해결할 수 있는 방법 중에는 thread-local-storage를 이용해 또 다른 복사본을 만들어 놓는 방법이 있습니다. 이 경우 스레드마다 갖게 되는 복사본 때문에 메모리 사용율이 매우 높습니다. st..

카테고리 없음 2025.10.28

C++ 소프트웨어 아키텍쳐와 모델링

잘못된 소프트웨어 아키텍처에서의 모델링이 미치는 영향은 큽니다. 현실세계의 모델과, 소프트웨어 아키텍처가 가지는 모델의 괴리가 발생할 때, 요구사항·장애 분석·운영·대화에서 동일한 용어에 서로 다른 논리를 가리키는 문제가 반복됩니다. 데이터 정합성 검증과 기능 수정, 해석에서도 각자의 모델에 대한 불필요한 대화와 이해가 수반되어 작업의 지연과 장애가 발생하게 됩니다. 이런 불필요한 과정들은 이해 관계자 모두를 지치게 만드는 요인들입니다. by NoteboolLM 데이터베이스와 모델링데이터베이스 테이블 설계는 현실 세계의 정보를 데이터베이스에 저장하기 위해 체계적으로 구조화하는 과정입니다. 현실세계의 개념들을 식별하고 그 개체들 간의 관계를 파악하며 그 관계를 실제 데이터베이스에 맞도록 옮깁니다. 개념적..

카테고리 없음 2025.09.23

libcurl을 이용한 간단한 C++ SFTP Client

클래싱 포인트SFTPCurl / SFTPCurlTemplate 클래스를 정의해 libcurl 옵션 설정과 에러 처리 캡슐화CRTP(Curiously Recurring Template Pattern)을 사용해 템플릿으로 추상화, 파생 클래스를 정적으로 확장Fluent Interface (메서드 체이닝) 패턴을 사용하여 user(...).password(...).url(...) 와 같은 인터페이스 설계단일 책임 원칙(SRP)와 인터페이스 분리 원칙(ISP)을 적용하여 업로드, 다운로드 기능 클래스 분리예외 클래스(SFTPCurl::exception) 로 CURL 오류를 객체 지향적으로 처리프록시 패턴을 이용한 실행(perform())RAII를 활용한 스마트 포인터(unique_ptr)와 ScopeExit를 ..

카테고리 없음 2025.08.18

C++ UDP 수신 최적화: recvmmsg 캡슐화

UDP는 송수신 시 데이터를 패킷(덩어리) 단위로 주고받습니다. 따라서 UDP를 사용할 때는 여러 가지 위험 요소를 고려하여, 데이터 크기가 MTU(Maximum Transmission Unit)에서 IP 및 UDP 헤더 크기를 뺀 값을 초과하지 않도록 설계합니다. by NotebookLM UDP 소켓을 통해 데이터를 수신할 때는 일반적으로 다음과 같은 recvfrom 함수를 사용합니다:ssize_t recvfrom(int sockfd, void buf[restrict .len], size_t len, int flags, struct sockaddr *_Nullable restrict src_addr, ..

카테고리 없음 2025.07.19

C++ 멀티쓰레드: Read-Only 데이터셋의 업데이트와 락프리 접근

어플리케이션에서 흔히 볼 수 있는 코드 중 하나가 마스터 정보를 메모리에 두고 다수의 쓰레드가 검색하는 것입니다. 이런 Read-Only 데이터셋은 굳이 Lock을 만들 필요가 없습니다. 하지만 이 마스터 정보가 간헐적으로 업데이트된다면 하는 수 없이 Lock을 사용해야 하는데요,간헐적으로 일어나는 업데이트 때문에 다수의 쓰레드도 데이터셋에 접근시마다 Lock을 사용할 수밖에 없습니다. 이렇게 되면 싱글쓰레드에서 검색하는 게 오히려 더 빠릅니다. C++ std::mutex보다 빠른 RCU(Lock-free) 라이브러리: cppurcuC++ Lock-free library faster than std::mutex: cppurcu 읽기 작업이 많은 프로세스멀티스레드 환경에서 특정 자료는 거의 읽기가 대부분..

카테고리 없음 2025.07.18

C++17 템플릿 추론기능을 이용한 안전한 배열 복사

들어가며 모던 C++을 사용하지 않은 코드에서는 std::string이나 std::array보다는 문자 기반의 배열을 자주 사용합니다. 이러한 방식은 코딩 실수가 발생하기 쉬우며, 그로 인해 의도치 않은 동작이나 비정상적인 종료로 이어질 수 있습니다. 특히 구조체에 이런 배열을 십수 개 이상 선언하는 관습에서는, 배열 복사 과정에서 발생하는 오류를 찾기가 쉽지 않습니다. 테스트를 진행하더라도 오류가 발생한 지점에서 즉시 종료되지 않는 경우가 많기 때문에, 문제를 더욱 찾기 어렵게 만듭니다. 이러한 배열 복사는 오늘날 실무에서도 여전히 자주 사용되고 있습니다. 때문에 모던 C++을 잘 모르는 많은 개발자들은 아직도 배열을 하나하나 확인하는 고통을 받고 있습니다. :( 여기서는 모던 C++을 이용하여 자동..

카테고리 없음 2025.07.10

C++ std::list와 빠른 검색을 동시에: FindableList

실무에서는 누적된 순서가 중요한 경우가 많습니다. 이런 경우 순차정보를 유지하며 검색을 빠르게 해야 할 필요가 있습니다. 그럴 때마다 매번 순차검색을 할 수는 없습니다. 특히 멀티 쓰레드 환경에서 매 트랜잭션마다 수십 수백 번의 순차검색을 시도하게 된다면 기능 단위의 단일 테스트에서는 별일 없겠지만 대량의 트랜잭션이 일어나는 상황에서는 아주 치명적일 수밖에 없습니다. 여기서는 그러한 문제를 캡슐화하여 클래스로 해결하려 합니다. 즉, 순서를 유지하면서도 빠르게 검색할 수 있는 컨테이너 클래스를 구현하는 게 이 글의 목적입니다. 인터페이스먼저 어떻게 사용할지 만들어 봅니다.#include ....int main(void){ // 원소 타입을 받을 수 있도록 합니다. FindableList flist; ..

카테고리 없음 2025.07.09

C++ 멀티쓰레드 데이터 관리: 샤딩(Sharding)

멀티쓰레드 애플리케이션을 개발하다 보면 여러 쓰레드가 하나의 자료구조에 동시에 접근해야 할 때가 있습니다. 물론 thread_local을 떠 올릴수도 있지만 사용하지 못하는 대부분의 상황에서 std::mutex로 보호된 컨테이너에 동시에 접근한다면 오히려 단일 쓰레드보다 느려집니다. 이 문제의 핵심은 모든 쓰레드가 하나의 락을 두고 경쟁한다는 점입니다. 한 번에 하나의 쓰레드만 데이터에 접근하기 때문에 다른 쓰레드는 기다려야 합니다. 마치 은행에 창구가 하나밖에 없는 상황과 같습니다.샤딩은 이 문제를 해결하는 방법중 하나입니다. 하나의 큰 자료구조를 여러 개의 작은 조각으로 나누고, 각 조각마다 별도의 락을 사용합니다. 이렇게 하면 쓰레드들이 서로 다른 샤드에 접근할 때는 경합이 줄어 성능향상에 도움이 ..

카테고리 없음 2025.05.29

C++ 템플릿 활용: 실행인자 처리: getopt

C의 getopt는 프로그램에서 인자 호출 시 많이 사용합니다. 보통은 아래와 같이 사용하는데요, 이렇게 하면 인자 처리하는데 많은 코드 양과 다른 부분들이 뒤섞이면서 좀 복잡해집니다. 고전 C 스타일#include #include #include #include #include int main(int argc, char *argv[]) { int opt; int a_flag = 0, b_flag = 0, c_flag = 0; int a_value = 0; int b_value = 3; // 기본값 char c_value[256] = {0}; // 명령줄 인수 파싱 while ((opt = getopt(argc, argv, "a:b:c:v")) != -1) { switch ..

카테고리 없음 2025.05.16

C++ 유틸리티: TPS 측정과 SpinLock

프로젝트에 참여해서 일을 하다 보면 TPS를 측정해야 할 일이 종종 있습니다. 이미 프로젝트에 사용되던 TPS소스를 사용하려 했지만 사용이 쉽지 않았습니다. TPS측정 소스를 보면 시간별 버킷을 이용하는 게 일반적이고, 유독 이런 소스들을 보면 복잡도가 상당히 높은 경향을 보였습니다. 이건 사실 측정 방식의 문제와는 다른 문제 이긴 합니다. by NotebookLM 난해한 코드아래 코드는 어떤 회사에서 사용됐던 TPS 계산 코드입니다,더보기int get_TPS(vector& vecTPS, std::atomic& nCurSec, int nRef){ int nCurIndex = (nCurSec/(nRef*1000))%TPS_MAX_INDEX; int PreIndex = (nCurIndex+TPS_MA..

카테고리 없음 2025.05.12

C++ 강력한 동시성 제어(3) - BlockingQueue을 이용한 Logger

C++ 강력한 동시성 제어(1) - BlockingQueue의 이해C++ 강력한 동시성 제어(2) - BlockingQueue 구현C++ 강력한 동시성 제어(3) - BlockingQueue을 이용한 Logger 참조std::thread의 실전적 랩핑 - thread 클래스 구현std::condition_variable의 안전한 시그널링C++ Lockfree Queue 항상 좋은 선택일까? 아래와 같은 조건으로 간단한 Logger를 BlockingQueue를 이용해 만들어 보려 합니다.(다만 이전 링크에서 구현한 BlockingVector를 사용할 예정입니다.)로그는 로그 기록 순서대로 파일에 출력되어야 합니다.로그는 표준출력으로 출력합니다. (간단한 예제이므로)로그 기록은 별도 쓰레드에서 처리하도록 합..

카테고리 없음 2025.05.11

C++ 강력한 동시성 제어(2) - BlockingQueue 구현

C++ 강력한 동시성 제어(1) - BlockingQueue 이해C++ 강력한 동시성 제어(2) - BlockingQueue 구현C++ 강력한 동시성 제어(3) - BlockingQueue을 이용한 Logger 이 글에서는 이전 포스팅 "C++ 강력한 동시성 제어(1) - BlockingQueue" 에서 구현해야 할 BlockingQueue를 std::deque가 아닌 std::vector기반으로 구현합니다. 이 구현은 boost::lockfree::queue보다 빠르며 표준 라이브러리를 이용한 구현으로 안정성과 편의성(자유로운 데이터형식, 디버깅)이 높고 외부 의존성을 피할 수 있습니다. std::vector기반의 BlockingQueue 벤치마크는 "C++ Lockfree Queue 항상 좋은 선택일..

카테고리 없음 2025.05.11

C++ 람다 활용: 시그널 핸들링

고전적 시그널 처리 방법은 정적 함수를 만들고 signal함수를 통해 정적 함수를 등록해야 합니다. 시그널은 기본적으로 커널의 인터럽트를 통해 처리되므로 핸들링하기 위해서는 몇 가지 조심스럽게 처리해야 합니다. by NotebookLM 먼저 고전적인 시그널 핸들링 코드입니다.// 전역 함수로 시그널 핸들러 정의static void signal_handler(int signal_number) { std::cout 위와 같은 코드의 시그널이 처리되는 과정을 살펴보면 아래와 같습니다.시그널이 처리되는 과정(Linux)프로그램이 실행 중일 때 시그널이 발생합니다 (예: Ctrl+C로 SIGINT 발생)운영체제는 현재 실행 중인 쓰레드를 인터럽트합니다. 즉, 쓰레드가 실행 중이던 코드가 일시 중단됩니다.제어..

카테고리 없음 2025.05.08

C++ 강력한 동시성 제어(1) - BlockingQueue의 이해

C++ 강력한 동시성 제어(1) - BlockingQueue의 이해C++ 강력한 동시성 제어(2) - BlockingQueue 구현C++ 강력한 동시성 제어(3) - BlockingQueue을 이용한 Logger 멀티쓰레드 환경에서의 어플리케이션은 쓰레드간 데이터 교환을 안전하고 효율적으로 주고받아야 하며 이러한 생산자와 소비자의 속도를 조절하는 등 동시성 문제를 해결하는 데 대한 이해는 매우 중요합니다. 특히 BlockingQueue는 동시성 프로그래밍이 필요한 어플리케이션 개발에서는 꼭 알아야 할 지식이라고 할 수 있습니다. 동시성 문제를 해결하는 가장 대표적이고 효과적인 방법 중 하나이기 때문입니다. 국내에서 많이 사용되는 언어인 JAVA(java.util.concurrent.BlockingQueu..

카테고리 없음 2025.05.05