==================
 Coding Standards
==================

.. list-table:: Revision History
   :widths: 30 30 70

   * - Identifier
     - Release date
     - Description
   * - v0.1 (Baseline)
     - 03/31/2026
     - Initial CML coding standards
   * - v0.2
     - 07/21/2026
     - Changed GitLab references to GitHub and converted to reStructuredText

.. list-table:: Approvers
   :widths: 150 150

   * - Prepared by
     - Approved by
   * - | Nino Tarantino
       | CML Maintainer
       | 03/31/2026
     - | Daniel Jordan
       | CML Lead
       | 03/31/2026

.. contents:: Table of Contents
   :local:
   :class: this-will-duplicate-information-and-it-is-still-useful-here

Introduction
============

This document provides the formal code standards that are used within the Common Model Library (CML) team. The coding
standards in this document are designed to protect the reliability, maintainability, and usability of the library while
avoiding overly restrictive standards that may prevent some simulation teams from easily contributing their models to
CML. These standards are written based on generally accepted best practices in industry as well as lessons learned from
experienced developers in the Trick-based simulation field at NASA JSC. These standards are expected to mature and
develop over time.

Purpose
-------

Coding standards are used in large software development projects because they provide multiple benefits to the
organization developing the software application. These benefits are seen as critical for the CML team developing and
maintaining complex and high-fidelity time-domain simulation models used for spacecraft analysis.

Scope
-----

The coding standards listed in this document apply only to the developed code associated with models under the control
of the CML team. These coding standards do not apply to external packages such as Trick, JEOD, or any other third-party
dependency.

Change Authority/Responsibility
-------------------------------

Proposed changes to this document shall be submitted as a GitHub issue or via email to the CML team for consideration
and disposition with the team lead.

Applicable Documents
--------------------

The following documents include specifications, models, standards, guidelines, handbooks, and other special
publications. The documents listed in this product are applicable to the extent specified herein.

.. list-table::
   :widths: 30 30 70
   :header-rows: 1

   * - Document Number
     - Document Revision
     - Document Title
   * - NASA-STD-7009
     - A.1
     - Standard for Models and Simulations
   * - NPR 7150.2
     - C
     - NASA Software Engineering Requirements

Reference Documents
-------------------

The following documents contain supplemental information to guide the user in the application of this document.

.. list-table::
   :widths: 50 50 50

   * - Document Number
     - Document Revision
     - Document Title
   * -
     -
     -

Coding Standards
================

This section describes the coding standards and how they apply to the software development workflow. The purpose of
having coding standards is to ensure that a project's code base not only functions correctly but is also readable
modifiable, and maintainable. The code that comes into the library must be easily reviewable and not threaten the
stability of the library itself. With these goals in mind, the CML Coding Standards fall in two categories:

-  :ref:`model-coding-standards` – These coding standards should be met upon a developer’s Pull
   Request Review. These standards are intended to ensure the quality, stability, and cohesiveness of CML.
   Non-compliances will be identified in the review and evaluated for risk to integration into the library.
-  :ref:`best-practice-coding-standards` – These coding standards should be met as early as
   possible but are not required to be met upon a developer’s Pull Request Review. These standards are intended to
   ensure that the codebase follows modern best practices. Non-compliances will be evaluated for risk to the library and
   documented in a follow-on GitHub issue for future resolution if necessary.

Application and Enforcement
---------------------------

New models submitted to CML must first pass through a Pull Request Review. During the review, the submitting group
provides CML with the NASA NPR 7150.2 classification of the model and evidence of NASA-STD-7009 compliance. The CML team
will review the documentation provided and will check the models submitted for adherence to the coding standards. Many
of the model coding standards are checked with assistance from automated tooling, which reduces the amount of manual
review necessary.

Updates to existing CML code will also be checked for adherence to the coding standards during a Pull Request Review.
Unlike a new model submission, NPR 7150.2 and NASA-STD-7009 documentation is not required unless the model’s
classification has changed.

________________________________________________________

.. _model-coding-standards:

Model Coding Standards
----------------------

These standards cover the attributes of the source code required for CML models and must be met before acceptance of the
source code into the main branch of the CML codebase.

Model Coding Standards are broken into categories depending on the language used. CML-MCS-GENERAL standards apply to all
code, regardless of language. CML-MCS-CPP standards apply to C++ code. CML-MCS-PYTHON standards apply to Python code.

