9.5 KiB
Structural FEM Solver C++ Coding Style
목적과 우선순위
이 문서는 production 및 test C++의 project-local 규칙이다. Google C++ Style Guide를 일반 baseline으로 사용하되 다음 순서가 우선한다.
- 승인된 feature requirements, formulation, numerical/verification와 I/O contract
AGENTS.md,docs/ARCHITECTURE.md,docs/ADR.md- 이 문서
- Google C++ Style Guide
- 수정 대상 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에 기록했다.