Engineering/Engineering Principles/Developer Standards/

Developer Standards

These standards outline the expectations for developers at Audacia - covering design, implementation, maintainability, security, and performance.

DevOps & Delivery

Deployments must be automated · DEVOPS-02.1 · MUST · DEV

Deployment rollbacks should be automated · DEVOPS-02.2 · MUST · DEV

It should be as quick and easy as possible to revert a deployment if needed.

Software updates must be deployed securely · DEVOPS-02.3 · MUST · DEV

Deployments must protect the confidentiality of software and configuration. Use secure, encrypted channels and avoid manual mechanisms.

  • Deploy only build artifacts from controlled Build pipelines.
  • Store credentials in a Key Vault or Variable Group Secret. Never use plain‑text secrets.
  • Use dedicated service principals with minimal RBAC to maintain least-privilage.
  • Require pipeline approvals for production releases.

Infrastructure creation should be automated using Infrastructure as Code · DEVOPS-04.1 · MUST · DEV

Use tools such as Terraform or Azure Bicep to automate infrastructure creation and maintenance.

Use YAML pipelines · DEVOPS-01.1 · MUST · DEV/TEST

Always use YAML (YAML Ain’t Markup Language) when creating DevOps pipelines.

Use lower, kebab case for file name, e.g. 'build-app.job.yaml'. · DEVOPS-01.2 · MUST · DEV/TEST

Always use lower, kebab case for file name. For example: build-app.job.yaml

Use Pascal, snake case for IDs, including the type, e.g. 'Job_Build_App'. · DEVOPS-01.3 · MUST · DEV/TEST

Always use Pascal, snake case for IDs, including the type. For example: Job_Build_App

Include a blank line between steps. · DEVOPS-01.4 · MUST · DEV/TEST

Always include a blank line between steps.

steps:
  - task: PowerShell@2
    inputs:
      targetType: inline
      script: Write-Host "Hello world"

  - task: PowerShell@2
    inputs:
      targetType: inline
      script: Write-Host "Goodbye world"

Batch changes when using the CI trigger. · DEVOPS-01.5 · MUST · DEV

Always batch changes when using the CI trigger.

Include an approval gate for deployments to customer-facing environments. · DEVOPS-01.6 · MUST · DEV/TEST

Always include an approval gate for deployments to customer-facing environments. View documentation

Use folders to group pipelines. · DEVOPS-01.10 · MUST · DEV/TEST

Always use a sensible folder structure for grouping pipelines (e.g., /deployment or /testing)

Restricted
Login to display internal content.
Sensible defaults can be found in the wiki here

Include an approval gate for deployments to internal environments. · DEVOPS-01.7 · SHOULD · DEV/TEST

It is strongly recommended that you include an approval gate for deployments to internal environments.

Split stages and jobs into their own file. · DEVOPS-01.8 · SHOULD · DEV/TEST

It is strongly recommended that you split stages and jobs into their own file.

Include explicit 'Use Node' and 'Use .NET' steps. · DEVOPS-01.9 · SHOULD · DEV/TEST

It is strongly recommended that you include explicit Use Node and Use .NET steps.

# Use Node.js ecosystem v1
# Set up a Node.js environment and add it to the PATH, additionally providing proxy support.
- task: UseNode@1
  inputs:
    #version: '10.x' # string. Version. Default: 10.x.
    #checkLatest: false # boolean. Check for Latest Version. Default: false.
    #force32bit: false # boolean. Use 32 bit version on x64 agents. Default: false.
  # advanced
    #retryCountOnDownloadFails: '5' # string. Set retry count when nodes downloads failed. Default: 5.
    #delayBetweenRetries: '1000' # string. Set delay between retries. Default: 1000.
# Use .NET Core v2
# Acquires a specific version of the .NET Core SDK from the internet or the local cache and adds it to the PATH. Use this task to change the version of .NET Core used in subsequent tasks. Additionally provides proxy support.
- task: UseDotNet@2
  inputs:
  #packageType: 'sdk' # 'runtime' | 'sdk'. Package to install. Default: sdk.
  #useGlobalJson: false # boolean. Optional. Use when packageType = sdk. Use global json. Default: false.
  #workingDirectory: # string. Optional. Use when useGlobalJson = true. Working Directory. 
  #version: # string. Optional. Use when useGlobalJson = false || packageType = runtime. Version. 
  #includePreviewVersions: false # boolean. Optional. Use when useGlobalJson = false  || packageType = runtime. Include Preview Versions. Default: false.
  # Advanced
  #vsVersion: # string. Compatible Visual Studio version. 
  #installationPath: '$(Agent.ToolsDirectory)/dotnet' # string. Path To Install .Net Core. Default: $(Agent.ToolsDirectory)/dotnet.
  #performMultiLevelLookup: false # boolean. Perform Multi Level Lookup. Default: false.

Parameters must be explicitly and unambiguously named · DEVOPS-03.1 · MUST · DEV/TEST

The name must clearly describe the parameter’s purpose without requiring additional context, ensuring that anyone can reliably identify and reference it.

Each parameter must be clearly and individually declared · DEVOPS-03.2 · MUST · DEV/TEST

To support clarity and prevent misinterpretation, each parameter must be declared on its own rather than embedded in compact or nested structures.

Parameter definitions must include essential metadata · DEVOPS-03.3 · MUST · DEV/TEST

All parameters must provide the necessary context to function predictably. This includes core attributes such as identifier, type, and default behaviour / value.

Parameter names must follow consistent naming conventions · DEVOPS-03.4 · MUST · DEV/TEST

Use a consistent casing convention (e.g. camelCase) for parameter names to ensure readability and familiarity across pipelines and projects.

Variables must be defined in a controlled and traceable manner · DEVOPS-03.5 · MUST · DEV/TEST

Avoid scattering variable definitions across pipeline stages. Use centralized declarations (e.g., variable groups, templates) to promote transparency and version control.

Secure variables must be stored in approved secret management tools · DEVOPS-03.6 · MUST · DEV/TEST

Sensitive values (e.g., connection strings, API keys) must be stored using secure mechanisms such as:

  • Azure DevOps Library Secure Files
  • Secret variable within a variable group
  • Azure Key Vault integration

Variable scope must match usage context · DEVOPS-03.7 · MUST · DEV/TEST

Define variables at the most appropriate scope:

  • Pipeline-level for global use
  • Stage/job-level for isolated logic
  • Environment-level for deployment scenarios

Avoid overly broad scoping, which can lead to unexpected overrides or conflicts.

Variable names must use a consistent format · DEVOPS-03.8 · MUST · DEV/TEST

