-
Notifications
You must be signed in to change notification settings - Fork 0
Coding Style
sparq follows the principles defined by the C++ Core Guidelines and applies additional conventions suitable for embedded systems development
The goal is to maximize:
- Readability
- Maintainability
- Testability
- Predictability
- Portability
Code should be written for humans first and compilers second
Code should communicate intent clearly, should be self-documented
auto motorSpeed = calculateMotorSpeed();auto x = calculateMotorSpeed();Functions should perform a single logical operation
void initializeMotor();
void configureMotor();
void startMotor();void initializeConfigureAndStartMotor();Prefer compile-time validation over runtime validation whenever possible
constexpr std::uint16_t maxMotorAngle = 180;#define MAX_MOTOR_ANGLE 180Classes, structs, enums and concepts use PascalCase
class MotorController;
struct MotorConfig;
enum class Direction;Interfaces use an I prefix
class IMotor;
class ISerialPort;
class IHttpClient;Functions use camelCase
initialize();
changeMotorAngle();
getPosition();Variables use camelCase
motorSpeed
currentPosition
serialPortMember variables use a leading specifier this->
this->motorSpeed
this->serialPort
this->httpClientConstants use camelCase
constexpr std::uint32_t maxPacketSize = 1024;Namespaces use camelCase
namespace sparq::hal
{
}Prefer composition over inheritance
class MotorService
{
private:
IMotor& motor;
};class MotorService : public MotorController
{
};Application code should depend on interfaces
class MotorService
{
public:
explicit MotorService(IMotor& motor);
};class MotorService
{
public:
explicit MotorService(Esp32Motor& motor);
};Single-argument constructors shall be marked explicit
explicit MotorService(IMotor& motor);Exceptions are disabled in many embedded environments
Use strongly typed error codes
enum class ErrorCode
{
Ok,
InvalidParameter,
InitializationFailed
};Return values must not be silently ignored
Prefer:
[[nodiscard]]
ErrorCode initialize();Dynamic allocation should be avoided after system startup
Prefer:
std::array<std::uint8_t, 256> buffer;Over:
std::vector<std::uint8_t> buffer;Ownership must be explicit
Prefer:
std::unique_ptr<T>when dynamic allocation is unavoidable
constexpr auto timeoutMs = 1000U;enum class Direction
{
Clockwise,
CounterClockwise
};Avoid passing unrelated primitive values
MotorAngle angle;
MotorSpeed speed;int angle;
int speed;Use auto when the type is obvious
auto error = initialize();auto value = someComplexCalculation();when the type is not clear
Avoid global mutable objects
Hardware-specific code belongs in PAL
Application code must not include vendor SDK headers
#include <sparq/hal/IMotor.hpp>#include <esp_wifi.h>outside PAL
Use templates when runtime polymorphism is not required
Use virtual interfaces only where abstraction boundaries exist
Use four spaces
No tabs
Opening braces are placed on a new line
if (condition)
{
doSomething();
}Target 150 characters
Hard limit: 200 characters
int speed;
int angle;Not:
int speed, angle;class MotorService
{
public:
explicit MotorService(IMotor& motor);
[[nodiscard]]
ErrorCode initialize();
private:
IMotor& motor;
};class motorservice
{
public:
motorservice(Motor* m);
int Init();
private:
Motor* _m;
};When guidelines conflict, the sparq coding style takes precedence
- Dependency rule: Application → HAL → PAL only; never reverse!
- Include order rule: sparq → third party libraries → standard library
- No RTTI rule:
dynamic_castandtypeidare prohibited