Skip to main content

Overview

Maintaining consistent coding standards ensures code quality, readability, and maintainability across all Intent Architect modules. These guidelines apply to all C# code, module specifications, and related artifacts.

General Principles

Clarity

Write code that is easy to read and understand. Prefer explicit over implicit.

Consistency

Follow established patterns in the codebase. Match the style of surrounding code.

Simplicity

Keep solutions simple and avoid over-engineering. YAGNI (You Aren’t Gonna Need It).

Testability

Design code to be testable. Separate concerns and minimize dependencies.

C# Coding Conventions

Naming Conventions

Follow standard .NET naming conventions:

Classes, Interfaces, and Methods

// Classes - PascalCase
public class TemplateFileBuilder { }

// Interfaces - PascalCase with 'I' prefix
public interface ITemplateLifeCycleHook { }

// Methods - PascalCase
public void GenerateTemplate() { }

// Properties - PascalCase
public string TemplateName { get; set; }

Fields and Variables

// Private fields - camelCase with underscore prefix
private readonly IApplication _application;
private string _templateId;

// Local variables - camelCase
var templatePath = GetTemplatePath();
int fileCount = 0;

// Constants - PascalCase
private const string DefaultOutputPath = "output";
public const int MaxRetries = 3;

Parameters and Arguments

// Parameters - camelCase
public void ProcessTemplate(string templateId, IOutputTarget outputTarget)
{
    // Implementation
}

File Organization

Organize class files in this order:
1

Using directives

Group and order using statements:
  1. System namespaces
  2. Third-party namespaces
  3. Intent namespaces
  4. Local project namespaces
using System;
using System.Collections.Generic;
using System.Linq;
using Intent.Engine;
using Intent.Modules.Common;
using Intent.Modules.Common.CSharp;
2

Namespace declaration