Use a clear naming convention such as UPPER_SNAKE_CASE or camelCase, depending on the team standard. Prefix values logically where relevant (e.g., dbConnectionString, testTimeoutMinutes).

Common variables must be centralized for reuse · DEVOPS-03.9 · MUST · DEV/TEST

Frequent or shared values must be placed in reusable variable groups or YAML includes. This minimizes duplication and improves maintainability.


Quality

Static code analysis must be configured for all application code · QUAL-02.1 · MUST · DEV

Static code analysis warnings must fail the build · QUAL-02.2 · MUST · DEV

NOTE On legacy codebases this can be a target that is being worked towards.

REST APIs must be documented using the OpenAPI standard · REST-01.1 · MUST · DEV

The following things must be included in the documentation:

  • Request types
  • Response types
  • Response codes

The appropriate HTTP verb must be used · REST-02.1 · MUST · DEV

Depending on the operation being performed by the API, the following HTTP verbs must be used:

  • GET: Read-only operation that returns data
  • PUT: Write operation that updates existing data
  • POST: Write operation that creates new data
  • DELETE: Write operation that removes existing data

It is important to note that GET, PUT and DELETE endpoints should be idempotent. If an endpoint is not idempotent (e.g. as well as updating/deleting/retrieving data, it also creates some data) then POST should be used.

Routes should be nouns · REST-02.2 · SHOULD · DEV

Nouns should primarily be used when building routes.

Simple routes must be based on nouns rather than verbs, e.g. /customers rather than /getCustomers, where the nouns are ‘resources’.

An exception to this rule would be that verbs can be used to represent a specific action to be taken on a resource, usually being specified at the end of the route, e.g. movies/{id}/play.

Routes must contain the IDs they act upon · REST-02.3 · MUST · DEV

Any endpoint that is performing an action on a specific item must specify the ID in the route, e.g. /customers/{id}. This applies to GET, PUT and DELETE requests.

If resources have children then it is often appropriate to reflect this in the route. For example, if each customer has a collection of addresses, then a good route would be /customers/{id}/addresses, where the {id} placeholder is the ID of the customer.

Routes should not have a depth greater than three · REST-02.4 · SHOULD · DEV

Limit the depth to which child resources are nested in a route to three levels, wherever possible.

For example, one/{idOne}/two/{idTwo}/three/{idthree} would be appropriate however one/{idOne}/two/{idTwo}/three/{idThree}/four should be restructured, possibly by making the resource two the root of the route.

Controllers must contain the endpoints for a single resource · REST-02.5 · MUST · DEV

Controllers must contain the endpoints for a single resource (following the single responsibility principle).

For example, endpoints at the root of customers (GET /customers/{id}) would be in the CustomersController. Endpoints for child resources should be in their own controller, meaning GET customers/{id}/addresses would be in the AddressesController.

Route naming must be consistent · REST-02.6 · MUST · DEV

Kebab-cased urls are preferred, e.g. /order-items rather than /orderItems.

When defining routes for a controller avoid using [Route(“[controller]”)], as this couples the url to the name of the controller. It is therefore possible to break clients by renaming a controller.

Successful GET requests must return a 200 (OK) status code · REST-03.1 · MUST · DEV

Successful GET requests must return data · REST-03.2 · MUST · DEV

  • If the GET request is for a specific ID (i.e. /customers/{id}), the response body should be a single object, which may be empty.
  • If the GET request is not for a specific ID (i.e. /customers or /customers?city=Leeds), the response body should be an array containing zero or more objects.

PUT requests that have been successfully processed must return a 204 (No Content) status code · REST-03.3 · MUST · DEV

PUT requests that have been accepted to be processed asynchronously must return a 202 status code · REST-03.4 · MUST · DEV

POST requests that have been successfully processed must return a 201 (Created) status code · REST-03.5 · MUST · DEV

Successful POST requests must include a location header · REST-03.6 · MUST · DEV

A location header should be included set to the url from which the resource can be obtained in future (i.e. the appropriate GET endpoint). ASP.NET Core provides the CreatedAtAction method to do this.

EXCEPTION This does not apply if the POST endpoint is for a search (e.g. where there are too many filters to capture in a query string so GET cannot be used).

POST requests that have been accepted to be processed asynchronously must return a 202 status code · REST-03.7 · MUST · DEV

Successful POST requests should return the data that has been created · REST-03.8 · SHOULD · DEV

The object created (including its ID) should be returned in the response body. If the object is large, or if it is infeasible to return the entire object, then the ID should be returned.

DELETE requests that have been successfully processed must return a 204 (No Content) status code · REST-03.9 · MUST · DEV

DELETE requests that have been accepted to be processed asynchronously must return a 202 status code · REST-03.10 · MUST · DEV

All API endpoints that receive data must validate that input · REST-04.1 · MUST · DEV

For example, validating the content of a request body, or the ID in a query string.

Validation errors should be returned as a 400 (Bad Request) status code · REST-04.2 · SHOULD · DEV

A validation error is an error on behalf of the client, and there a code in the 4** range is appropriate. Generally speaking a 400 status code is the best choice.

Error HTTP status codes must contain information about the error returned · REST-04.3 · MUST · DEV

In the case of a non-2** status code being returned, a response body must contain information about the error.

The structure of the error response must be consistent across the API, i.e. all responses should have a body with the same structure. The following points should be considered:

  • Return a list of errors rather than a single error
  • Return an error code as well as a message

Conventional Commits must be used for commit messages · QUAL-04.1 · MUST · DEV/TEST

Commit messages must follow the Conventional Commits specification.

It is strongly recommended that projects at least use types from the specification to communicate the main purpose of the commit, e.g.:

  • feat: for new features
  • fix: for bug fixes
  • docs: for documentation changes
  • refactor: for refactoring
  • etc. (any type from the specification can be used)

Projects can optionally go beyond just using the type and follow the full specification, which includes additional features such as:

  • Including a scope after the type, e.g. the scope api after a feature would be feat(api):
  • Communicating breaking changes by appending a ! after the type/scope, e.g. feat!:
  • Including a footer

Commit messages must including work item number · QUAL-04.2 · MUST · DEV/TEST

The work item number (e.g. PBI or Bug) must be added to the end of the commit message. For example: fix: added phone number validation #xxxx, where #xxxx is the card related to the commit

A branch policy must be set on main development branches · QUAL-05.1 · MUST · DEV/TEST

