Files
FESADev/docs2/CODINGSTYLE.md
T
2026-09-05 15:14:21 +09:00

9.5 KiB

Structural FEM Solver C++ Coding Style

목적과 우선순위

이 문서는 production 및 test C++의 project-local 규칙이다. Google C++ Style Guide를 일반 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를 사용한다.
#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<T> 계약으로 반환한다.
  • 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 주의
/// @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<ElementContribution> 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에만 적용한다.

clang-format --dry-run --Werror <changed-cpp-and-header-files>
clang-tidy <changed-cpp-files> -- -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에 기록했다.