________________________________________________________

**CML-MCS-GENERAL-1**: All Trick-based simulation model code shall be written in the C++ programming language
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Trick simulation models should be written in C++. Other programming languages, such as C, are not allowed
to be used for model implementation. Autocoded models from MATLAB or Simulink source are not considered to have been
written in C++.

**Enforcement**: Static analysis and Pull Request Review.

________________________________________________________

**CML-MCS-GENERAL-2**: All scripts required to maintain model code must be committed at the time of Pull Request Review
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Some models may contain data or other content that was automatically generated by means of a script.
These scripts must also be committed and live alongside the model so that the model may be properly maintained.

**Enforcement**: Pull Request Review.

________________________________________________________

**CML-MCS-GENERAL-3**: Source code shall not contain ITAR, EAR, or CUI data
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: CML is an open-source project and must not contain sensitive data.

**Enforcement**: Pull Request Review.

________________________________________________________

**CML-MCS-GENERAL-4**: Source code shall be formatted in accordance with a common stylesheet
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Consistent codebases are easier to use and maintain. Automated code formatting ensures that the git
history contains only impactful changes to the code rather than formatting tweaks. The specific formatting
enforcement tool and stylesheet may differ between languages.

**Enforcement**: Static analysis operating off of a common stylesheet available to developers and users.

________________________________________________________

**CML-MCS-GENERAL-5**: Commented-out code shall only be allowed when accompanied by an associated project issue, point of contact email address, and current date
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Commented-out code should be rare. When it is included in the codebase, there should be an expectation
that the code will be un-commented or removed by a certain date.

**Enforcement**: Pull Request Review.

**Example**

.. code-block:: cpp

    // TODO jane.doe@nasa.gov 01/01/2000: uncomment when addressing issue #1.
    //my_type.nonexistent_field = 1;

________________________________________________________

**CML-MCS-CPP-1**: Source code shall live within the “cml” C++ namespace
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Namespaces prevent name collisions between CML-defined types and the types defined by consumers of the
CML library.

**Enforcement**: Pull Request Review.

**Example**

.. code-block:: cpp

   namespace cml {

   struct MyType {
   };

   void my_function(int my_param);

   }

________________________________________________________

**CML-MCS-CPP-2**: Header files shall direct Trick to place generated interface code in the “cml” Python module via the Trick header “PYTHON MODULE” directive
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Trick provides the option to generate Python interface code into a specific Python module rather than in
the global “trick” scope. This prevents name collisions between CML-defined types and the types defined by Trick or
consumers of the CML library.

**Enforcement**: Static analysis.

**Example**

.. code-block:: cpp

   /* PURPOSE: (My purpose)
    *
    * PYTHON_MODULE: (cml)
    */

________________________________________________________

**CML-MCS-CPP-3**: Source code shall use the .hh file extension for headers and the .cc file extension for source files
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Consistent codebases are easier to use and maintain.

**Enforcement**: Static analysis.

________________________________________________________

**CML-MCS-CPP-4**: Functions and types limited in scope to the implementation details of a module shall be placed in an unnamed namespace within the corresponding module source file
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Exposing internal implementation details in public headers slows down Trick interface code generation and
may confuse users. Unnamed namespaces are the modern equivalent to static functions and types declared at the file-level.

**Enforcement**: Pull Request Review.

**Example**

.. code-block:: cpp

   // Within myfile.cc
   namespace {

   void some_local_function() {
   }

   }

________________________________________________________

**CML-MCS-CPP-5**: Structs shall be used only for passive objects with all public fields that have no invariants
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Structs are widely understood by the C++ community to carry data with no invariants. Although structs may
have protected or private fields, if such encapsulation is necessary, then classes should be used.

**Enforcement**: Pull Request Review.

**Examples**

.. code-block:: cpp

   struct JustSomeData {
       int int_data {};
       double double_data {1.0};
       std::string string_data {"Some Data"};
   };

   class EncapsulationNecessary {
   public:
       void set_coefficient_of_friction(double coefficient_of_friction_in) {
           if (coefficient_of_friction_in >= 0.0) {
               coefficient_of_friction = coefficient_of_friction_in;
           } else {
               throw_some_error();
           }
       }

   private:
       double coefficient_of_friction {};
   };