Code reviews must be enforced by setting a branch policy on the main development branches (e.g. dev and/or main) with the following settings:

  1. Require a minimum of at least 1 reviewer (an individual project can require more than 1 reviewer if desired).
  2. Do not allow users to approve their own changes (unless the minimum number of reviewers is more than 1).
  3. ‘Reset code reviewer votes when there are new changes’ should be selected.
  4. ‘Check for linked work items’ should be required.
  5. ‘Check for comment resolution’ should be required.
  6. ‘Limit merge types’ should generally be set to ‘Basic merge (no fast-forward)’.
  7. ‘Build validation’ should be set for the relevant build pipeline(s) to ensure that the pull request doesn’t break the build, with the expiration set to immediately.

Projects can diverge from this policy provided it makes the policy stricter rather than more relaxed. For example, requiring more than 1 reviewer.

Technical debt must be documented · QUAL-01.1 · MUST · DEV/TEST


Documentation

Delivery team roles and responsibilities must be documented · DOC-01.1 · MUST · DEV/TEST

These role and responsibilities can be captured as a RACI matrix, or something less formal if preferable.

Client key contacts must be documented · DOC-01.2 · MUST · DEV/TEST

Important information to capture includes each person’s contact details, role and decision-making authority on the project.

An overview of each delivery phase must be documented · DOC-01.3 · MUST · DEV/TEST

At a minimum, the following information must be included:

  • List of each phase delivered
  • Delivery dates
  • High-level summary of what was delivered in each phase.

EXCEPTION This is not applicable to projects that have not had multiple delivery phases.

README files must contain a title and introduction to detail the purpose of the repository · DOC-04.1 · MUST · DEV/TEST

README files must document the technologies used within the repository · DOC-04.2 · MUST · DEV/TEST

The main technologies used and any pre-requisite software that must be installed must be listed in the README: for example .NET 10, Node.js 20, Playwright.

README files must document how to use the repository locally · DOC-04.3 · MUST · DEV/TEST

Application Code

  1. Document any required installs, such as SSL Certificates
  2. Document any configuration files such as appsettings.Development.json or nuget.config
  3. Document how to setup local development, including any local databases
  4. Document how to run the application locally, explaining any npm scripts and any command-line options or parameters that must be provided
  5. Document any additional applications (such as IDEs, or IDE extensions/plugins) which are needed for debugging etc.

Automated Tests

  1. Document any required installs
  2. Document any credentials required to run the tests and the file they should be added to. For example, contributors should populate cypress.env.json from the UI Cypress Tests record in Keeper.
  3. Document how to run the tests locally, explaining any npm scripts and any command-line options or parameters that must be provided
  4. Document any additional applications which may be used. For example, Playwright Test for VSCode by Microsoft.

Key system workflows must be documented · DOC-02.1 · MUST · DEV/TEST

A glossary of terms and acronyms used within a project must be provided · DOC-02.2 · MUST · DEV/TEST

A known issues log must be maintained · DOC-02.3 · MUST · DEV/TEST

System roles and permissions must be documented · DOC-02.4 · MUST · DEV/TEST

The architecture of a system must be documented · DOC-03.1 · MUST · DEV

This should be documented in the form of one or more architecture diagrams.

Restricted
Login to display internal content.
Sensible default rules for the creation of architecture diagrams can be found in the wiki.

Architecture decision records (ADRs) must be written to record key technical decisions · DOC-03.2 · MUST · DEV/TEST

ADRs can be included in the main project wiki or in the same repo as the source code (and linked to from the main wiki).

Restricted
Login to display internal content.
Sensible default rules for ADRs in the wiki.

The hosting location and access must be documented · DOC-03.3 · MUST · DEV

Possible hosting locations include:

  • Audacia CSP hosted
  • Client hosted
  • Third-party hosted (the third-party must be specified)

Some examples of access that should be documented are:

  • Guest accounts in an external Azure tenant
  • Separate client-provided accounts
  • Any specific access requirements, like a VPN or white-listed IP address

Environments and system URLs must be documented · DOC-03.4 · MUST · DEV

NOTE This information must be recorded in Olympus.

Non-functional requirements must be documented · DOC-03.5 · MUST · DEV/TEST

Examples of non-functional requirements are:

  • Performance and response times
  • Accessibility
  • Device testing requirements (these should be captured in the Test Strategy)
  • Logging and observability

Deployment and release processes must be documented · DOC-03.6 · MUST · DEV

The kind of processes that should be documented include:

  • CI/CD pipelines
  • Health checks
  • Release windows, i.e. any days/times agreed by the client
  • Manual processes (where applicable)
  • Rollback procedure

The branching strategy must be documented · DOC-03.7 · MUST · DEV/TEST

This should include the overall strategy, the reasoning behind it, and any specific details such as naming conventions, e.g. release/.

Disaster recovery processes must be documented · DOC-03.8 · MUST · DEV

The following items must be included:

  • Agreed Recovery Time Objective (RTO) and Recovery Point Objective (RPO), or if none has been agreed a statement to this effect together with a reference to when this decision was made
  • Details of any processes to follow beyond restoring data to a known point, e.g. any manual failover tasks or fallback to paper-based processes
  • Details of what backups are taken, at what frequency, to what location, and who owns them

External resources must be listed and signposted · DOC-03.9 · MUST · DEV/TEST

For example, Postman collections or JMeter scripts.

The use of feature switches must be documented · DOC-03.10 · MUST · DEV

NOTE This is only applicable if feature switches are actually in use.

A troubleshooting quickstart guide must be provided · DOC-03.12 · MUST · DEV

Include information that will be useful for anyone triaging or debugging an issue, such as where logs are located in each environment.


Observability

All hosting environments that incur a cost must have the expected cost documented · HC-01 · MUST · DEV

Each project must maintain a “Hosting Costs” page in the project wiki. This page must either:

  • Detail the expected monthly cost per environment, with the date of last review.
  • Link directly to the cloud provider’s cost management view for each environment (e.g. Azure Cost Management, AWS Budgets).

All environments must have a budget configured to alert on cost overruns · HC-02 · MUST · DEV

Configure a budget for each environment with alerts in the cloud provider’s cost management service. Alerts must notify the project team via agreed channels on cost overruns. Budget amounts must be kept up to date as resources are added, scaled or deprovisioned.

Tags must be used on the resource group to designate the environment and the customer · HC-03 · MUST · DEV

Apply tags on the resource group to enable accurate cost allocation. At a minimum, include:

  • environment: e.g. QA, UAT and Prod
  • customer: the client name or identifier

All budgets must be approved prior to creation or change · HC-04 · MUST · DEV

Budgets for any environment must be approved by IT before they are created, increased, or changed.

NOTE Approval of hosting costs for specific environments (e.g. Dev/QA) does not imply approval for other environments (e.g. UAT/Production), which may require separate formal sign-off.

Use structured logging · LOG-01.1 · MUST · DEV