Use file-scoped namespaces (C# 10+) where possible:
namespace Intent.Modules.Common.CSharp.Templates;

public class CSharpTemplateBase { }
3

Class members order

Organize class members:
  1. Fields (constants, static, instance)
  2. Constructors
  3. Properties
  4. Public methods
  5. Protected methods
  6. Private methods
  7. Nested types

Code Formatting

Indentation and Spacing

// Use 4 spaces for indentation (not tabs)
public class Example
{
    private readonly string _value;
    
    // Single blank line between members
    public Example(string value)
    {
        _value = value;
    }
    
    public void ProcessValue()
    {
        if (string.IsNullOrWhiteSpace(_value))
        {
            return;
        }
        
        // Process value
    }
}

Braces and Line Breaks

// Always use braces, even for single-line statements
if (condition)
{
    DoSomething();
}

// Opening brace on new line (Allman style)
public void Method()
{
    // Implementation
}

// For lambda expressions, use appropriate formatting
var result = items
    .Where(x => x.IsActive)
    .Select(x => x.Name)
    .ToList();

Comments and Documentation

XML Documentation Comments

Provide XML documentation for public APIs:
/// <summary>
/// Generates C# code from the specified template.
/// </summary>
/// <param name="template">The template to generate code from.</param>
/// <param name="outputTarget">The output target for generated code.</param>
/// <returns>The generated C# code as a string.</returns>
/// <exception cref="ArgumentNullException">Thrown when template is null.</exception>
public string GenerateCode(ITemplate template, IOutputTarget outputTarget)
{
    // Implementation
}

Inline Comments

// Use comments to explain WHY, not WHAT
// Good: Explain reasoning
// We cache this value because the calculation is expensive
// and the value doesn't change during execution
var cachedResult = CalculateExpensiveOperation();

// Bad: Stating the obvious
// Set x to 10
var x = 10;

Language Features

Use Modern C# Features

// Prefer pattern matching
if (obj is TemplateFile templateFile)
{
    ProcessTemplateFile(templateFile);
}

// Use null-coalescing and null-conditional operators
var name = template?.Name ?? "default";

// Use expression-bodied members for simple operations
public string TemplateName => _template.Name;

// Use collection expressions (C# 12+)
var numbers = [1, 2, 3, 4, 5];

// Use string interpolation
var message = $"Processing template: {templateName}";

LINQ and Functional Patterns

// Prefer LINQ over imperative loops for collections
var activeTemplates = templates
    .Where(t => t.IsEnabled)
    .OrderBy(t => t.Priority)
    .ToList();

// Use method chaining appropriately
var result = collection
    .Where(x => x.IsValid)
    .Select(x => x.Transform())
    .FirstOrDefault();

Module-Specific Standards

Module Specifications (.imodspec)

All modules must have properly configured specifications:

Required Metadata

<?xml version="1.0" encoding="utf-8"?>
<package>
  <id>Intent.ModuleName</id>
  <version>1.0.0</version>
  <authors>Your Name or Organization</authors>
  <summary>Brief description of the module</summary>
  <description>Detailed description of what the module does</description>
  <iconUrl>data:image/svg+xml;base64,...</iconUrl>
  <tags>tag1 tag2 tag3</tags>
  <releaseNotes>release-notes.md</releaseNotes>
  <dependencies>
    <dependency id="Intent.Common" version="4.0.0" />
  </dependencies>
</package>

Version Requirements

1

Follow Semantic Versioning

Version numbers must follow SemVer format: MAJOR.MINOR.PATCH
  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (backward compatible)
2

Update release notes

Add an entry to the release notes file for each version:
### Version 1.2.3

- Fixed issue with template generation
- Added support for new attribute types
3

Update dependencies

Ensure all dependencies have explicit version numbers:
<!-- Good: Explicit version -->
<dependency id="Intent.Common.CSharp" version="4.1.0" />

<!-- Bad: Missing version -->
<dependency id="Intent.Common.CSharp" />

Template Development

Template Base Classes

// Use appropriate base classes from Intent.Modules.Common
public class MyTemplate : CSharpTemplateBase<IClassModel>
{
    public const string TemplateId = "MyModule.MyTemplate";
    
    public MyTemplate(IOutputTarget outputTarget, IClassModel model)
        : base(TemplateId, outputTarget, model)
    {
    }
    
    public override string TransformText()
    {
        // Template implementation
    }
}

Avoid Obsolete Dependencies

Do not add dependencies to modules marked as obsolete. The pre-build validation script will flag these as errors.

Quality Checks

Before submitting code, ensure it passes all validations:

Pre-Build Validations

The repository includes automated validation checks:
./PipelineScripts/pre-build-validations.ps1 -ModulesFolder "Modules" -TestsFolder "Tests"
This validates:
  • Module metadata is complete (authors, summary, description)
  • Version numbers are specified
  • Icons are properly embedded
  • Dependencies have versions
  • Release notes exist and contain current version
  • No obsolete dependencies
  • Tags are specified

Code Analysis

Enable and address warnings from:
  • Roslyn Analyzers - Built-in C# code analysis
  • StyleCop - Code style enforcement
  • ReSharper - Additional code quality checks (if available)

Build Verification

# Ensure clean build
dotnet clean
dotnet build

# Verify no warnings (treat warnings as errors)
dotnet build /p:TreatWarningsAsErrors=true

Common Patterns

Dependency Injection

// Use constructor injection
public class TemplateService
{
    private readonly ITemplateRepository _repository;
    private readonly ILogger _logger;
    
    public TemplateService(
        ITemplateRepository repository,
        ILogger logger)
    {
        _repository = repository;
        _logger = logger;
    }
}

Error Handling

// Be specific with exception types
try
{
    ProcessTemplate(template);
}
catch (ArgumentNullException ex)
{
    _logger.LogError(ex, "Template was null");
    throw;
}
catch (TemplateException ex)
{
    _logger.LogError(ex, "Template processing failed");
    // Handle or rethrow
}

Resource Management

// Use 'using' statements for IDisposable
using var stream = File.OpenRead(filePath);
using var reader = new StreamReader(stream);
var content = reader.ReadToEnd();

// Or traditional using blocks
using (var connection = CreateConnection())
{
    // Use connection
}

Next Steps

With coding standards in mind:
  1. Learn about Testing to ensure code quality
  2. Review the Pull Request Process for submission guidelines
  3. Explore existing modules to see these standards in practice
When in doubt, follow the style and patterns of existing code in the repository. Consistency is key!

Build docs developers (and LLMs) love