Files
FESADev/docs/CODINGSTYLE.md
T
2026-08-16 01:54:41 +09:00

257 lines
12 KiB
Markdown

# 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<T>`로 반환한다.
- 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<Matrix> 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 <changed-cpp-and-header-files>
clang-tidy <changed-cpp-files> -- -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가 계획되어 있다.