Ara3D.Domo 1.4.5

dotnet add package Ara3D.Domo --version 1.4.5                
NuGet\Install-Package Ara3D.Domo -Version 1.4.5                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ara3D.Domo" Version="1.4.5" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Ara3D.Domo --version 1.4.5                
#r "nuget: Ara3D.Domo, 1.4.5"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Ara3D.Domo as a Cake Addin
#addin nuget:?package=Ara3D.Domo&version=1.4.5

// Install Ara3D.Domo as a Cake Tool
#tool nuget:?package=Ara3D.Domo&version=1.4.5                

Domo

NuGet Version

Domo is a state management library for C#.

Overview

<i>The key to controlling complexity is a good domain model, a model that goes beyond a surface vision of a domain by introducing an underlying structure, which gives the software developers the leverage they need. A good domain model can be incredibly valuable, but it’s not something that’s easy to make.</i> <p>- Martin Fowler, 2003 in the preface to Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans

Domo (short for "Domain Modeling") is a .NET Standard 2.0 library that aids in building layered architecture applications inspired by good software engineering principles and best practices. Domo is inpsired by some of the lessons from Domain Driven Design, without being overly dogmatic.

Domo offers a solution for defining data models as simple immutable objects that are unaware of the infrastructure and application logic, while providing support for data binding, and offering advantages of a centralized data management system (like Redux).

Domo is an unopinionated cross-platform library with no dependencies and works well with other application frameworks and libraries (e.g., Entity Framework, Prism, MVVM Light, WPF Toolkit, etc.).

For an example of what using Domo can look like see: ChatDemo.cs in the test folder.

How Domo Works

Domo allow you to define the domain model using regular C# classes, structs, or records. There is no requirement to decorate the model type with special attributes, inherit from base classes, or implement a particular interface.

Domo wraps models types in an interface called IModel<T>. This interface

  1. provides a GUID to facilitate maintaining references when persisting the model
  2. implements INotifyPropertyChanged to inform of changes to the value
  3. references the repository which created and owns the model
  4. removes all event handlers in IDisposable.Dispose() to avoid memory leaks
public interface IModel<TValue> 
    : INotifyPropertyChanged, IDisposable
{
    Guid Id { get; }
    TValue Value { get; set; }
    IRepository<TValue> Repository { get; }
}

Notice that the model can be parameterized with structs, classes, or records. In DDD parlance this would be the difference between a "value" or "entity". Either way it is strongly recommended to use immutable types.

The property changed event handler is triggered when a new value is provided.

IModel instances are created, retrieved, updated, validated, and deleted by a repository class. This repository class ultimately is responsible for storing the model data is stored.

public interface IRepository<T>
    : IDisposable
{
    Guid RepositoryId { get; }
    Version Version { get; }
    IModel<T> Create(T model);
    bool Delete(Guid modelId);
    T Read(Guid modelId);
    bool Update(Guid modelId, Func<T,T> updateFunc);
    (bool, T) Validate(T value);
    IReadOnlyList<IModel<T>> GetModels();
}

There are two types of repositories, aggregate repositories which contain a collection of data models, and singleton repositories which manage precisely one data model.

    public interface IAggregateRepository<T> 
        : IRepository<T>, INotifyCollectionChanged
    { }

    public interface ISingletonRepository<T> 
        : IRepository<T>
    { }

All of the active repositories in an application are managed through an IDataStore

public interface IDataStore
    : IDisposable
{
    void AddRepository(IRepository repo);
    IReadOnlyList<IRepository> GetRepositories();
    void DeleteRepository(IRepository repository);
    IRepository GetRepository(Type type);   
    event EventHandler<RepositoryChangedArgs> RepositoryChanged;
}

Suggested Best Practices

The following are some suggested practices for using Domo:

  • Start new applications by creating the domain models first
  • Keep the domain models in a separate project
  • Make model types immutable
  • Use records as model types and leverage with expressions
  • Create a separate test project just for your domain models
  • Layer your domain models, so that higher-level models observe and react to changes in lower level models
  • Use Domo for application and infrastructure domain models as well.
  • Design and test your application so that arbitrary changes in the domain model are reflected throughout the API and the application, without putting it into an invalid state.
  • Don't be afraid to bind UI directly to domain models if/when appropriate

Advantages of Decoupled and Centralized Models

Domo can be used to manage the entire state of your application in a single location (the data store) in a stand-alone project. This simplifies many traditional tasks:

  • Testing
  • Changing the persistence mechanism of the data
  • Creating new applications with same data state
  • Synchronizing state over a network
  • Taking snap shots of the application state (e.g. auto-backup)
  • Creating undo/redo systems
  • Logging
  • Playback

An example of centralized state management is Redux a popular JavaScript state management library.

Domain Driven Design Principles

Eric Evans wrote the following insightful guidance in a white-paper called Domain-Driven Design Reference which are just plain old good ideas, regardless of whether one chooses to follow all of the recommendations of DDD or not.

Isolate the expression of the domain model and the business logic, and eliminate any dependency on infrastructure, user interface, or even application logic that is not business logic.

Partition a complex program into layers. Develop a design within each layer that is cohesive and that depends only on the layers below. Follow standard architectural patterns to provide loose coupling to the layers above.

The domain objects, free of the responsibility of displaying themselves, storing themselves, managing application tasks, and so forth, can be focused on expressing the domain model. This allows a model to evolve to be rich enough and clear enough to capture essential business knowledge and put it to work.

Further Reading

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Ara3D.Domo:

Package Downloads
Ara3D.Services

Infrastructure for creating well architected software.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.4.5 97 10/9/2024
1.4.4 134 8/25/2024
1.4.3 128 3/19/2024
1.4.1 119 3/12/2024
1.3.2 128 3/5/2024
1.3.0 125 3/3/2024
1.2.1 130 2/21/2024
1.0.0 114 2/21/2024