UI layer shouldn't use directly DB types

Rule ND1403 Architecture

A sample rule to adapt to your need showing how to define code layers and be warned about dependency violations. It checks if any UI layer type directly uses any DB framework layer type.

- DB framework layer: third-party types of ADO.NET, EntityFramework, NHibernate consumed by the application (easy to adjust).

- UI layer: types using WPF, Windows Form, ASP.NET.

UI using directly DB frameworks is poor design: DB accesses should be hidden from UI in a dedicated Data Access Layer (DAL). Estimated debt is proportional to the UI/DB coupling.

How to fix

The rule lists which UI type uses which DB framework type. Rather than fixing matches one by one, first imagine how DB framework accesses could be encapsulated into a dedicated layer.

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>UI layer shouldn't use directly DB types</Name>
// <Id>ND1403:UILayerShouldntUseDirectlyDBTypes</Id>

warnif count > 0

// UI layer is made of types using a UI framework
let uiTypes = Application.Types.UsingAny(Assemblies.WithNameIn(
   "Microsoft.AspNetCore", "PresentationFramework", "System.Windows", "System.Windows.Forms", "System.Web"))

// You can easily customize this part to define what are DB types.
let dbTypes = ThirdParty.Assemblies.WithNameIn("System.Data", "EntityFramework", "NHibernate").ChildTypes()
              // Ideally even DataSet and associated, usage should be forbidden from UI layer: 
              // http://stackoverflow.com/questions/1708690/is-list-better-than-dataset-for-ui-layer-in-asp-net
              .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))

from uiType in uiTypes.UsingAny(dbTypes)
let dbTypesUsed = dbTypes.Intersect(uiType.TypesUsed)

let dbTypesAndMembersUsed = dbTypesUsed.Union(dbTypesUsed.ChildMembers().UsedBy(uiType))

// Per defaut this rule estimates a technical debt
// proportional to the coupling between the UI and DB types.
let couplingPerUIType = 2 +
   uiType.Methods.UsingAny(dbTypesUsed).Count() +
   dbTypesAndMembersUsed.Count()

select new { 
   uiType, 
   dbTypesAndMembersUsed,
   Debt = (4 * couplingPerUIType).ToMinutes().ToDebt(),
   Severity = Severity.High
}

//<Expl>
// The *{0}* shouldn't use directly *{1}* because doing so binds the UI layer directly with the DB layer.
//</Expl>
      
//<Desc>
// A *sample rule to adapt to your need* showing how to define code layers
// and be warned about dependency violations. It checks if any UI layer type
// directly uses any DB framework layer type.
//
// - **DB framework layer**: *third-party* types of *ADO.NET*,
// *EntityFramework*, *NHibernate* consumed by the application (easy to
// adjust).
//
// - **UI layer**: types using *WPF*, *Windows Form*, *ASP.NET*.
//
// *UI using directly DB frameworks* is *poor design*: DB accesses should be
// hidden from UI in a **dedicated Data Access Layer (DAL)**. Estimated debt
// is proportional to the UI/DB coupling.
//</Desc>

//<HowToFix>
// The rule lists which UI type uses which DB framework type. Rather than
// fixing matches one by one, first imagine how DB framework accesses could
// be encapsulated into a dedicated layer.
//</HowToFix>

Architecture: all 13 items