Skip to content

Coding Standards

Aaron (Qilong) edited this page Oct 23, 2023 · 39 revisions

Coding Standards

Formatting

Usings

  • All system usings should go before custom usings, both usings block should be sorted. Setting of usings order can be found in the picture below, make sure you turn on Place 'System' directives first when sorting usings.

    • VS2019

    image

    • VS2022

    image

  • No unused usings should be introduced to the code base

Conditional Blocks

  • All conditional blocks should be enclosed in curly brackets. If a block is a one word statement, such as return, it can be placed on the same line.
// Acceptable...
if(something) return;

if(something)
{
  return;
}

//Not acceptable...
if(something)
  return;

Const

Mutation

Class Properties

Class property getters and setters should minimize side effects. Although possible, it's particularly dangerous to mutate other properties in a property setter.

Namespaces

Namespaces should adhere to the Namespace Naming Guidelines provided by Microsoft. Project sub-folder organization in Visual Studio should reflect the namespace structure.

Documentation

Where not specified otherwise in this document, you should adhere to the C# Coding Conventions.

Inline Comments

Use common sense. If the block of code you're writing is abstruse or does a lot in one line, consider commenting it. A good example are dense LINQ calls.

Class definition

For each method, provide the following:

  • A summary describing the purpose of the class and basic implementation details.

Here's an example

/// <summary>
/// Manages instantiation of custom nodes.  All custom nodes known to Dynamo should be stored
/// with this type.  This object implements late initialization of custom nodes by providing a 
/// single interface to initialize custom nodes.  
/// </summary>
public class CustomNodeLoader {
...
}

Class Properties

For properties, provide the following:

  • A summary what the property does.

Here's an example:

/// <summary>
/// A dictionary of node ids, keyed by the node names.
/// </summary>
public ObservableDictionary<string, Guid> NodeNames
{
    get;
    private set;
}

Class methods

For each method, provide the following:

  • A summary written in the imperative mood.
  • A descriptions for each parameter
  • A description of what the method returns if applicable.
  • Class and Method names should always be in Pascal Case.
  • Method argument and Local variables should always be in Camel Case
  • Avoid the use of underscore while naming identifiers
  • Constants should always be declared in UPPER_CASE.
  • Always prefix an interface with letter I.
  • For better code indentation and readability always align the curly braces vertically.
  • Declare the properties as private or internal unless they need to be exposed publicly.
  • Always separate the methods, different sections of program by one space.
  • Use Auto Properties for method fields.

Here's an example

/// <summary>
/// Get a node header (guid, name, category) from a given path.  This path points
/// usually to a .dyf file.
/// </summary>
/// <param name="path">The path from which to get the header</param>
/// <param name="guid">A reference to the guid (OUT) Guid.Empty if function returns false. </param>
/// <param name="name">A reference to the node name (OUT) Empty string if function returns false </param>
/// <param name="category">A reference to the category name (OUT) Empty string if function returns false </param>
/// <returns>Whether we successfully obtained the header or not.  </returns>
public static bool GetHeaderFromPath(string path, out Guid guid, out string name, out string category ) 
{
...
}

For zero-touch methods, it is highly recommended that you include the names of the output ports. This is discussed in more depth here.

  • Use a lambda expression, if you're defining an event handler that you don't need to remove later.
  • Unsubscribe the event handlers in the dispose method.
  • Use 'try-catch' and 'using' statements in exception handling.
  • Always use the 'using' keyword when working with disposable types. It automatically disposes the object when program flow leaves the scope.
  • Use LINQ queries, whenever possible.

Testing

For all new pieces of functionality, provide unit tests.

Framework

The Dynamo project uses NUnit for testing. Using ReSharper allows you to run unit tests directly from Visual Studio. If you don't have ReSharper, you probably should get it. Otherwise, get yourself a copy of NUnit - it's free.

Naming

Unit tests should be placed in a separate assembly from the one you are testing and named by appending "Tests" to the project name. For example, for the "DynamoCore" project the unit test assembly is called "DynamoCoreTests." Putting unit tests in a separate assemblies allows us to omit unit tests when shipping and naming them as such allows us to easily identify those assemblies.

Design considerations for unit-testing

If applicable, design your classes such that they can be unit-tested without needing to instantiate a large amount of other infrastructure (particularly user interfaces). This is all obvious good OOP. If you are passing DynamoModel as a reference to a method or class, you're probably doing something bad.

Releases

Roadmap

How To

Dynamo Internals

Contributing

Python3 Upgrade Work

Libraries

FAQs

API and Dynamo Nodes

Clone this wiki locally