반응형
이번에 소개할 표현은 "Brownfield Project"입니다. "Brownfield Project"는 이미 존재하는 레거시 시스템이나 기존 코드베이스를 개선하거나 통합하는 프로젝트를 가리키는 표현입니다. 마치 건물이 이미 들어선 오래된 개발지(brownfield)를 재개발하듯, 기존 시스템 위에 새로운 기능을 추가하거나, 현대적인 기술 스택으로 전환하는 등 변화를 주는 상황을 의미합니다.1. 의미"Brownfield Project"는 백지 상태에서 시작하는 Greenfield Project와 반대되는 개념입니다. 여기서 개발 팀은 이미 구축된 인프라나 레거시 코드, 기존 설계 제약사항, 운영 중인 시스템 등 다양한 역사적 요소를 안고 출발합니다. 이 때문에 단순한 초기 설계 자유도는 낮을 수 있지만,..
지금까지 이 시리즈를 통해 C++ 표준이 어떻게 발전해 왔는지, 그리고 그 과정에서 왜 오래된 구현이나 관용구를 버려야 하는지를 살펴보았습니다. auto_ptr부터 시작해, C-Style 배열, 매크로 상수, 전통적 for 루프, C-Style 문자열, printf, SFINAE 트릭, 구식 함수 객체와 std::bind, 직접 스레드 관리, 직접 구현한 알고리즘까지 — 이 모든 레거시 패턴들이 모던 C++에서는 훨씬 더 나은 대안으로 대체되고 있습니다.C++20 이후로 언어와 라이브러리는 더욱 풍부해졌습니다. std::unique_ptr로 명확한 메모리 소유권을 관리하고, std::array와 std::vector, std::span으로 컨테이너를 안전하게 다루며, constexpr와 enum clas..
과거 C++98/03 시절에는 표준 라이브러리가 제공하는 알고리즘도 제한적이었고, 특정 요구사항을 만족하기 위해 개발자가 직접 알고리즘을 구현하거나, 반복자 기반 STL 알고리즘을 복잡하게 조합해야 하는 경우가 많았습니다. 또한 병렬 처리나 고성능 연산을 위해서는 플랫폼별 스레드 관리나 OpenMP, TBB 같은 서드파티 라이브러리에 의존해야 했습니다.모던 C++20에서는 Ranges 라이브러리를 통해 알고리즘 파이프라인을 선언적으로 구성할 수 있으며, 병렬 알고리즘 지원을 통해 표준 라이브러리 레벨에서 병렬화를 쉽게 도입할 수 있습니다. 이렇게 하면 코드 가독성과 유지보수성이 대폭 개선되며, 성능 향상을 위한 병렬화도 간단히 적용할 수 있습니다.관련 참고 자료:C++20 RangesParallel al..
과거 C++98/03 시절, 멀티스레딩을 구현하기 위해서는 운영체제별 API(pthread, Win32 threads 등)를 직접 호출하거나, Boost Threads와 같은 서드파티 라이브러리에 의존해야 했습니다. 이는 코드 이식성을 저하시켰고, 스레드 생성, 종료, 동기화 관리가 번거롭게 이루어지는 경우가 많았습니다.C++11 이후 표준 라이브러리에 std::thread, std::mutex, std::lock_guard, std::async 등 기본적인 멀티스레딩 기능이 도입되었고, C++20에서는 std::jthread와 중단 요청(stop token) 메커니즘이 추가되어 스레드 관리가 더 단순해졌습니다. 또한 C++20 코루틴(coroutine)을 활용하면 비동기 처리를 더 간결하고 직관적으로 ..
과거 C++98/03 시절에는 함수 객체(function object) 클래스를 직접 정의하거나, std::bind를 통해 함수 호출을 커스터마이징하는 패턴이 흔했습니다. 하지만 이러한 방법은 코드가 장황해지고 의도를 분명히 드러내지 못하는 경우가 많았습니다. 호출 대상이 어디에 있는지, 어떤 인자를 바인딩했는지 일일이 추적해야 했으며, 이는 코드 가독성과 유지보수성에 악영향을 끼쳤습니다.모던 C++에서 이 문제를 해결하기 위해 람다(lambda) 표현식과 std::function을 사용할 수 있습니다. 람다는 익명 함수 객체를 간결한 문법으로 정의할 수 있고, 캡처를 통해 외부 변수를 자연스럽게 접근할 수 있습니다. 또한 std::function은 범용 함수 포인터 래퍼로, 다양한 호출 대상(람다, 함..
과거 C++ 템플릿 프로그래밍에서 타입 제약을 표현하기 위해 사용되던 기법 중 하나가 바로 SFINAE(Substitution Failure Is Not An Error)였습니다. 이는 템플릿 인자의 대입 과정에서 타입이 맞지 않을 경우 에러 대신 다른 오버로드를 시도하는 기법으로, 조건부로 템플릿을 선택하는 메타프로그래밍 트릭이었습니다.그러나 SFINAE는 코드가 복잡해지고, 컴파일 에러 메시지가 난해해진다는 단점이 있었습니다. 모던 C++20에서는 Concepts를 통해 이 문제를 해결했습니다. Concepts는 템플릿 인자에 대한 명확한 제약 조건을 선언적으로 표현할 수 있어 코드 가독성과 유지보수성, 그리고 에러 진단을 크게 개선합니다.관련 참고 자료:SFINAEConcepts (C++20)과거:..
과거 C++98/03 시절, 문자열 형식 지정 출력은 주로 C 표준 라이브러리 함수를 이용했습니다. printf 계열 함수들은 간단히 사용할 수 있지만, 타입 미스매치 문제나 서식 문자열 관리가 번거로운 단점이 있었습니다. 예를 들어 %d, %f, %s 등의 포맷 지정자가 실제 매개변수와 불일치할 경우 런타임 버그가 발생할 수 있으며, 이는 디버깅하기도 까다롭습니다.모던 C++에서는 이러한 문제를 해결하기 위해 C++20부터 std::format 함수를 도입했습니다. 이는 타입 안전하고, Python의 f-string과 유사한 형식 지정 문법을 제공하며, 가독성과 유지보수성을 크게 향상시킵니다.관련 참고 자료:std::format (C++20)과거: printf 계열 함수의 문제점printf는 서식 문자..
과거 C++98/03 시절에는 문자열 처리를 위해 C-Style 문자열(char*)을 직접 다루는 경우가 많았습니다. 그러나 C-Style 문자열은 널 종단 문자('\0')를 통해 문자열의 끝을 인식하고, 이를 다루는 과정에서 범위 초과, 메모리 누수, 버퍼 오버플로우 같은 위험이 상존했습니다. 또한 문자열 조작을 위해 std::strlen, std::strcpy 등 C 표준 라이브러리 함수를 반복적으로 사용하는 것은 번거롭고 오류를 내기 쉬운 방식이었습니다.모던 C++에서는 이러한 문제를 해결하기 위해 std::string과 C++17 이후의 std::string_view를 활용할 수 있습니다. 이로써 문자열 처리가 안전하고 직관적이며, 성능까지 고려한 형태로 진화했습니다.관련 참고 자료:std::st..
초창기 C++에서는 컨테이너를 순회하기 위해 전통적인 for 루프나 반복자(iterator)를 명시적으로 사용하는 패턴이 흔했습니다. 이런 방식은 인덱스나 반복자 관리에 번거로움이 있었고, 컨테이너 타입이 바뀌면 루프 조건을 바꾸는 등 유지보수가 어려웠습니다.모던 C++에서는 이러한 문제를 해소하기 위해 range-based for 루프와 C++20 Ranges 라이브러리가 등장했습니다. range-based for 루프를 통해 컨테이너 순회를 단순화하고, Ranges 라이브러리를 사용하면 필터링, 변환 등의 파이프라인 스타일 알고리즘을 선언적으로 표현할 수 있습니다. 이로써 코드 가독성과 유지보수성이 크게 향상됩니다.관련 참고 자료:Range-based for loopC++20 Ranges 라이브러리과..
과거 C++98/03 시절에는 정적 상수를 정의할 때 매크로를 사용하는 경우가 흔했습니다. 매크로는 전처리 단계에서 단순한 텍스트 치환을 수행하므로, 타입 정보가 없고 디버깅도 까다롭다는 문제가 있었습니다. 또한 범위(scope) 개념이 없어 어디서나 무분별하게 확장되며, 심지어 이름 충돌 문제도 야기할 수 있었습니다.모던 C++에서는 이러한 문제를 해결하기 위해 constexpr, const 정적 상수, 그리고 enum class를 적극적으로 활용할 수 있습니다. 이를 통해 타입 안전성과 가독성을 향상시키고, 컴파일 시간 상수 평가를 통한 성능 최적화도 기대할 수 있습니다.관련 참고 자료:constexpr specifierenum class과거: 매크로 상수의 문제점C-Style 매크로를 통해 상수를 ..