# Structural FEM Solver C++ Coding Style ## 목적과 우선순위 이 문서는 production 및 test C++의 project-local 규칙이다. [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)를 일반 baseline으로 사용하되 다음 순서가 우선한다. 1. 승인된 feature requirements, formulation, numerical/verification와 I/O contract 2. `AGENTS.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md` 3. 이 문서 4. Google C++ Style Guide 5. 수정 대상 module의 기존 local style 요청 범위 밖 파일을 style-only 이유로 수정하지 않는다. 새 코드는 즉시 준수하고 기존 코드는 승인된 변경 slice 안에서만 점진적으로 정리한다. ## Language와 toolchain - 최소 language level은 C++17이다. - Windows validation baseline은 MSVC x64다. - Compiler extension과 운영체제 전용 type을 public API에 노출하지 않는다. - Build generator, preset, configuration과 test command는 `.harness/config.json`을 우선한다. - Standard library, RAII와 value semantics를 manual lifetime management보다 우선한다. - Vendor linear algebra, sparse, persistence와 OS header는 private adapter 내부에 둔다. ## 파일과 header - File 이름은 소문자 `snake_case`를 사용한다. - Source는 `.cpp`, header는 `.h`를 사용한다. 이미 존재하는 다른 extension은 별도 migration 없이 이름만 바꾸지 않는다. - Header는 self-contained이며 consumer의 transitive include에 의존하지 않는다. - Full repository path 기반 include guard를 사용한다. ```cpp #ifndef FEM_CORE_VECTOR3_H_ #define FEM_CORE_VECTOR3_H_ namespace fem { class Vector3 {}; } // namespace fem #endif // FEM_CORE_VECTOR3_H_ ``` Include group은 대응 header, C system, C++ standard library, third party, project header 순서다. 각 group 사이에 빈 줄을 두고 직접 사용하는 declaration의 header를 include한다. ## 이름 규칙 | 대상 | 규칙 | 예 | | --- | --- | --- | | class, struct, enum, alias | `PascalCase` | `ElementProperty` | | function, method, accessor | `PascalCase` | `ComputeResidual()` | | local variable, parameter | `snake_case` | `element_id` | | class data member | `snake_case_` | `youngs_modulus_` | | struct data member | `snake_case` | `source_label` | | constant | `kPascalCase` | `kNodeCount` | | enumerator | `kPascalCase` | `FailureKind::kModel` | | namespace | `snake_case` | `fem::numerics_internal` | | macro | `UPPER_SNAKE_CASE` | `FEM_CORE_VECTOR3_H_` | Root namespace는 실제 project bootstrap에서 한 번 선택한다. 위 `fem`은 예시이며 여러 feature가 서로 다른 root namespace를 만들지 않는다. 이름은 physical/numerical 의미를 드러내야 한다. 넓은 scope의 `data`, `value`, `manager`, `handler`를 피하고 source label, entity ID, DOF ID와 equation ID를 이름에서 구분한다. ## Formatting - `.clang-format`은 Google 기반, space 2개와 최대 100 columns를 기본으로 한다. - Tab을 사용하지 않는다. - Declaration/control statement와 같은 줄에 opening brace를 둔다. - Namespace body는 들여쓰지 않고 closing namespace comment를 작성한다. - 한 statement에 한 declaration만 둔다. - Variable은 가능한 가장 좁은 scope에서 선언과 동시에 초기화한다. - 의미가 허용하면 `const`, `constexpr`, `explicit`, `override`, `noexcept`와 `[[nodiscard]]`를 사용한다. 장식 목적으로 contract를 과장하지 않는다. - Formatting-only 변경과 behavior 변경을 불필요하게 섞지 않는다. ## API와 ownership - Public interface는 현재 필요한 최소 capability만 제공한다. - Class는 하나의 명확한 responsibility와 invariant를 가진다. - Invariant, encapsulation, lifetime 또는 behavior가 없으면 data-only `struct`를 사용할 수 있다. - 단독 ownership은 `std::unique_ptr` 또는 value로 표현한다. 실제 shared lifetime이 없으면 `std::shared_ptr`를 사용하지 않는다. - Non-owning pointer/reference/span의 lifetime과 nullability를 API contract에 기록한다. - Polymorphic base에는 public virtual destructor가 있어야 한다. - Downcast와 type switch를 주요 확장 mechanism으로 사용하지 않는다. - 단일 사용을 위해 abstract factory, registry 또는 future option을 만들지 않는다. - Public header는 implementation/vendor dependency 방향을 역전하지 않는다. ## FEM module 규칙 - `model`은 validated immutable semantic definition을 소유한다. - `element`는 local residual/tangent와 recovery를 소유하며 global matrix를 직접 수정하지 않는다. - `material`은 constitutive trial/commit/revert contract를 소유한다. - `dof`는 active DOF와 equation numbering을 소유한다. Node가 equation ID를 영구 저장하지 않는다. - `assembly`는 sparsity, scatter와 deterministic reduction을 소유한다. - `constraints`는 equation policy를 소유한다. - `analysis`는 procedure lifecycle, convergence와 state commit을 소유한다. - `results`는 physical result identity를 소유하고 persistence layout을 알지 않는다. - `io`와 `storage`는 external representation을 core contract에 mapping한다. - `numerics`는 physical entity를 알지 않는 backend-neutral operation을 제공한다. 비슷해 보이는 수식을 공통화하기 전에 units, sign, coordinates, result location, state lifetime와 tolerance가 같은지 확인한다. 한 번만 사용하는 logic을 future flexibility를 위해 framework로 만들지 않는다. ## 수치 코드 - DOF/component/local-node ordering은 type, constant 또는 contract로 명시한다. - Shape derivative, Jacobian, quadrature weight와 coordinate transform의 convention을 수식과 test에서 동일하게 유지한다. - Residual과 tangent의 부호 및 linearization point를 주석/contract에 기록한다. - Parallel worker는 owner가 정해진 output만 수정하고 floating-point reduction 순서를 의도적으로 결정한다. - 임의 clamp, `max(1, ...)`, missing-row ignore와 silent fallback을 추가하지 않는다. - `double` 값의 equality를 일반적인 engineering quantity에 직접 사용하지 않고 `docs/TOLERANCE.md`의 목적별 metric을 사용한다. - 성능 변경 전 benchmark와 correctness baseline을 기록한다. Expression order를 바꾸는 optimization은 numerical regression을 다시 검증한다. ## Error와 failure atomicity - 예상 가능한 실패는 project의 `Status`/`Result` 계약으로 반환한다. - Backend exception과 raw error code가 public solver boundary를 통과하지 않게 한다. - Unsupported type/property/material/procedure 조합은 structured diagnostic으로 fail closed한다. - Candidate model/state/result를 완성해 검증한 뒤 authoritative owner에 commit한다. - Partial failure가 기존 committed state 또는 정상 result artifact를 덮어쓰지 않게 한다. - Assertion은 사용자 입력 오류가 아니라 내부 invariant 위반에 사용한다. ## Documentation Public/protected production declaration은 필요한 경우 다음을 영어 Doxygen로 기록한다. - purpose와 physical/numerical meaning - units, coordinates, ordering과 valid range - ownership, lifetime, precondition과 failure - deterministic behavior 또는 backend limitation - sign, trial/committed state와 destructive side effect 주의 ```cpp /// @brief Computes an element contribution in the declared local DOF order. /// @return A finite residual and consistent tangent, or a structured failure. /// @note This function does not modify the global system or committed state. virtual Result Evaluate( const ElementContext& context) const = 0; ``` 코드가 말하는 내용을 번역하는 comment는 쓰지 않는다. 비자명한 formulation, operation order, ownership 또는 선택 이유를 설명한다. Test helper에는 형식적인 Doxygen를 요구하지 않는다. ## Test와 변경 관리 - Production C++ 변경은 관련 test 변경과 같은 patch에 포함한다. - `RED -> observed failure -> minimal GREEN -> focused VERIFY -> full VERIFY`를 따른다. - Test는 정상값뿐 아니라 invalid combination, identity/order, state rollback, determinism과 error category를 검증한다. - Numerical feature는 직접 kernel test와 독립 system/benchmark evidence를 모두 가진다. - Reference artifact나 tolerance를 implementation 결과에 맞춰 수정하지 않는다. - 새 warning, flaky test 또는 검증되지 않은 platform 성공 주장을 추가하지 않는다. - Commit을 요청받으면 review 가능한 module slice와 Conventional Commits 형식을 사용한다. ## Tooling Repository 설정과 존재하는 target에만 적용한다. ```powershell clang-format --dry-run --Werror clang-tidy -- -std=c++17 cmake --build .harness/build --config Debug ctest --test-dir .harness/build -C Debug --output-on-failure ``` Tool, build metadata 또는 target이 없으면 검사를 성공으로 표시하지 말고 `미실행`과 이유를 보고한다. Generated documentation, build directory, cache와 runtime output은 source control에 넣지 않는다. ## Implementation checklist - 승인된 feature contract와 직접 관련된 파일만 변경한다. - Public dependency 방향과 owner가 architecture와 일치한다. - 실패 test를 구현 전에 관찰했다. - Units, coordinates, identity와 local/global ordering이 드러난다. - Trial/committed state와 failure atomicity가 보존된다. - Focused test와 가능한 full build/test를 실제로 실행했다. - 미실행 검사, warning과 residual risk를 evidence에 기록했다.