jezzsantos / saastack

A comprehensive codebase template for starting your real-world, fully featured SaaS web products. On the .NET platform
The Unlicense
45 stars 13 forks source link

Code Rules. Guidance and enforcement #10

Closed jezzsantos closed 8 months ago

jezzsantos commented 1 year ago

These coding rules should be backed by Rosyln Analyzers and Code Fixes.

API Class

Location: any project with variable: <HasApi>true</HasApi> Definition: Any instance method of an API class (instance class derived from IWebApiService)

Rules:

  1. Warning: Should return a Task<T> or T, where T is either ApiEmptyResult or ApiResult<TResource, TResponse> or ApiPostResult<TResource, TResponse>.
  2. Warning: must have at least one parameter, and first parameter must be IWebRequest<TResponse>, where TResponse is same type as in the return value. Second parameter can only be a CancellationToken
  3. Warning: method must be decorated with a WebApiRouteAttribute
  4. Warning: the route of all methods in this class should start with the same path
  5. Warning: should not have more than one method (in the same class) with the same TRequest

API project file (csproj)

Location: any project with variable: <HasApi>true</HasApi> Definition: N/A

Rules:

  1. Error: Should either have a package reference to SaaStack.Tools.Generators.WebApi or a project reference to Tools.Generators.WebApi.csproj
jezzsantos commented 1 year ago

commit 6c6fcd48eb535ceb24c75bdb780f8f68b02306a4 implemented the first few diagnostics

commit 04eb2d516310a6913f495fff0b2dc54d6d9c78a0 added project templates, which enforce the project references for the second part.

Not sure its worth implementing a Roslyn analyzer for a *.csproj file, since most developers don't spend much time inside them and may never see the diagnostics. However, the build warnings may direct them there. Can investigate

jezzsantos commented 1 year ago

Roslyn rules for Aggregates and value objects:

Root Aggregates

  1. classes that are derived from AggregateRootBase
  2. Must have at least one Create() factory method
  3. Must raise a create event in the Create method
  4. ctors must all be private
  5. Must have a public static AggregateRootFactory<TAggregateRoot> Rehydrate() method
  6. Is dehydratable if has a public Dehydrate() method
  7. If dehydratable, then must have a public override Dictionary<string, object?> Dehydrate method
  8. If dehydratable, then must have a [EntityName("AName")] attribute on the class

Entities

  1. classes that are derived from EntityBase
  2. Must have at least one Create() factory method
  3. ctors must all be private
  4. Is dehydratable if has a public Dehydrate() method
  5. If dehydratable, then must have a public override Dictionary<string, object?> Dehydrate method
  6. If dehydratable, then must have a public static EntityFactory<TEntity> Rehydrate() method
  7. If dehydratable, then must have a [EntityName("AName")] attribute on the class

Value Objects

  1. classes that derive from ValueObjectBase
  2. Must have at least one Create() factory method
  3. ctors must all be private
  4. must have public static ValueObjectFactory<TValueObject> Rehydrate() method
  5. Immutable methods only, or overriden
jezzsantos commented 11 months ago

Architecture Tests library NetArchTest, or ArchUnit NetArchUnit: https://www.youtube.com/watch?v=eWjNLYNS-og

Layers

API

Applicaton

Domain

Vertical Slices

jezzsantos commented 8 months ago

Last rule: (probably Roslyn)

Foreach ISubDomainModule, if the DomainAssembly property has a type (as opposed to null),

then load that type, and scan all entities and aggregates, and make sure they have entries in the AggregatePrefixes property

jezzsantos commented 8 months ago

CodeFixes: