Skip to content

Arch Forum 2025-05-15

Participants: Backend devs & Victor

Agenda

  • File-scoped namespaces
  • Namespace import region
  • Launch settings (Docker, WSL, IIS, IISExpress, Kestrel)
  • Timeline model move out from Transaction domain to Core Shared (Lars)
  • C# Nullable and more (Anders)
  • Prefer non-nullable patterns

Summary

File-scoped namespaces

File-scoped namespaces are a feature introduced in C# 10 details here.
We have already started to use them.

Discussion Result:
- We should use them whenever we can.
- If possible, they should be enforced by editorconfig. Some areas have already updated their editorconfigs to do this.

Namespace import region

Today we often wrap the using statements in a file in a #region Namespace Imports region.

Discussion Result:
- This is legacy and not something we need.
- We are free to remove them whenever we can.
- If possible, they should be removed by editorconfig.

Launch settings (Docker, WSL, IIS, IISExpress, Kestrel)

Today we have a mix of launch settings in different projects, usually a mix of Docker, WSL, IIS, IISExpress, or Kestrel, but there can be others as well.
Example in MoneyIn.Ach.Api here.

Discussion Result:
- We only need the Kestrel one; all others can be removed.
- Let's run a script to fix this everywhere.

Timeline model move out from Transaction domain to Core Shared

In Phone Plan, there's a need for a timeline that is the same model as the timeline used in Transaction Details.

https://github.com/majority-dev/be-bank-platform/tree/master/Minority/Bank.Platform/Minority.Transactions.Domain.Contract/TransactionDetails

Discussion Result:
- The Timeline is moved with this PR.

C# Nullable and more (Anders)

Anders walked through a couple of different features and patterns that can be good, especially around nullability.

Nullable:

  • Already discussed in Arch Forum 2024-12-05.
  • Nullable should be enforced in new projects (<Nullable>enable</Nullable>).
  • Nullable should be annotated in existing projects (<Nullable>annotations</Nullable>).

Required modifier:

  • Details on how it works here.
  • We should use required whenever possible, e.g., when a property is required to be set.

Avoiding nulls:

Instead of allowing a value to be null, it's better to try and instantiate the value directly.

Not optimal, here invoiceEntity is a nullable type.

var invoiceEntity = await _invoiceRepository.Get(evt.InvoiceId);
if (invoiceEntity == null)
{
    throw new NotFoundException("Invoice not found");
}

Instead, in this way, the type of invoiceEntity can be non-nullable.

var invoiceEntity = await _invoiceRepository.Get(evt.InvoiceId)
            ?? throw new NotFoundException("Invoice not found");

Primary constructor (bonus)

Primary constructors are described in detail here.

This sparked some concerns (i.e., with primary constructors, the constructor-injected objects can no longer be readonly). For now, their use is on a wait-and-see basis. The c# team might add the readonly. Another option would be a static analyzer that checks it.

Some questions around variable naming came up.
- It would be good to enforce a naming standard for variables, class members, etc. (_name vs name vs NAME vs Name and so on in different places).

Records (bonus)

Records are described in detail here.

They should be good to use, but not all platform code supports using records (e.g., in events).

  • Records are good and, long-term, something we should use.
  • Not all platform code supports them. PRs that add support for them are welcome.
  • If you use them, make sure to test properly because of the possible platform non/partial-support.