________________________________________________________

**CML-MCS-CPP-6**: Source code shall compile with no warnings
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Compiler warnings signify that something may be wrong with the code and should rarely be ignored.

**Enforcement**: Automated builds in GitHub Actions treat warnings as errors.

________________________________________________________

**CML-MCS-CPP-7**: Source code shall pass review by linters without generating any warnings
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Linters such as ``cppcheck`` and ``clang-tidy`` are widely used in industry and provide meaningful
feedback on potential code quality issues. These warnings should rarely be ignored.

**Enforcement**: Linters are run in a GitHub Action and produce a failing result upon detecting an error.

________________________________________________________

**CML-MCS-CPP-8**: Source code shall have associated unit tests which cover at least 90% of lines with meaningful tests
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Inadequately tested code is prone to introducing regressions and is not fit for use within high-fidelity
spacecraft simulations.

**Enforcement**: Manual review of code coverage artifacts generated in a GitHub Action during Pull Request Review.

________________________________________________________

**CML-MCS-CPP-9**: Source code shall compile using the ISO/IEC 14882 C++17 standard
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: A reasonably recent version of the C++ language should be used by all models to leverage new language
features and maintain interoperability with other open-source libraries.

**Enforcement**: All toolchains use the minimum supported C++ standard.

________________________________________________________

**CML-MCS-CPP-10**: Source code shall have associated documentation which includes, at minimum, the model’s public API, a users’ guide, assumptions and limitations, and details about prior verification and validation activities
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Code without documentation cannot be effectively maintained or used.

**Enforcement**: Pull Request Review.

________________________________________________________

**CML-MCS-PYTHON-1**: Source code shall not call exec(), eval(), or otherwise evaluate an arbitrary string as Python code
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Exceptions thrown within code evaluated by ``exec()`` or other related functions do not provide meaningful
debugging information. These functions also introduce security concerns into the codebase. Use modules and functions
instead of ``exec(open())``.

**Enforcement**: Pull Request Review.

**Example, wrong**

.. code-block:: python

   exec(open("Modified_data/utils.py").read())
   some_function_from_utils()

**Example, correct**

.. code-block:: python

   from Modified_data.utils import some_function_from_utils
   some_function_from_utils()

________________________________________________________

**CML-MCS-PYTHON-2**: Methods which accept keyword arguments shall document all allowable keyword arguments
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Users should not have to read implementation details to determine which keyword arguments are accepted by
a function.

**Enforcement**: Pull Request Review.

**Example**

.. code-block:: python

   def myfunc(*args, **kwargs) -> None:
       """Does a few things.

       Keyword arguments:
       ------------------
       foo : An instance of Foo
       bar : A numeric type such as an int or float
       baz : A string-like type
       """
       implementation(*args, **kwargs)

________________________________________________________

.. _best-practice-coding-standards:

Best Practice Coding Standards
------------------------------

These standards cover best practice for the code within CML. These standards are not required to be met at the time of
integration into the main CML branch but should be met as soon as possible afterwards. Like the
:ref:`model-coding-standards`, CML Best Practice Coding Standards are grouped by programming language.

________________________________________________________

**CML-BP-CPP-1**: Do not define macros
++++++++++++++++++++++++++++++++++++++

**Rationale**: Macros cannot be put into a namespace and can be difficult to debug. Use function templates and inline
variables instead.

**Example, wrong**

.. code-block:: cpp

   #define ADD_ONE(input) ((input) + 1)

   #define SPEED_OF_LIGHT 299792458.0

**Example, correct**

.. code-block:: cpp

   template <typename Type>
   [[nodiscard]] constexpr Type add_one(const Type& input) {
      return input + 1;
   }

   inline constexpr double SPEED_OF_LIGHT = 299792458.0;

________________________________________________________

**CML-BP-CPP-2**: Do not invoke undefined behavior
++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: The outputs of a program which invokes undefined behavior are suspect.

**Note**: Most undefined behavior will be caught by static analysis tools and will be required to be addressed during
Pull Request Review.

________________________________________________________

**CML-BP-CPP-3**: Do not use global variables
+++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Global variables often lead to “spaghetti code” which is difficult to maintain and understand.

________________________________________________________