Consistency and readability are crucial in our logs. Providing strong discoverability speeds up development and aides in diagnosing problems.

Unstructured logging example (❌)

console.log("User logged in at 2024-08-02T12:34:56Z");

Structured logging example (✅)

console.log(JSON.stringify(new Log(
  timestamp: "2024-08-02T12:34:56Z",
  level: "info",
  message: "User logged in",
  userId: 12345
));

Messages are clear and concise · LOG-01.2 · MUST · DEV

Each log message should be one or two sentences, which relay information relating to the level of the log.

e.g.

LevelMessage
InformationEntry: Attempting to save {numberOfInvoices} Invoices.
InformationSuccessfully saved Invoice {invoiceName}, Id: {invoiceId}.
ErrorError thrown while saving Invoice {invoiceName} due to a missing payment line.
InformationExit: Successfully saved {numberOfSuccesses}/{numberOfInvoices} Invoices.

Messages are templated · LOG-01.3 · MUST · DEV

Use templates for log messages instead of interpolation to ensure consistency and parsability.

What bad looks like (❌)

// Bad
_logger.LogInformation($"Processing Payment {paymentIdToProcess}");

This example creates a log from a simple string, making it less structured.

What good looks like (✅)

// Good
_logger.LogInformation("Processing Payment {paymentIdToProcess}", paymentIdToProcess);

This version uses a templated string, resulting in an enriched log with a custom property named paymentIdToProcess. This allows for better querying and analysis in the logging back-end.

Advantages of Templated Strings

  1. Consistency: Ensures that the overall structure of each message remains consistent.

  2. Queryability: Allows for specific and general searches. For example, you can query for:

    • “Processing Payment {paymentIdToProcess}” to get all occurrences of this log.
    • “Processing Payment 412” to find specific instances.
  3. Enhanced Context: You can pass complex objects instead of primitive types, enabling richer log details. Ensure these objects do not include Personal Identifiable Information (PII) unless approved by the client.

For example, if using Application Insights, you can search for “paymentIdToProcess” or “paymentIdToProcess 412” to pinpoint specific logs more effectively.

Use meaningful and engineer-friendly messages · LOG-01.4 · MUST · DEV

State the implication of the codes execution before or after the log line and the action an engineer would need to take (if any).

For example:

// Bad - vague with no explanation:
_logger.LogError("An error occured while trying to process the Payment {paymentId}", paymentId);

// Good - says specifically why:
_logger.LogError("Payment {paymentId} failed during processing because the customer's payment provider was not configured.", paymentId);

Avoid re-using user-facing error messages. Logs are read by engineers, the steps of which one would take to resolve the problem would differ greatly. “Please contact your system administrator” would help the user but not an engineer.

Never log sensitive data unless absolutely necessary · LOG-01.5 · MUST · DEV

Information such as passwords, application secrets (e.g. API Keys) and Personal Identifiable Information (PII) must only be logged if an agreement is in place with the client.

Logging sensitive data must be subject to agreements with the client · LOG-01.5.1 · MUST · DEV

Such an agreement must be made with security considerations regarding access-control and the right to be forgotten.

Store logs in secure & access-controlled ways · LOG-02 · MUST · DEV

Logs must be stored using secure solutions to protect client data. Application insights is a common option for this, but engineers are not restricted to this, so long as the alternative solution has access-control.

Use a consistent logging solution · LOG-03 · SHOULD · DEV

Use the same logging provider for the front-end, back-end or data layers respectively.

e.g. For a .NET backend, if one class implements logging via the ILogger Microsoft.Extensions.Logging , then other classes on the backend should use the same logging provider.

Whichever logging provider the UI uses (e.g. Sentry) then this should be used for all logging on the front end.

Whether logs are from the UI or the server, they should be viewable in the same monitoring solutions (e.g. Application Insights).

Use appropriate logging · LOG-04 · MUST · DEV

Use appropriate log levels · LOG-04.1 · MUST · DEV

Logs must have an assigned log level which describes how that log is intended to provide value.

LevelUsageExample
TraceDetailed information that will only be used when diagnosing bugs.LogTrace(“Starting search for disabled users.”, args[…])
DebugInformation that will be used when diagnosing bugs in debug mode and not production.LogDebug(“Deserialised JSON from {jsonString} to {object}”, args[…])
InformationHighlight the progress of the executing code.LogInformation(“Attempting to rename object with Id {id} from {oldName} to {newName}.”, args[…])
WarningEvents which are potentially, or could lead to, harmful situationsLogWarning(“Using a default Payment Provider as the value of one wasn’t provided.”, args[…])
ErrorError event occurred which might allow the code to continue runningLogError(“Could not find object with Id {id} and name {oldName} in the database.”, args[…])
CriticalError events which are severe and may halt the executing code.LogCritical(“Connection string is missing for database context {databaseContext}.”, args[…])

Avoid excessive logging that may cause performance degradation · LOG-04.2 · MUST · DEV

Logging should be performed judiciously throughout a user workflow to ensure that observability is seamlessly integrated without impacting performance. Excessive logging can lead to performance degradation and increased costs. Techniques such as Adaptive Sampling can automatically remove redundant log lines, which may result in loss of effort when too much logging has been implemented.

Debug Logs

If a log line is valuable for debugging but not essential for the production environment, consider using the Debug level. This helps keep production logs concise while still providing detailed information for development and troubleshooting.

Projects must have a client-agreed retention policy · LOG-04.3 · MUST · DEV

Every project should establish a log retention policy agreed upon with the client. This policy defines how long logs will be stored before they are archived or deleted. This ensures compliance with legal, operational, and business requirements.

Ensure log storage compliance with data location policies · LOG-04.4 · MUST · DEV

Logs must be stored in compliance with internal policies and applicable legislation regarding data location. Specifically, storing logs in non-UK/EU data centers may not be compliant and could lead to legal and regulatory issues. Always verify and adhere to data storage regulations relevant to your project to ensure compliance.

Don't repeat messages · LOG-04.5 · SHOULD · DEV

Each log message should contain information specific to the logic being executed around it. Ensure that each log line includes unique details that provide context for the execution.

Repeated log messages can hinder an engineer’s ability to find useful information during searches. Avoid duplication to maintain the effectiveness of your logging system.

Signpost significant application events · LOG-04.6 · SHOULD · DEV

Logging should be added to important workflow moments. This leaves breadcrumbs which can later be used to diagnose failure points in the application.

EventExample Message
Major code branching”Processing Payment 5 via the STRIPE strategy as a STRIPE signature was found.”
Domain events that will affect application behaviour”The PaymentProviderSelection feature switch has been turned on, the payment page now allows users to select their provider.”
The entry point of intensive processes”Entry: User 0f153eb6-ec66-4de6-9642-9dc2f8c3bfa9 initiated bulk processing of 100 payments.”
The exit point of intensive processes”Exit: Finished processing 100 payments successfully.”
The entry point of a brittle process”Attempting to send a payment process request to the STRIPE API.”

Automated Testing

Unit tests must be written to test application code · UT-01.1 · MUST · DEV

These basic rules should be followed:

  • Unit tests should cover core business logic and validation, including edge cases
  • Unit tests generally are not needed for simple CRUD functionality
  • Communication is needed with test engineers to ensure effort is not duplicated among different kinds of automated test
  • Unit testing is not a substitute for manual developer testing

Unit tests within a system must use a consistent naming convention · UT-01.2 · MUST · DEV

All unit test methods should follow the same naming convention. Each project can have it’s own conventions so long as it’s adequately documented.

Unit tests must have a descriptive name that documents the business logic under test · UT-01.3 · MUST · DEV

Writing unit tests as documentation helps to ensure that when the project is handed over to support, or when different teams are delivering new phases of work, there is clear, reliable, and up-to-date documentation of the code’s intended functionality. This facilitates smoother transitions and reduces onboarding time for new team members.

Unit tests must assert against the behaviour in the method name · UT-01.4 · MUST · DEV

In other words, don’t have a test method name that says one thing, and then assert on something else within the method.

Unit tests must be atomic · UT-01.5 · MUST · DEV

Each test must be independent of other tests, i.e. a test should not rely on any other test already having run.

Build validation must be in place to fail the build if unit tests fail · UT-01.6 · MUST · DEV

There should be a step in any pipeline that builds the software to also run unit tests.

Unit tests must not use data that may change between test runs · UT-01.7 · MUST · DEV

For example:

  • Randomly generated data
  • DateTime.Now/DateTime..Today

EXCEPTION Random data can be used if it does not impact the outcome of the test, e.g. a mandatory property that is not needed by the behaviour under test.

Unit tests should not mock objects that are under the control of the system under test · UT-01.8 · SHOULD · DEV

For example, you should generally not mock other classes within your codebase, but should mock things like external APIs, message queues, and email clients.

Unit tests should not re-use domain logic within tests · UT-01.9 · SHOULD · DEV

Generally speaking, when business logic code is changed, unit tests that test that logic should fail. Re-using domain logic in a test can mean that happen, and therefore should be avoided.

Unit tests should use realistic test data · UT-01.10 · SHOULD · DEV

Using realistic data in unit tests can help to document the behaviour under test and ensures that the tests are as close as possible to real-world usage.

NOTE The Audacia.Seed library can be used to help the structured, reusable generation of test data.


User Experience

Reuse Proven UI Patterns · UX-01.1 · MUST · DEV

Use widely adopted UI patterns for common flows such as sign-up, login, password reset, onboarding, etc. Avoid novelty in routine interactions unless it’s tied to product differentiation. Leveraging existing UX patterns reduces user learning curves and speeds up delivery. Reference aggregators like Mobbin or PageFlows for examples.

✓ Use centred forms, clear buttons, and familiar field layouts.
✓ Reference competitor flows where users already feel comfortable.

Set UX Goals Explicitly · UX-01.2 · MUST · DEV

Define a clear, outcome-focused goal for every user flow. Avoid focusing on UI components in isolation. Reframe goals as questions to guide better UX decisions.

✗ "Build a sign-up form with two text fields and a button."
✓ "How can we make sign-up as fast and error-proof as possible?"

This practice ensures the design stays focused on real outcomes like conversion or task completion.

Optimize for Edge Cases · UX-01.3 · MUST · DEV

Anticipate user errors and distractions. Build defences and guidance into the UI at both field and flow levels.

✓ Provide instant feedback on errors (e.g. mismatched passwords).
✓ Confirm input accuracy before submission (e.g. "confirm email").
✓ Display clear error messages: "We couldn't save your changes", not "500 Internal Server Error".

Good UX accounts for the 80% happy path and the 20% that causes real frustration.

Use Established Layout & Interaction Conventions · UX-01.4 · MUST · DEV

Stick to UI conventions users already know.

✓ Logo top-left
✓ Primary CTA bottom-right or centred
✓ Forms in vertical layout with visible labels
✓ Responsive design for all viewports

Avoid design award aesthetics that compromise usability. Favour familiarity and clarity over originality unless deliberately differentiating.

Keep Visual Design Simple · UX-01.5 · SHOULD · DEV

Use a restrained palette: one primary, one secondary, and one accent colour. Avoid visual noise. Use tools like Coolors for consistent colour schemes.

✓ Use consistent button styles across the app.
✓ Avoid gradients, excessive shadows, or non-functional animations.

Simple visuals reduce user distraction and improve focus.

Prioritize Clarity in Language · UX-01.6 · MUST · DEV

Use language familiar to your audience. Avoid technical jargon or developer-oriented messages.

✗ "Validation error: token mismatch"
✓ "You’ve been logged out. Please sign in again."

Write content as if explaining to a non-technical friend. Error states especially should offer solutions, not confusion.

Learn from Adjacent Domains · UX-01.7 · SHOULD · DEV

When designing new or uncommon flows (e.g. collecting sensitive data), look at adjacent industries:

✓ Study mortgage, tax, and legal apps for patterns around trust and risk.
✓ Identify how these platforms build credibility and reduce anxiety.

Use this insight to design flows that are clear, empathetic, and trustworthy.

Leverage AI for UX Testing · UX-01.8 · SHOULD · DEV/TEST

Use AI tools like ChatGPT for usability feedback. Simulate user perspectives to reveal blind spots. Example prompts:

✓ "Critique this sign-up flow: where could users get stuck?"
✓ "Act like a distracted user—what's confusing in this screen?"
✓ "How do top SaaS products design this flow?"

AI feedback isn’t final, but it helps prioritize areas for further testing or validation.

Choose Metrics That Matter · UX-01.9 · MUST · DEV

Define clear success metrics per flow: conversions, drop-off rate, completion time, or task success.

✓ Track user behaviour via tools like Amplitude or Hotjar.
✓ Use metrics to challenge assumptions and identify improvement areas.

Measuring UX makes quality tangible, allowing for iteration based on real-world feedback.

Follow Jakob's Law · UX-01.10 · SHOULD · DEV

Users spend most of their time on other sites. This means that users prefer your site to work the same way as all the other sites they already know.

Follow Jakob’s Law by defaulting to use what already works. Innovate only on your core differentiators.

✓ Use standard flows to train users via familiarity.
✓ Focus your innovation where it enhances value, not on aesthetics.

Efficient UX is about speed, clarity, and impact—not novelty.


Security & Availability

Applications must use Mailtrap for emails in test environments · DS-01 · MUST · DEV/TEST

Applications must use Mailtrap for emails in test environments

EXCEPTION: This requirement does not apply if the client has their own service or process in place for handling test emails.

Data must be anonymised when moved between environments · DS-02 · MUST · DEV/TEST

Sensitive data must be anonymised before being transferred between environments (e.g., from production to development or test).

Restricted
Login to display internal content.
For guidance on reporting data movements, refer to the Security Infrastructure FAQs%3F).

