blob: 6b6261f281a89647e709654d6bc02007c77b5b98 [file] [log] [blame]
/**
@page guide_developer_styleguide Style Guide
@brief Guide for the coding style used in this SDK.
The goal of this style guide is to encourage a readable and consistent coding style across the entire SDK.
@section guide_developer_styleguide_codingstyle Coding Style
@brief The coding style used in this SDK.
The coding style aims to produce code that is readable and easy to debug. An example is provided in @ref guide_developer_styleguide_codingstyle_example.
@subsection guide_developer_styleguide_codingstyle_generalguidelines General guidelines
@brief General guidelines for library style.
- Libraries should only use features from [C99](https://en.wikipedia.org/wiki/C99) and earlier.
- Libraries should [log](@ref logging) extensively.
- Code should be well-commented.
- Only `/*` and @c *`/` should be used to start and end comments.
- All comments end with a period.
- Only spaces should be used for indenting. A single indent is 4 spaces. No tab characters should be used.
- A parenthesis is usually followed by a space (see @ref guide_developer_styleguide_codingstyle_example).
- Lines of code should be less than 80 characters long, although longer lines are permitted.
- All local variables should be declared at the top of a function.
- All global variables should be declared at the top of a file.
- Variables are always initialized.
- A separator is placed between different sections of a file. The current separator is:
@code{c}
/*-----------------------------------------------------------*/
@endcode
- All files must include `iot_config.h` at the top of the file <b>before any other includes</b>.
- `static` functions must have a declaration at the top of the file and be implemented before any application-facing functions.
@subsection guide_developer_styleguide_codingstyle_typeguidelines Type guidelines
@brief Guidelines for variable types.
- Only fixed-width integer types should be used. Exceptions for `bool` and types required by third-party APIs.
- The default integer in the libraries should be 32 bits wide, i.e. `int32_t` or `uint32_t`.
- Sizes and lengths should be represented with `size_t`, and Boolean variables with `bool`.
@subsection guide_developer_styleguide_codingstyle_example Example File
@brief An example file that follows the coding style rules.
See @ref guide_developer_styleguide_naming for how to name the functions, variables, and macros.
@code{c}
/* Included headers are at the top of the file. The config file include is always first. */
#include "iot_config.h"
/* Standard includes are immediately after the config file. They are sorted alphabetically.
* They use angle brackets <> around the file name. */
/* Standard includes. */
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
/* Library internal headers are included next. They use quotes "" around the file name. */
/* Library internal include. */
#include "private/iot_library_internal.h"
/* Error handling include (include only when needed). */
#include "private/iot_error.h"
/* Library application-facing headers are included last. They use quotes "" around the file name. */
/* Library include. */
#include "iot_library.h"
/*-----------------------------------------------------------*/
/* Defined constants follow the included headers. */
/* When possible, parentheses () should be placed around contant values and a type
* should be specified. */
#define LIBRARY_CONSTANT ( ( int32_t ) 10 )
#define LIBRARY_FUNCTION_MACRO( argument ) \ /* Line continuators are right-aligned. */
{ \ /* Function-like macros are surrounded by curly braces {}. */
macro_body( argument ); \
}
/*-----------------------------------------------------------*/
/* Library typedefs follow the defined constants. */
/* Forward declarations are used only when necessary. They are placed before all
* other typedefs. */
typedef int32_t _type_t;
typedef struct _structType /* Structs are named along with the typedef. */
{
int32_t member;
union /* Anonymous structs/unions are permitted only inside of other structs. */
{
int32_t a;
int32_t b;
};
int32_t variableLengthMember[]; /* Variable length arrays (a C99 feature) are permitted. */
} _structType_t;
/*-----------------------------------------------------------*/
/* Declarations of static and extern functions follow the typedefs. */
static bool _libraryStaticFunction( void * pArgument,
size_t argumentLength );
/* External function declarations should be used sparingly (using an internal
* header file to declare functions is preferred). */
extern int32_t IotLibrary_ExternalFunction( void * pArgument );
/*-----------------------------------------------------------*/
/* Declarations of global variables follow the static and extern function
* declarations. Global variables are permitted, but should be avoided when
* possible. */
/* Global variables are always initialized. */
static int _globalVariable = 0;
static int _globalArray[ _LIBRARY_CONSTANT ] = { 0 };
/*-----------------------------------------------------------*/
/* Implementations of static functions follow the global variable declarations. */
static bool _libraryStaticFunction( void * pArgument,
size_t argumentLength )
{
/* All local variables are declared at the top of the function. Variables are
* always initialized. */
size_t i = 0;
int32_t localVariable = 0;
int32_t * pLocalPointer = ( int32_t * ) pArgument;
/* Error handling setup, which declares a status variable type and initial
* value. */
IOT_FUNCTION_ENTRY( bool, true );
/* All functions make generous use of the logging library. */
IotLogInfo( "Performing calculation..." );
if( ( pArgument == NULL ) || ( argumentLength == 0 ) ) /* Note the parentheses and spacing in if statements */
{
IotLogError( "Bad parameters." );
/* Error handling exit. */
IOT_SET_AND_GOTO_CLEANUP( false );
}
for( i = 0; i < argumentLength; i++ ) /* Note the spacing in the for loop. */
{
localVariable += IotLibrary_ExternalFunction( pArgument );
IotLogDebug( "Current value is %d.", ( int ) localVariable );
}
if( localVariable < 0 )
{
IotLogWarn( "Failed to calculate positive value." );
}
IotLogInfo( "Calculation done." );
/* Error handling exit. */
IOT_FUNCTION_EXIT_NO_CLEANUP();
}
/* A separator is placed between all function implementations. */
/*-----------------------------------------------------------*/
/* Implementations of application-facing functions are at the bottom of the file. */
bool IotLibrary_ApplicationFunction( void ) /* Functions with no arguments have void in their argument list. */
{
LIBRARY_FUNCTION_MACRO( _globalArray );
return true;
}
/* Separator and newline at end of file */
/*-----------------------------------------------------------*/
@endcode
@section guide_developer_styleguide_naming Naming
@brief Naming convention used in this SDK.
The naming convention aims to differentiate this SDK's files, variables, and functions to avoid name collisions. In general:
- The first characters of all <i>publicly visible</i> names should identify the name as part of this SDK. <br>
<b>Example:</b> For general-purpose libraries (such as MQTT), names start with `iot_` or `Iot`. <br>
<b>Example:</b> For libraries specific to AWS IoT (such as Shadow), names start with `aws_iot_` or `AwsIot`.
- Words in names should be ordered with the most general word first and the most specific word last. <br>
<b>Example:</b> `iot_mqtt_api.c` identifies a file as part of the general MQTT library. `_IotMqtt_ValidateConnect` identifies a function as part of the <i>Internal</i> component of the general MQTT library.
- Names should avoid using abbreviations.
@subsection guide_developer_styleguide_naming_definedconstantsandenumvalues Defined constants and enum values
@brief Naming convention for constants set using preprocessor @c #`define` and enum values.
@formattable{defined constants and enum values}
@formattableentry{`IOT_`<b>LIBRARY</b>`_`<b>DESCRIPTION</b><br>`AWS_IOT_`<b>LIBRARY</b>`_`<b>DESCRIPTION</b>,Defined constants and enum values in application-facing library header files,`IOT_MQTT_SUCCESS` (iot_mqtt.h)<br>`AWS_IOT_SHADOW_SUCCESS` (aws_iot_shadow.h)}
@formattableentry{`IOT_DEMO_`<b>DESCRIPTION</b><br>`IOT_TEST_`<b>DESCRIPTION</b>,Defined constants and enum values in demos and tests,`IOT_DEMO_MQTT_PUBLISH_BURST_SIZE`<br>`IOT_TEST_MQTT_THREADS`}
@formattableentry{`AWS_IOT_DEMO_`<b>DESCRIPTION</b><br>`AWS_IOT_TEST_`<b>DESCRIPTION</b>,Defined constants and enum values in demos and tests specific to AWS IoT,`AWS_IOT_DEMO_THING_NAME`<br>`AWS_IOT_TEST_SHADOW_THING_NAME`}
@formattableentry{<b>DESCRIPTION</b>,Internal constants and enum values<br>No `AWS_` prefix for internal names in AWS-specific libraries,`MQTT_PACKET_TYPE_CONNECT`<br>(iot_mqtt_internal.h)<br>`SHADOW_OPERATION_COUNT`<br>(aws_iot_shadow_internal.h)}
Names of constants and enum values should contain only uppercase letters and underscores. All names intended for application use must begin with `IOT_` or `AWS_IOT_`.
@subsection guide_developer_styleguide_naming_files Files
@brief Naming convention for files.
@formattable{files}
@formattableentry{`iot_`<b>library</b>`_`<b>description</b>`.extension`<br>`aws_iot_`<b>library</b>`_`<b>description</b>`.extension`,General library file,`iot_mqtt_api.c`<br>`aws_iot_shadow_api.c`}
@formattableentry{`iot_`<b>library</b>`_internal.h`<br>`aws_iot_`<b>library</b>`_internal.h`,Internal library header,`iot_mqtt_internal.h`<br>`aws_iot_shadow_internal.h`}
@formattableentry{`iot_demo_`<b>library</b>`.c`<br>`aws_iot_demo_`<b>library</b>`.c`,Library demo source,`iot_demo_mqtt.c`<br>`aws_iot_demo_shadow.c`}
@formattableentry{`iot_tests_`<b>library</b>`_`<b>description</b>`.c`<br>`aws_iot_tests_`<b>library</b>`_`<b>description</b>`.c`,Library test source,`iot_tests_mqtt_api.c`<br>`aws_iot_tests_shadow_api.c`}
File names contain only lowercase letters and underscores. All file names should start with `iot_` or `aws_iot_` and be named according to their purpose. For example:
- `iot_mqtt_api.c`: A file in the MQTT library that implements the MQTT API functions.
- `iot_demo_mqtt.c`: A file in the Demos for the MQTT library.
- `iot_demo_mqtt_posix.c`: A file in the Demos for the MQTT library on POSIX systems.
- `iot_tests_mqtt_api.c`: A file in the Tests for the MQTT library. Since the tests currently only run on POSIX systems, test file names do not use the `_posix` suffix.
Library file names should use one or two words to describe the functions implemented in that file. For example:
- `iot_mqtt_serialize.c`: Implements the MQTT library's packet serialization and deserialization functions.
- `iot_clock_posix.c`: Implements the platform clock component for POSIX systems.
Declarations of internal functions, structures, macros, etc. of a library should be placed in a header file with an `_internal` suffix. The `_internal` header file should go in the `lib/include/private` directory. For example:
- `iot_mqtt_internal.h`: Declares the MQTT library's internal functions, structures, macros, etc.
File names for tests and demos should all begin with `iot_demo_` and `iot_tests_`, respectively. The names should then specify the library being demoed or or tested; for example, the files names of the MQTT library's demos and tests start with `iot_demo_mqtt_` and `iot_tests_mqtt_`. Additionally, test file names should describe what tests are implemented in the file, such as `iot_tests_mqtt_api.c` for a file containing tests for the MQTT library API functions.
@subsection guide_developer_styleguide_naming_functions Functions (and function-like macros)
@brief Naming convention of functions and function-like macros.
@formattable{functions}
@formattableentry{`Iot`<b>Library</b>`_`<b>Description</b><br>`AwsIot`<b>Library</b>`_`<b>Description</b>,Externally-visible library function,`IotMqtt_Publish`<br>`AwsIotShadow_Update`}
@formattableentry{`_Iot`<b>Library</b>`_`<b>Description</b><br>`_AwsIot`<b>Library</b>`_`<b>Description</b>,Internal (but not `static`) library function,`_IotMqtt_ValidateNetIf`<br>`_AwsIotShadow_ParseShadowStatus`}
@formattableentry{`IotTest`<i>Library</i>`_`<b>Description</b>,Function only used in tests,`IotTest_NetworkConnect`<br>`IotTestMqtt_createMqttConnection`}
@formattableentry{`_`<b>description</b>,`static` function (never uses `Aws` prefix),`_createMqttConnection`<br>`_codeToShadowStatus`}
@formattableentry{`IotTest`<b>Library</b>`_`<b>accessedFunction</b>,Test access function,`IotTestMqtt_createMqttConnection`}
Externally visible (i.e. not `static`) functions are [UpperCamelCased](https://en.wikipedia.org/wiki/Camel_case) and must begin with `Iot` or `AwsIot` (public API functions); or `_Iot` or `_AwsIot` (internal functions). Function names should then specify their library name; followed by an underscore; followed by a brief description of what the function does. For example:
- `IotMqtt_Publish`: This function is part of the public MQTT API. It <i>Publishes</i> an MQTT message.
- `_IotMqtt_ValidateNetIf`: This function is internal to the MQTT library, but not `static`. It validates an `IotMqttNetIf_t`.
Functions not visible outside their source file (i.e. `static` functions) have names that are [lowerCamelCased](https://en.wikipedia.org/wiki/Camel_case) and begin with an underscore. These function names do not contain the library name or `Aws`. For example:
- `_createMqttConnection`: A `static` function in `iot_mqtt_api.c`.
- `_codeToShadowStatus`: A `static` function in `aws_iot_shadow_parser.c`.
Test access functions begin with `IotTest`; followed by the library name; followed by an underscore; followed by the function that the test function accesses. Since the accessed function is always `static`, the accessed function will be [lowerCamelCased](https://en.wikipedia.org/wiki/Camel_case).
@subsection guide_developer_styleguide_naming_types Types
@brief Naming conventions of library `typedef` types.
@formattable{types}
@formattableentry{`Iot`<b>LibraryDescription</b>`_t`<br>`AwsIot`<b>LibraryDescription</b>`_t`,General types in application-facing library header files,`IotMqttError_t` (iot_mqtt.h)<br>`AwsIotShadowError_t` (aws_iot_shadow.h)}
@formattableentry{`Iot`<b>LibraryFunction</b>`Info_t`<br>`AwsIot`<b>LibraryFunction</b>`Info_t`,Application-facing parameter structure,`IotMqttPublishInfo_t`<br>(Parameter structure to `IotMqtt_Publish`)<br>`AwsIotShadowDocumentInfo_t` <br>(Parameter structure for Shadow documents)}
@formattableentry{`_`<b>libraryDescription</b>`_t`,Type in an `internal` header,`_mqttOperation_t` (iot_mqtt_internal.h)<br>`_shadowOperation_t` (aws_iot_shadow_internal.h)}
@formattableentry{`_`<b>description</b>`_t`,Internal type in source file,`_topicMatchParams_t` (iot_mqtt_subscription.c)}
Types intended for use in applications are [UpperCamelCased](https://en.wikipedia.org/wiki/Camel_case). The names must start with `Iot` or `AwsIot` and end with `_t`. Parameter structures should indicate their associated function: for example, `IotMqttPublishInfo_t` is passed as a parameter to `IotMqtt_Publish`.
Types intended for internal library use defined in a header file are [lowerCamelCased](https://en.wikipedia.org/wiki/Camel_case). The names must start with `_`, followed by the library name, and end with `_t`. Internal types defined in a library source file must start with `_`, end with `_t`, and not include the library name.
`struct` typedefs should always be named along with the `typedef`. The struct name should be identical to the `typedef` name, but without the `_t` at the end. For example:
@code{c}
typedef struct IotLibraryStruct
{
int32_t member;
} IotLibraryStruct_t;
typedef struct _libraryInternalStruct
{
int32_t member;
} _libraryInternalStruct_t;
@endcode
A `struct` may contain anonymous `struct` or `union` members.
@subsection guide_developer_styleguide_naming_variables Variables
@brief Naming conventions of variables.
@formattable{variables}
@formattableentry{<b>variableDescription</b>,General local variable,`startTime`}
@formattableentry{`p`<b>VariableDescription</b>,Local variable pointers and arrays (including strings),`pSubscriptionList`}
@formattableentry{`_`<b>variableDescription</b>,Global variable that is `static`,`_connectMutex` (iot_mqtt_api.c)<br>`_pSamplePayload` (string)}
@formattableentry{`_Iot`<i>Library</i><b>Description</b><br>`_AwsIot`<i>Library</i><b>Description</b>,Global variable that is <b>NOT</b> `static`,`_IotMqttTaskPool` (iot_mqtt_operation.c)<br>`_pIotSamplePayload` (string)}
Local variable names are [lowerCamelCased](https://en.wikipedia.org/wiki/Camel_case) and consist only of a description of the variable. Names like `i` or `j` are acceptable for loop counters, but all other variables should have a descriptive name.
Global variable names always start with a `_`. Global variables that are `static` consist of only the description in [lowerCamelCase](https://en.wikipedia.org/wiki/Camel_case). Global variables that are not static consist of the library name <b>and</b> the description in [UpperCamelCase](https://en.wikipedia.org/wiki/Camel_case); for example: `_IotLibraryNonStaticGlobalVariable`.
All pointers, arrays, and strings (both global and local) start with `p` (local) or `_p` (global).
*/