**CML-BP-CPP-4**: Do not use the “new” or “delete” keywords
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: The Trick Memory Manager should be used to allocate memory which must be logged or otherwise available
for Trick-specific purposes. Otherwise, smart pointers provided by the C++ standard library should be used for
dynamic memory management. Both of these options provide automated cleanup of the allocated memory.

**Example, wrong**

.. code-block:: cpp

   auto* data = new double;

**Example, correct** using the Trick memory manager

.. code-block:: cpp

   auto* data = static_cast<double*>(trick_TMM->declare_var("double"));

**Example, correct** using smart pointers

.. code-block:: cpp

   auto data = std:make_unique<double>();

________________________________________________________

**CML-BP-CPP-5**: Do not allocate significant memory in scheduled simulation jobs
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Trick scheduled jobs are often intended to be run at high frequencies for high-fidelity spacecraft
analysis. Frequently reallocating memory during such jobs introduces performance bottlenecks and is a symptom of bad
design. Some reallocation may be expected during certain simulation events, but most memory allocation should occur
during simulation initialization.

________________________________________________________

**CML-BP-CPP-6**: Favor composition over inheritance
++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Frequent use of inheritance can make a codebase difficult to understand. Often, composition allows for
easier code maintenance and testability.

________________________________________________________

**CML-BP-PYTHON-1**: Use docstrings
+++++++++++++++++++++++++++++++++++

**Rationale**: Python docstrings help users use Python code correctly and are recommended by PEP 257.

**Example**

.. code-block:: python

   def foo(bar) -> None:
       """Foos a bar."""

________________________________________________________

**CML-BP-PYTHON-2**: Use type annotations
+++++++++++++++++++++++++++++++++++++++++

**Rationale**: Type annotations help address one of the biggest shortcomings of dynamically typed languages, where the
types allowed as inputs or expected as outputs from functions are not always easy to deduce.

**Example**

.. code-block:: python

   def connect(port: int, hostname: str) -> StatusCode:
       """Attempt to connect to a port on a host."""
       return implementation(port, hostname)

________________________________________________________

**CML-BP-PYTHON-3**: Functions should always return the same number of items, preferably only one item
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Functions which return a variable number of arguments depending on the logic path taken are brittle and
require users to understand the inner workings of the function which they are accessing.

________________________________________________________

**CML-BP-PYTHON-4**: Do not use classes in code intended for use in Trick input files
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

**Rationale**: Classes are designed to hold state and provide access control to data, while Trick input files are
designed to be a purely procedural interface to a simulation. Frequent overuse of classes in Trick input files has
proven repeatedly to negatively impact code usability and maintainability. Use free functions instead.

________________________________________________________

Coding Standards Waiver
-----------------------

Waivers to any coding standard may be granted on a case-by-case basis when it can be demonstrated that the following
criteria are both met:

1. Safeguards are in place to ensure that the exception does not create a risk to the overall project.
2. The effort required to bring the code to a satisfactory standard would be excessive.

The request for a waiver is made during Pull Request Review. The request may be in the form of a PowerPoint
presentation, a memo, or any other format capable of conveying the following information:

-  Violation (with code)
-  Options for mitigation/resolution
-  Rationale why the violation is acceptable
-  Evaluation of risk to accepting the waiver

If the waiver is granted, the request must be updated to reflect the approver, date of approval, and this information
must be recorded with the model documentation. The complete list of waivers will be maintained separately for CML
maintenance and metrics purposes. If the waiver is denied, the developer is directed to resolve the violation.

Appendix A: Acronyms and Abbreviations
======================================

.. list-table::
   :widths: 30 70

   * - Acronym
     - Abbreviation
   * - CML
     - Common Model Library
   * - CUI
     - Controlled Unclassified Information
   * - EAR
     - Export Administration Regulations
   * - ITAR
     - International Traffic in Arms Regulations
   * - JEOD
     - Johnson Space Center Engineering Orbital Dynamics
   * - JSC
     - Johnson Space Center

Appendix B: Glossary of Terms
=============================

.. list-table::
   :widths: 30 70

   * - Term
     - Description
   * - Trick
     - An open-source C++/Python driven simulation development framework. See https://github.com/nasa/trick for more
       information.
   * - Pull Request Review
     - When code is ready to be reviewed and accepted into the main production branch of CML, a pull request is opened.
       The Pull Request Review is the process by which the code is assessed for compliance with CML's code standards and
       other NASA standards by the CML team.