EXCEPTION: This requirement may be waived if the data is essential for reproducing a specific issue, provided there is a documented process in place to delete the data from the destination environment once it is no longer required.

Sensitive data must be stored securely · DS-03 · MUST · DEV/TEST

Sensitive data includes credentials, API keys, connection strings and certificates. Store only in approved secret stores and encrypted services. Never commit to source control or place in plain text in config.

  • Use a managed cloud secret store for secrets, keys and certificates (e.g. Azure Key Vault or AWS Secrets Manager).
  • Store pipeline secrets in your platform’s secure secret management (e.g. Azure DevOps Variable Groups or Github Actions secrets). Restrict access via RBAC and least privilege. See DEVOPS-03.6.
  • For local development, store .env secrets in Keeper as a “Secure Note”. Do not share as plain text.

A database backup strategy must be implemented in production environments · SEC-03.1 · MUST · DEV

For production environments where Audacia is responsible for a system’s infrastructure, a database backup strategy must be agreed with the client and documented in the project’s wiki.

Any backup strategy must enable compliance with any applicable data privacy legislation · SEC-03.2 · MUST · DEV

If a database contains personally identifiable information, a process must be agreed with the client to ensure that a user’s right to be forgotten under GDPR legislation is honoured. In the event of a database backup being recovered, any user who has requested to be forgotten must have their information removed.

