# FESA C++ Coding Style ## 목적 이 문서는 FESA production 및 test C++의 코드 스타일, 객체 설계, 문서화와 검증 규칙을 정의하는 project-local source of truth다. 새 C++를 작성하거나 기존 C++를 리팩터링하는 사람과 Implementation Agent는 작업 전에 이 문서를 읽어야 한다. [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)를 baseline으로 사용한다. 이 문서, `AGENTS.md`, 승인된 feature contract와 architecture/ADR이 Google guide의 일반 규칙보다 우선한다. ## 적용 범위와 우선순위 규칙 충돌 시 다음 순서로 해석한다. 1. 승인된 feature requirements, formulation, numerical-review, I/O와 reference contract 2. `AGENTS.md`, `docs/ARCHITECTURE.md`와 `docs/ADR.md` 3. 이 문서의 FESA-specific rule과 exception 4. Google C++ Style Guide 5. 기존 local style 새 코드는 이 문서를 즉시 준수한다. 기존 코드는 승인된 refactoring plan의 module slice 단위로 전환한다. 요청 범위 밖의 file을 style-only 이유로 함께 수정하지 않는다. ## Language와 Toolchain - Production language는 C++17 이상이며 MSVC x64를 지원해야 한다. - 승인된 build 기준은 CMake, Visual Studio generator와 Debug configuration이다. - C++ compiler extension에 의존하지 않는다. - MKL, TBB, HDF5와 Win32 type은 public solver core header에 노출하지 않는다. - Standard library와 RAII를 manual lifetime management보다 우선한다. - Google guide가 현재 권장하는 C++20 language target은 FESA의 C++17 contract를 바꾸지 않는다. ## File 이름과 Header - File 이름은 소문자 snake_case를 사용한다. - Production 및 test source extension은 기존 FESA/CMake 관례인 `.cpp`를 유지한다. - Header extension은 `.h`를 사용한다. 기존 `.hpp`는 승인된 migration slice에서 `.h`로 바꾼다. - Header는 self-contained여야 하며 include consumer의 transitive include에 의존하지 않는다. - Header는 `#pragma once` 대신 full repository path 기반 include guard를 사용한다. 예: ```cpp #ifndef FESA_MATH_VECTOR3_H_ #define FESA_MATH_VECTOR3_H_ namespace fesa { class Vector3 {}; } // namespace fesa #endif // FESA_MATH_VECTOR3_H_ ``` Include 순서는 다음과 같다. 1. 대응하는 header 2. C system header 3. C++ standard library header 4. Third-party header 5. FESA project header 각 non-empty group 사이에는 빈 줄을 두고 group 안에서는 알파벳순으로 정렬한다. 사용하는 symbol의 declaration을 제공하는 header를 직접 include한다. ## 이름 규칙 | 대상 | 규칙 | 예 | | --- | --- | --- | | class, struct, enum, alias | PascalCase | `ElementProperty`, `EntityIndex` | | function, method, accessor | PascalCase | `ComputeStiffness()`, `NodeCount()` | | local variable, parameter | snake_case | `element_index`, `source_order` | | class data member | snake_case + trailing `_` | `youngs_modulus_` | | struct data member | snake_case | `source_id` | | compile-time/static constant | `kPascalCase` | `kNodeCount` | | enumerator | `kPascalCase` | `FailureCategory::kModel` | | namespace | snake_case | `fesa::hdf5_internal` | | macro | UPPER_SNAKE_CASE | `FESA_MATH_VECTOR3_H_` | Google guide는 accessor의 snake_case를 허용하지만 FESA는 사용자 승인에 따라 production 및 test 호출부를 포함한 모든 function name에 PascalCase를 적용한다. Constructor, destructor와 operator 이름은 C++ language 규칙을 따른다. 이름은 물리 및 수치 의미를 드러내야 한다. `value`, `data`, `handler`, `manager`처럼 문맥이 없는 generic name을 넓은 scope에서 사용하지 않는다. Source label, internal entity index와 equation index를 이름에서 구분한다. ## Formatting - `.clang-format`의 `BasedOnStyle: Google`을 사용한다. - 들여쓰기는 space 2개이며 tab을 사용하지 않는다. - 최대 line length는 80자다. Include, guard, URL과 분할할 수 없는 contract string은 Google guide의 예외를 따른다. - Opening brace는 declaration/control statement의 마지막 줄에 둔다. - Namespace body는 들여쓰지 않고 closing namespace comment를 작성한다. - 한 statement에 한 declaration만 둔다. - Variable은 가능한 가장 좁은 scope에서 선언과 동시에 초기화한다. - `const`와 `constexpr`를 의미가 허용하는 범위에서 사용한다. - `override`, `final`, `explicit`, `noexcept`와 `[[nodiscard]]`는 실제 contract를 표현할 때 사용한다. Formatting-only 변경과 behavior/architecture 변경은 같은 commit에 섞지 않는다. ## Class와 Interface 설계 - Class는 하나의 명확한 책임과 invariant를 가져야 한다. - Polymorphic base는 public virtual destructor를 가져야 한다. - Abstract interface에는 현재 concrete 구현이 공유하지 않는 future method를 추가하지 않는다. - 단독 ownership은 `std::unique_ptr`로 표현한다. 실제 shared lifetime이 없는 `std::shared_ptr`는 사용하지 않는다. - Non-owning pointer/reference의 lifetime은 Doxygen contract에 기록한다. - Downcast와 type switch를 주요 확장 mechanism으로 사용하지 않는다. - State가 없는 함수를 묶기 위한 static-only class를 만들지 않는다. Internal namespace와 focused module을 사용한다. - Base class에 optional field와 no-op method를 누적하지 않는다. Material density, plastic state와 anisotropic constitutive law처럼 독립적인 의미는 별도 capability 또는 구성 객체로 설계한다. - Public header가 implementation/vendor dependency를 역으로 끌어오지 않도록 한다. Data-only record는 struct를 사용할 수 있다. Invariant, encapsulation, lifetime 또는 behavior가 있으면 class를 사용한다. ## FEM Module 책임 - `model`: immutable semantic definition과 stable source/internal identity - `elements`: element numerical kernel, local contribution과 element recovery - `properties`: element property identity와 concrete section data - `materials`: constitutive capability와 concrete material behavior - `fem`: DOF/equation numbering, scatter와 sparse pattern - `assembly`: deterministic element/load contribution reduction - `constraints`: constraint definition 적용과 equation policy - `analysis`: procedure-specific lifecycle과 backend orchestration - `results`: backend-neutral recovery record와 physical result identity - `io`: Abaqus syntax/semantic mapping과 HDF5 schema implementation - `math`: backend-neutral value/storage type와 private numerical adapter 한 module의 class가 다른 module의 owner 책임을 가져가지 않는다. Element가 global CSR을 직접 쓰거나 Node가 equation ID를 저장하거나 Material이 analysis state를 임의로 소유하면 안 된다. ## 중복과 공통화 같은 의미, units, coordinate, failure policy와 ownership을 가진 logic을 한 번만 구현한다. 현재 승인된 공통화 방향은 다음과 같다. - 3D coordinate/axis/director 연산은 `Vector3` value class - source label/set/instance 해석은 `SourceTargetResolver` - full/free/constrained invariant는 `DofManager` owner validation - MKL size/copy helper는 private dense-BLAS adapter - ASCII case-insensitive comparison과 label parsing은 focused core utility 두 코드 block이 비슷해 보여도 formulation sign, result location, source identity 또는 tolerance가 다르면 공통화하지 않는다. 단 한 번 사용하는 logic을 future flexibility만을 위해 framework로 만들지 않는다. ## Error와 Ownership - Expected failure는 `Status` 또는 `Result`로 반환한다. - Public solver API를 통해 backend exception이 그대로 새지 않게 한다. - Unknown type/property/material 조합은 structured diagnostic으로 fail-closed 처리한다. - Invalid input을 silent default, clamp, average 또는 fallback으로 숨기지 않는다. - Candidate를 완성하고 검증한 뒤 Domain state, AnalysisState 또는 final HDF5에 commit한다. - Stable ordering과 failure atomicity는 optimization option이 아니라 correctness contract다. ## Doxygen Doxygen coverage는 production code에만 요구한다. Test function과 test helper에는 Doxygen를 요구하지 않는다. Public/protected class와 function declaration은 다음 내용을 필요한 만큼 기록한다. - `@brief`: 무엇을 하는지 동사형 한 문장 - `@param`: 이름만으로 드러나지 않는 units, coordinates, ownership 또는 valid range - `@return`: success value와 failure 의미 - `@throws`: 실제로 경계를 넘어가는 exception - `@pre`: caller가 보장해야 하는 invariant - `@note`: deterministic order, lifetime 또는 backend constraint - `@warning`: sign, physical/numerical distinction 또는 destructive side effect 예: ```cpp /// @brief Computes the element stiffness in stable global DOF order. /// @return A finite symmetric contribution or a structured model failure. /// @note The returned matrix does not include nonphysical result terms. virtual Result ComputeStiffness() const = 0; ``` Private/internal production function은 declaration 또는 definition에 목적을 기록한다. 수식, sign, coordinate transform, lifetime, ordered reduction이나 failure preservation이 비자명하면 그 이유를 설명한다. Header declaration의 사용법을 `.cpp` definition에서 그대로 반복하지 않는다. Comment는 코드 한 줄을 한국어 또는 영어로 번역하는 방식으로 작성하지 않는다. Public API Doxygen는 일관된 tool output을 위해 영어를 기본으로 한다. Diagnostic message와 existing contract language는 현재 외부 계약을 유지한다. ## Determinism과 수치 코드 - Element contribution은 stable source/internal index 순서로 생성한다. - Parallel worker는 index-owned output만 수정한다. - Floating-point reduction 순서는 명시적으로 고정한다. - Refactoring 중 expression/reduction 순서를 편의상 바꾸지 않는다. - Arbitrary `max(1, ...)`, zero clamp 또는 missing-row ignore를 추가하지 않는다. - End action, section resultant, generalized result와 stress의 identity/sign을 구분한다. - Reference mapping은 row order가 아니라 승인된 source identity와 component를 사용한다. 수치식을 공통화할 때는 현재 formulation과 test가 정의한 operation order 및 tolerance를 먼저 확인한다. ## Test와 변경 관리 - Production C++ 변경은 관련 C++ test와 같은 patch에 있어야 한다. - Behavior 또는 interface 변경은 `RED -> observed failure -> minimal GREEN -> VERIFY`를 따른다. - Refactoring test는 base interface 사용, ownership/lifetime, invalid combination, deterministic order와 current numerical result preservation을 검증한다. - Focused test 뒤에 full MSVC x64 Debug build와 CTest를 실행한다. - B33/MITC4 output 경계를 건드린 변경은 승인된 reference comparison을 다시 실행한다. - Reference artifact, input path와 tolerance를 리팩터링에 맞춰 수정하지 않는다. - Commit은 review 가능한 module slice로 제한하고 Conventional Commits를 사용한다. ## Tooling Repository가 제공하는 설정을 우선한다. ```powershell clang-format --dry-run --Werror clang-tidy -- -std=c++17 doxygen Doxyfile ``` 실제 build/test command는 `.harness/config.json`이 있으면 그 설정을 우선하고, 없으면 `AGENTS.md`와 Harness의 MSVC/CMake/CTest entry point를 따른다. 필요한 tool이 설치되지 않아 검증을 실행할 수 없으면 성공으로 간주하지 않고 environment limitation을 보고한다. Generated Doxygen HTML과 tool cache/build output은 source control에 넣지 않는다. ## Implementation Agent Checklist Implementation Agent는 C++ Step을 시작하기 전에 다음을 확인한다. - 이 문서와 feature implementation plan을 읽었다. - 변경할 base/concrete/module owner가 승인 설계와 일치한다. - 관련 test file과 RED condition이 Step에 명시되어 있다. - Public API naming과 production Doxygen가 이 문서에 맞는다. - Vendor dependency와 ownership direction이 역전되지 않는다. - Stable identity, numerical order, HDF5와 reference contract가 보존된다. - Formatting, Doxygen, focused/full MSVC/CTest acceptance command가 계획되어 있다.