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

12 KiB

FESA C++ Coding Style

목적

이 문서는 FESA production 및 test C++의 코드 스타일, 객체 설계, 문서화와 검증 규칙을 정의하는 project-local source of truth다. 새 C++를 작성하거나 기존 C++를 리팩터링하는 사람과 Implementation Agent는 작업 전에 이 문서를 읽어야 한다.

Google C++ Style Guide를 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를 사용한다.

예:

#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

예:

/// @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가 제공하는 설정을 우선한다.

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가 계획되어 있다.