The scope of the penetration test must be defined clearly in advance · PEN-01 · MUST · DEV/TEST

Define the scope explicitly before testing begins, specifying systems, applications, and components to be tested.

Recognised scope types include:

  • External Network Testing
  • Internal Network Testing
  • Web Application Testing
  • API Testing
  • Cloud Infrastructure Testing
  • Social Engineering (only if explicitly agreed)

The penetration test must have formal sign-off from the System Owner and Relevant Stakeholders before it begins · PEN-02 · MUST · DEV/TEST

An agreed contract or Statement of Work (SoW) from the testing provider must be in place and cover: scope, methodology, test windows, escalation paths, impact management, and legal statements.

Testing should be performed on a representative environment · PEN-03 · SHOULD · DEV/TEST

Prefer a non‑production environment that mirrors production configuration (e.g. Azure Front Door, Web Application Firewall). Avoid testing in production unless absolutely necessary and explicitly approved.

System access to conduct the penetration test must be controlled and monitored · PEN-04 · MUST · DEV/TEST

Grant the least privilege required for the duration of testing. Access must be time‑bound and revoked immediately after testing concludes. Maintain audit logs of access and tester activity, and rotate any credentials or tokens post‑test.

Penetration testers must not have access to production data · PEN-05 · MUST · DEV/TEST

Do not provide testers with access to live production data. If production must be used, ensure no production data is present, or anonymise sensitive data to an acceptable standard. After testing, reset or roll back changes and revoke access.

Penetration testers must provide a formal report of findings and remediation recommendations · PEN-06 · MUST · DEV/TEST

Require a formal report including scope and methodology, evidence of findings with severity ratings, impacted assets, reproducible steps, and clear remediation recommendations.

Use long-term support framework versions · SEC-01.1.1 · MUST · DEV/TEST

Applications must target long-term support (LTS) versions of major frameworks (e.g. .NET or Angular).

Using LTS versions of frameworks improves an applications security, as LTS releases receive security patches and updates for a longer period than standard term support versions. For .NET applications, Microsoft provides LTS releases with 3 years of patching support.

Avoid the use of libraries with known vulnerabilities · SEC-01.1.2 · MUST · DEV/TEST

Applications must not utilise external libraries with known vulnerabilities (e.g. older versions of jQuery).

The use of external libraries should be carefully monitored, reviewed, and virus scanned in order to reduce the risk of malicious code injection (for example, cross-site scripting injection).

Use secure package versions · SEC-01.1.3 · SHOULD · DEV/TEST

Applications must maintain the security and reliability of all libraries and packages by upgrading to the latest secure version.

If a vulnerability is discovered, then it should be upgraded to the latest, patched version as soon as one becomes available.

Vulnerabilities can propagate through indirect dependencies or outdated packages - any packages which cannot be upgraded to secure versions must be recorded as a risk within the project tracker.

Use strict code compilation · SEC-01.1.4 · SHOULD · DEV

All code must be compiled to the highest warning level available to the compiler.

These warnings should be investigated to ascertain a severity, before they have the potential to become logic errors or security vulnerabilities, where critical vulnerabilities and warnings are actioned as soon as possible.

All application credentials must follow the Password and Authentication Policy · SEC-01.2.1 · MUST · DEV/TEST

To ensure password complexity, passwords must adhere to Audacia’s ‘Password and Authentication Policy’

Restricted
Login to display internal content.
.

Application credentials must not be re-used · SEC-01.2.2 · MUST · DEV/TEST

Unique, auto-generated passwords should be used to ensure the same password cannot be reused for accounts across multiple applications.

Un-encrypted credentials must not be stored in source control · SEC-01.2.3 · MUST · DEV/TEST

All credentials (not limited to API keys, default application logins or database config) must not be stored in source control.

If encrypted credentials are stored in source control, the necessary decryption key(s) must stored securely elsewhere.

Passwords must be salted/hashed before being stored · SEC-01.2.4 · MUST · DEV

Passwords must never be stored in plaintext. If an application manages authentication itself, any passwords must be salted and hashed before being stored.

Passwords or personal information must be obfuscated before being logged · SEC-01.2.5 · MUST · DEV

If any data containing personal information or a password is being logged, this should be obfuscated (replaced with ”****” or an empty string) before being logged. If information about who performed a certain action is to be logged, instead use database-generated user ID or similar identifier.

Emails must not send information to external sources · SEC-01.2.6 · MUST · DEV

Test emails must use one of the following approaches

Restricted
Login to display internal content.
, as defined in POL011 - Secure Development (see Policies)

:
  • Use a domain that is recognised as invalid such as @example.com or .test
  • Use your Audacia email with plus addressing so create alternative emails. For example audaciaemail+{stringvalue}@audacia.co.uk

