Gist/documents/Powerof10Guide.md

5.3 KiB

NASA-style Programming for C#

I asked the coding AI to write their system prompt in the form of programming guidelines. They're based on NASA's Power of 10. I figured I'd use C# since it's both my preferred language and the language's syntax should be fairly easy to grasp once you understand the basics.

My only request was to apply .NET 6's top-level statements for brevity. Aside from a few organizational changes, minor tweaks to section 8, and adding the Program class to the scope example, it all works flawlessly.

Why NASA? Their coding standards have loads of redundancies, and if AI is going to behave like advanced code generation tools, they need to be as fault-tolerant as possible. While my instructions were modified to account for modern languages, the principles are still the same.

1. Write Clear, Well-Structured, and Maintainable Code

  • Keep the code simple and coherent. Use meaningful identifiers and limit the complexity of expressions.
  • Keep functions or methods short, with a single responsibility.

Example:

// Good example of a short, focused method
int Sum(int a, int b)
{
    return a + b;
}

// Good example of clear, well-structured code
var result = Sum(5, 3);
Console.WriteLine($"The sum is {result}");

2. Follow Best Practices for Security, Performance, and Reliability

  • Validate and sanitize inputs to prevent security vulnerabilities like injection attacks.
  • Use try-catch blocks to handle exceptions gracefully.

Example:

using System.Globalization;

string userInput = "2023-10-30";
if (DateTime.TryParseExact(userInput, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
{
    Console.WriteLine($"Parsed date: {date}");
}
else
{
    throw new FormatException("Invalid date format.");
}

3. Ensure Portability and Adaptability Across Different Environments

  • Use environment variables or configuration files for environment-specific settings.
  • Rely on cross-platform libraries within .NET.

Example:

// Reading configuration using environment variables
var configValue = Environment.GetEnvironmentVariable("CONFIG_KEY");
if (configValue != null)
{
    Console.WriteLine($"Configuration value: {configValue}");
}
else
{
    throw new InvalidOperationException("Configuration key not found.");
}

4. Manage Resources Efficiently and Safely

  • Prefer using statements to safely manage resource cleanup.
  • Avoid excessive memory allocation and prefer stack-allocated variables.

Example:

// Using statement to ensure safe disposal
using (var reader = new StreamReader("example.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

5. Use Minimal Scope for Variables and Functions

  • Limit the visibility of variables and functions to the smallest scope necessary.

Example:

namespace Application;

class Program
{
	static void Main()
	{
        // 'a' and 'b' are limited to Main method scope
		int a = 5, b = 3;
		Console.WriteLine($"Sum: {Add(a, b)}");
	}

	static int Add(int a, int b)
	{
		// 'a' and 'b' are limited to Add method scope
		return a + b;
	}
}

6. Always Validate and Sanitize Input

  • Sanitize and validate all external inputs to secure your application.

Example:

using System.Web;

string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
    throw new ArgumentException("Input cannot be null or whitespace.");
}
else
{
    string sanitizedInput = HttpUtility.HtmlEncode(input);
    Console.WriteLine($"Processed input: {sanitizedInput}");
}

7. Documentation Comments

  • Use XML documentation comments for functions or methods to improve maintainability and provide documentation.

Example:

/// <summary>
/// Sums two integers.
/// </summary>
/// <param name="a">The first integer.</param>
/// <param name="b">The second integer.</param>
/// <returns>The sum of the two integers.</returns>
int Sum(int a, int b)
{
    return a + b;
}

8. Use Preprocessors, Macros, or Metaprogramming Techniques Sparingly to Maintain Code Clarity

  • Preprocessor directives can be useful for conditional compilation but should be used judiciously to avoid obscuring the code.

Example:

#if DEBUG
Console.WriteLine("Running in Debug mode.");
#else
Console.WriteLine("Running in Release mode.");
#endif

int result = Sum(5, 3);
Console.WriteLine($"The sum is {result}");

int Sum(int a, int b) => a + b;

Example Using Top-Level Statements in .NET 6

Combining several of the above principles:

using System;
using System.Globalization;

string userInput = "45";
if (!int.TryParse(userInput, out int number))
{
    throw new FormatException("Invalid integer format.");
}

Console.WriteLine($"Parsed number: {number}");

void ProcessDate(string dateString)
{
    if (DateTime.TryParseExact(dateString, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
    {
        Console.WriteLine($"Parsed date: {date}");
    }
    else
    {
        throw new FormatException("Invalid date format.");
    }
}

ProcessDate("2023-10-31");