Skip to content

Latest commit

 

History

History
231 lines (185 loc) · 8.35 KB

ARCHITECTURE.md

File metadata and controls

231 lines (185 loc) · 8.35 KB

Solid Instruments


Architectural Guide

The Solid Instruments product deliverables consist of a collection of .NET Standard libraries which are distributed as NuGet packages via the NuGet Gallery.

Principles

Our team is committed to seeking, adopting and maintaining best practices. Here are some philosophies that guide our decision making at a high level.

Transparency over flexibility

In most cases, the team should...

favor a design that

  • advertises its modes of failure
  • fails as advertised
  • cultivates trust among users
/// <summary>
/// Converts the current <see cref="String" /> to an array of bytes.
/// </summary>
/// <param name="target">
/// The current instance of the <see cref="String" />.
/// </param>
/// <param name="encoding">
/// The encoding to use.
/// </param>
/// <returns>
/// An array of bytes representing the current <see cref="String" />.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="encoding" /> is <see langword="null" />.
/// </exception>
/// <exception cref="EncoderFallbackException">
/// The current <see cref="String" /> could not be decoded; a fallback occurred.
/// </exception>
public static Byte[] ToByteArray(this String target, Encoding encoding)
{
    encoding.RejectIf().IsNull(nameof(encoding));
    return encoding.GetBytes(target);
}

over a design that

  • obscures important functional details
  • tolerates external faults
  • casts doubt upon expected behavior
/// <summary>
/// Converts the current <see cref="String" /> to an array of bytes.
/// </summary>
/// <param name="target">
/// The current instance of the <see cref="String" />.
/// </param>
/// <param name="encoding">
/// The encoding to use.
/// </param>
/// <returns>
/// An array of bytes representing the current <see cref="String" />.
/// </returns>
public static Byte[] ToByteArray(this String target, Encoding encoding)
{
    if (encoding is null)
    {
        return Array.Empty<Byte>();
    }

    try
    {
        return encoding.GetBytes(target);
    }
    catch (EncoderFallbackException)
    {
        return null;
    }
}

Consistency over novelty

In most cases, the team should...

favor a design that

  • uses perennial technologies and/or patterns
  • establishes or adheres to meaningful conventions
  • sets forth clear, helpful, repeatable examples for others
/// <summary>
/// Converts the specified <see cref="String" /> representation of a semantic version to its <see cref="SemanticVersion" />
/// equivalent. The method returns a value that indicates whether the conversion succeeded.
/// </summary>
/// <param name="input">
/// A <see cref="String" /> containing a semantic version to convert.
/// </param>
/// <param name="result">
/// The parsed result if the operation is successful, otherwise the default instance.
/// </param>
/// <returns>
/// <see langword="true" /> if the parse operation is successful, otherwise <see langword="false" />.
/// </returns>
public static Boolean TryParse(String input, out SemanticVersion result)
{
    if (Parse(input, out var value, false))
    {
        result = value;
        return true;
    }

    result = default;
    return false;
}

over a design that

  • introduces new technologies and/or patterns
  • departs from established, meaningful conventions
  • confuses others
/// <summary>
/// Attempts to hydrate the current <see cref="SemanticVersion" /> using the specified <see cref="String" /> representation
/// of a semantic version.
/// </summary>
/// <param name="input">
/// A <see cref="String" /> containing a semantic version to import.
/// </param>
public void SafeImport(String input)
{
    try
    {
        var parsedOutput = Parse(input);
        MajorVersion = parsedOutput.MajorVersion;
        MinorVersion = parsedOutput.MinorVersion;
        PatchVersion = parsedOutput.PatchVersion;
        PreReleaseLabel = parsedOutput.PreReleaseLabel;
        BuildMetadata = parsedOutput.BuildMetadata;
    }
    catch
    {
        return;
    }
}

Clarity over brevity

In most cases, the team should...

favor a design that

  • employs unambiguous terminology and naming conventions
  • is thoroughly documented
  • can be readily understood and used by others
/// <summary>
/// Gets a value indicating whether or not the current <see cref="ICryptographicProcessor" /> can be used to encrypt or
/// decrypt information using symmetric key cryptography.
/// </summary>
public Boolean SupportsSymmetricKeyEncryption
{
    get;
}

over a design that

  • was developed quickly
  • saves visual space on screen
  • can only be understood and used after careful research
public Boolean Encrypts
{
    get;
}

Adherence to object oriented principles

We are committed to engineering excellence. We welcome creative and pioneering approaches, but we also understand that the most straightforward paths toward success are those paved by professionals who traveled before us. We observe and find great value in the SOLID principles. Our oversimplified statements of expectation with respect to SOLID are as follows.

  • In most cases, your class or interface should serve one purpose. Don't reuse types for varying workloads.
  • When it is meaningful to do so, provide ways for other developers to extend the behavior of your components without disrupting their original purpose.
  • Derived types should be usable as instances of the type from which they are derived.
  • Try not to create interfaces that do too many things (or, if you must, split them into distinct interfaces with smaller, related groups of functionality).
  • Prefer dependency injection over self-composition whenever feasible. Ask for what you need in the constructor rather than creating it yourself.

There are good reasons to deviate from these guidelines and we do. Start a conversation when in doubt.

Dependencies

The maintainers of Solid Instruments make every effort to minimize the inclusion of third-party dependencies. Several of the constituent libraries expose implementations of first-party abstractions for competing third-party product libraries. Those first-party abstractions are listed below with their accompanying implementations.

To review the constituent library dependencies, navigate to any library from this page and expand the "Dependencies" section.

More information

If you haven't already, please review the Instructions for Contributing, where you will find guidance on other topics such as support and revision control. For a thorough treatment on coding standards review the Development Guidelines. For questions, contact [email protected].




RapidField

Copyright (c) RapidField LLC. All rights reserved. "RapidField" and "Solid Instruments" are trademarks of RapidField LLC.