Validate, encode or escape user input to prevent cross-site scripting (XSS) · SEC-01.3.1 · MUST · DEV/TEST

Any data entered by a user must be treated as untrusted.

All untrusted input must be validated, escaped or encoded appropriately when being rendered in a HTML page as this defends against cross-site scripting (XSS).

Server-side input validation must be performed,to ensure that malicious or malformed data is not processed. This is in addition to client-side validation, which can be by-passed.

Automated API tests should be written for input validation

Functional API tests can validate business logic rules around field length, required fields and expected data types faster than UI tests which need to login or navigate to the form or page under test.

Use request verification tokens to prevent cross-site request forgery (CSRF) · SEC-01.3.2 · MUST · DEV

Applications must use request verification tokens (anti-forgery tokens) to validate all requests.

Request verification tokens protect against data tampering i.e. if an attacker modifies form data, the token validation will fail, rejecting the request.

Utilise parameterized queries to prevent against SQL injection · SEC-01.3.3 · MUST · DEV

Always use parameterized queries if executing SQL directly from code (although an ORM or, failing that, a stored procedure with no unparameterized dynamic SQL should be preferred for any data access).

Applications should utilise virus scanning · SEC-01.3.4 · SHOULD · DEV

All systems that use file upload functionality, should have anti-virus configured and tested.

File upload architectures must be documented · SEC-01.3.5 · MUST · DEV

The anti-virus configuration and file upload architecture should be documented in the projects Architectural Decision Records.

Do not serialized objects from untrusted sources · SEC-01.3.6 · MUST · DEV

Applications must not accept serialized objects from untrusted sources to prevent against remote code execution attacks.

If this is not possible, one or more of the following strategies should be adopted to avoid insecure deserialization:

  • Implementing integrity checks such as digital signatures on any serialized objects to prevent hostile object creation or data tampering.
  • Enforcing strict type constraints during deserialization before object creation as the code typically expects a definable set of classes.
  • Log deserialization exceptions and failures, such as where the incoming type is not the expected type, or the deserialization throws exceptions.

Adopt rate limiting on all endpoints · SEC-01.4.1 · MUST · DEV

Applications must employ rate limiting on all endpoints to mitigate against brute force attacks, prevents server overload and DoS.

If the system utilises a Web Application Firewall (WAF) then rate limiting should be implemented in the WAF, the AspNetCoreRateLimit NuGet package provides a coded alternative.

Rate limiting decisions should be documented · SEC-01.4.2 · SHOULD · DEV

Weather all requests made to an API are rate limited or limits are applied to each API URL or HTTP verb and path, this should be documented in the projects Architectural Decision Records.

Access and authorisation must be restricted · SEC-01.5.1 · MUST · DEV

Features and system areas must be protected by roles, that give users the permissions to access only required areas/information.

If necessary authorization should be applied to specific data to prevent ID enumeration.

API endpoints must be authenticated by default · SEC-01.5.2 · MUST · DEV

Endpoints should be authenticated by default and anonymous access should have to be explicitly granted, for example to a ‘login’ endpoint.

APIs must enforce the same-origin policy · SEC-01.5.3 · MUST · DEV

APIs must enforce the same origin policy. If an API is hosted on a different domain/subdomain to a front-end application then this can be relaxed, but only to allow those specific origins as required.

Web applications must define a content security policy (CSP) · SEC-01.6.1 · MUST · DEV

A Content Security Policy header is used to define where assets such as scripts and stylesheets can be loaded from and whether inline execution of such as assets is allowed.

The Audacia.SecureHeadersMiddleware library contains a configurable Content Security Policy for .NET apps.

Web applications must include and exclude HTTP headers following security best practices · SEC-01.6.2 · MUST · DEV

Certain HTTP headers are recommended to be present in (or absent from) all responses for security reasons -see OWASP recommended HTTP headers.

The Audacia.SecureHeadersMiddleware library contains a configurable ASP.NET Core middleware to add the appropriate headers for .NET apps. It also has default configuration for APIs and MVC applications.

Restricted
Login to display internal content.
Example configurations for single page apps are documented as sensible defaults.

Web applications must include the relevant HTTP headers when there are SEO considerations · SEC-01.6.3 · MUST · DEV

Use the X-Robots-Tag meta HTTP tag, which tells web crawlers what they are allowed to do when they visit a site (and are more highly valued than a robots.txt file).

Restricted
Login to display internal content.
More information about SEO considerations are documented as sensible defaults.

The appropriate OWASP guidance must be followed · SEC-01.7.1 · MUST · DEV/TEST

Teams must follow current OWASP guidance relevant to the system and document the risks considered and the controls applied.

  • OWASP Top 10: Common web application risks (e.g. injection, broken access control, cryptographic failures, insecure design, vulnerable and outdated components, SSRF). See the OWASP Top 10.
  • OWASP Top 10 for LLM Applications: Risks specific to LLM systems (e.g. prompt injection, data poisoning, supply chain/model integrity, sensitive information disclosure). See the OWASP Top 10 for LLM Applications.
  • OWASP Top 10 for Business Logic Abuse: Abuse of workflows and rules (e.g. bypassing business processes, DoS, privilege escalation through logic flaws, quota/metering circumvention). See the OWASP Top 10 for Business Logic Abuse.

All externally accessible services must use a custom domain · CLOUD-02.1 · MUST · DEV

All deployed environments must expose services via custom domains. Default or auto-generated platform URLs (e.g. app-name.azurewebsites.net, xyz.cloudfront.net) must not be used for direct access in any environment.

This improves:

  • URL readability and user trust
  • Compatibility with enterprise SSO and OAuth
  • Portability across hosting providers

Secure all custom domains using managed SSL/TLS certificates · CLOUD-02.2 · MUST · DEV

Custom domains must be protected with automatically managed SSL/TLS certificates offered by the hosting or CDN provider. These certificates should:

  • Support automatic renewal
  • Be provisioned through DNS or HTTP challenge
  • Avoid manual upload workflows unless explicitly justified

This ensures continuous HTTPS support without administrative overhead or security risks.

EXCEPTION This does not apply where SSL/TLS certificates are managed by the client.

Follow a standardised domain naming convention · CLOUD-02.3 · MUST · DEV

All custom domains must follow a consistent structure to clearly identify:

  • The service name
  • The tenant/customer (if multi-tenant)
  • Optional: The deployed environment

Recommended pattern

..

Use centralised DNS management · CLOUD-02.4 · SHOULD · DEV

DNS zones should be managed via a centralised, version-controlled configuration using Infrastructure as Code (e.g. Terraform, Pulumi, Bicep).

