193 lines
9.5 KiB
Markdown
193 lines
9.5 KiB
Markdown
# 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<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 주의
|
|
|
|
```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<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에만 적용한다.
|
|
|
|
```powershell
|
|
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에 기록했다.
|