Benefits include:

  • Reviewed, auditable changes
  • Avoidance of duplicated or conflicting records
  • Reproducibility across multiple environments

Automate domain provisioning and validation · CLOUD-02.5 · COULD · DEV

Where feasible, automate the provisioning of domains, validation of SSL certificates, and creation of DNS records as part of the deployment process.

This supports:

  • Faster, safer deployments
  • Reduced manual configuration errors
  • Stronger alignment with GitOps and infrastructure-as-code workflows

Cloud resources must have descriptive and meaningful names · CLOUD-01.1 · MUST · DEV

Use names that accurately describe the resource’s purpose, function, or role. Avoid ambiguous or generic names that may lead to confusion or misinterpretation. Ensure names convey relevant information without being overly long or complex.

Example 1:

  • Good: olympus-dev-vm
  • Bad: vm1

Example 2:

  • Good: olympus-dev-asp-functions
  • Bad: app-service-plan

Example 3:

  • Good: olympusdevst
  • Bad: storageaccount

Cloud resources must be named consistently · CLOUD-01.2 · MUST · DEV

Establish a consistent naming convention that is applied uniformly across all resources. Include all relevant teams and stakeholders in the development of the naming standard to ensure buy-in and alignment.

Good:

  • olympus-dev-asp-functions
  • olympus-qa-asp-functions
  • olympus-uat-asp-functions

Bad:

  • olympus-dev-service-plan-functions
  • olympus-qa-asp-functions
  • olympus-uat-app-service-plan-functions

Resource names must use lowercase letters and numbers · CLOUD-01.3 · MUST · DEV

Stick to lowercase letters and numbers to avoid potential case sensitivity issues and ensure consistency. Avoid using special characters, spaces, or uppercase letters in resource names.

Resource names must include an environment indicator · CLOUD-01.4 · MUST · DEV

Include environment indicators to differentiate resources across development, production, staging, or testing environments. Use abbreviations or standardized keywords such as “dev”, “prod”, “staging” or “qa”.

Generic: {project}-{environment}-*

Examples:

  • olympus-dev-*
  • olympus-qa-*
  • olympus-uat-*
  • olympus-prod-*

Resource names must include purpose or resource type indicators · CLOUD-01.5 · MUST · DEV

Use the purpose and the type of the resource to categorize the resources based on their purpose, department, or function. Prefixes provide a quick way to identify resource types and aid in navigation and management.

Generic: {project}-{environment}-{purpose*}-{resource}-*

purpose*: A prefix indicating the purpose of the resource in the context of the system.

Examples:

  • olympus-qa-portal-api
  • olympus-qa-public-api
  • olympus-qa-orders-func
  • olympus-qa-timers-func
  • olympus-qa-customers-sqldb
  • olympus-qa-sales-sqldb
  • olympus-qa-language-vnet
  • olympus-qa-build-vnet

Resource names must include a location indicator · CLOUD-01.6 · MUST · DEV

Include location indicators for resources deployed across multiple regions or geographical locations. Use standardized location abbreviations or keywords to maintain consistency.

Generic: {project}-{environment}-{resource}-{location}

  • olympus-qa-sqldb-uksouth
  • olympus-qa-sqldb-westeu
  • olympus-qa-cosmos-westus
  • olympus-qa-cosmos-usva

Resource names must be concise and clear · CLOUD-01.7 · MUST · DEV

Keep resource names concise while maintaining clarity and conveying relevant information. Avoid excessively long or cryptic names that may hinder readability and management.

Project-specific conventions must be documented · CLOUD-01.8 · MUST · DEV

If the project requires a different naming convention this should be documented and distributed among relevant teams and stakeholders. Provide clear guidelines, examples, and explanations to ensure proper understanding and adoption of the naming standard. Conduct training or workshops to educate teams on the importance of adhering to the naming conventions.

Access to infrastructure must be granted using the principle of least privilege · SEC-02.1 · MUST · DEV

Web applications should utilise a Web Application Firewall (WAF) to protect systems from common attacks · SEC-02.2 · SHOULD · DEV

This should always be presented as an option to clients, with benefits and costs clearly explained.

Cloud-hosted applications should be deployed within an isolated virtual network · SEC-02.3 · SHOULD · DEV

This approach introduces additional cost and complexity, so should be presented as an option to clients for them to understand the pros and cons.

Due diligence must be performed before introducing a new third-party dependency · SEC-04.1 · MUST · DEV/TEST

The due diligence must, at a minimum, cover the following questions (with an aim to answer “Yes” to every question):

  1. Is the dependency stable, popular, etc. (using metrics like GitHub stars and downloads)?
  2. Is the dependency actively maintained (using metrics like number of contributors and last update)?
  3. Is the latest version secure (i.e. no unpatched vulnerabilities)?
  4. Is the dependency solving a well-scoped, common problem (e.g. Excel integration or date parsing)?
  5. Does the cost to build outweigh the risk of importing?
  6. Is the dependency solving a non-trivial problem or one that likely to evolve in future (i.e. it would be harder to write our own code)?
  7. Is the license acceptable for our intended use (e.g. copyleft licenses are generally to be avoided)?

Performance & Scalability

Regular database reindexing must be performed · PERF-01.1 · MUST · DEV

Where possible, regular database reindexing should be automated, e.g. a script running on a schedule.

Restricted
Login to display internal content.
There are some useful resources in the Audacia wiki.

Data archiving must be considered · PERF-01.2 · MUST · DEV

This may not always be possible, but must always be considered.

Database queries must be optimized · PERF-01.3 · MUST · DEV

Basic optimizations must be performed, for example:

  • Projecting entities to a DTO if an untracked subset of data is needed
  • Applying in-database filtering to restrict data returned to what is required
  • Using the most efficient aggregation technique, e.g. if using Entity Framework, prefer Any() over Count() > 0
  • If using Entity Framework, eliminate unnecessary Include() statements and don’t track entities that will not be updated

Web applications must be stateless by design in order to be horizontally scalable · PERF-02.1 · MUST · DEV

Systems should utilise caching in order to provide more scalable data access · PERF-02.2 · SHOULD · DEV

Caching increases cost and complexity, therefore this must be a consideration rather than a mandate, and the costs and benefits should be communicated to the client where appropriate.

A distributed caching solution should generally be preferred in order to best enable horizontal scalability.

Asynchronous operations should be preferred where possible · PERF-02.3 · SHOULD · DEV

Where an operation does not need to be performed synchronously, technologies like message queues and events should be used in order to process actions asynchronously.

Common examples include:

  • Sending an email
  • Writing to an audit log
  • Notifying an external system of an event