Skip to main content

Software Guide Rails

The guide rails below are used by CRUK's Software Engineering teams to ensure alignment and aid decision making.

Summary

Guide RailDescription
LanguageTypeScript
Version ControlGitHub - Product Monorepos
Cloud PlatformAWS
AWS ServicesServerless
Lambda >> Fargate >> EC2
DynamoDB >> Aurora Serverless >> RDS
EnvironmentsPR - ephemeral for testing
Integration (int) - static for clients
Production (prod)
AWS Accountsint - PR & Integration Environments
prod - Production Environment
Frontend FrameworksNext.JS
Frontend Form LibrariesReact Hook Form | Zod
Frontend Styling LibrariesStyled Components | CRUK React Component Library
Frontend Testing Librariesjest | vitest | React Testing Library | Cypress | Playwright

Introduction

The Software Engineering team’s purpose is the design, development, operation of custom-developed software for the charity. This includes:

  • External-facing websites such as the main Cancer Research UK website
  • Web applications such as the Payments Web Service, Online Fundraising and Event Management
  • Applications aimed at researchers, clinicians and internal users like the ECMC Trial Finder
  • Data integration solutions like Person Hub or the U4BW interfaces

This document defines high-level principles that all software engineers at Cancer Research UK should adhere to. This promotes strategic alignment and consistency between teams whilst empowering engineers to make lower-level decisions as part of their day-to-day work. The main benefits of adhering to these principles are that:

  • engineers are able to move between teams more easily thanks to familiar frameworks and patterns and
  • technical decision making is quicker as higher-level decisions have already been made

Assurance approach

The assurance approach to ensure these guide rails are followed is to:

  • Involve the software engineering team in early stages of initiatives where buy vs build decisions are made
  • Ensure all code changes go through a code review, either by a peer or by a more senior Engineer; Lead Software Engineers are accountable for the guide rails being followed within their teams

Exception process

If an engineer needs to deviate from these guide rails, they are expected to produce a decision document supporting this, to be approved by the Senior Manager of Software Engineering or the Head of Engineering. This decision document should be kept with the rest of the product documentation (typically in the code repository) for future reference.


Engineering approach

When & how to engage with the Software Engineering team

The Software Engineering team’s purpose is to design, develop and operate custom-built applications for the charity where suitable off-the-shelf commercial alternatives do not exist on the market or where there is a strategic advantage to developing a custom solution.

Rationale

The Software Engineering team’s purpose is to design, develop and operate custom-built applications for the charity such as:

  • Content Management System (CMS) websites such as the main Cancer Research UK website
  • External-facing fundraising web applications such as the Payments Web Service, Online Fundraising and Event Management
  • Web applications aimed at researchers, clinicians and internal users like the ECMC Trial Finder
  • Data integration solutions like Person Hub or the U4BW interfaces that allow custom-built or off-the-shelf applications to communicate with each other

The Engineering strategy is not to develop custom applications where suitable off-the-shelf commercial alternatives exist on the market. Good examples are U4BW (Finance system), Workday (HR system), FirstClass (legacy management system).

Separate Engineering teams are in place for CRM/Marketing engineering and Business Intelligence.

The Software Engineering team should be engaged during the discovery phase of new products/services/initiatives to assess and estimate options, design custom solutions and mobilise the delivery team using either internal or external software engineers.

Further reading


Preferred language

The preferred language for all aspects of software engineering is TypeScript. This includes front-end, back-end, infrastructure-as-code, QA automation.

Rationale

Using a single language for all aspects of software engineering encourages collaboration between engineers and cross-skilling into areas that engineers are less familiar with. This makes the engineering team more flexible and efficient. Typescript is strongly typed and should indicate issues at compile time before they appear at run time

Further reading


Preferred cloud platform

The preferred cloud platform for software engineering is AWS. Specialist service providers/vendors will only be considered if they have a significantly superior offering to the equivalent AWS service. The preferred approach is to adopt its native services and libraries (as opposed to cloud-agnostic tools or abstraction frameworks).

Rationale

Focussing our skills on one cloud provider makes the most of the software engineers we have available. Using native services and libraries (e.g. AWS Lambda, AWS SDK, AWS CDK) rather than abstraction frameworks (e.g. Serverless Framework, Terraform) reduces complexity and allows us to recruit more easily.

Further reading


Preferred AWS services

We prefer using serverless services (e.g. prefer Lambda over Fargate, Fargate over EC2, Aurora Serverless over RDS).

Rationale

Serverless services require less coding and less maintenance to meet the same non-functional requirements

Further reading


Preferred approach to version control repositories (monorepo)

A monorepo is a software development strategy where the source code for multiple projects and packages are stored in a single git repository. At CRUK monorepos are applied at the product level. The monorepo approach means that the frontend, backend, infrastructure and shared packages are stored within the same repository for a given product.

Rationale

Engineers can change multiple components in a single PR. Refactors and adjustments to one package can be applied across all packages in a single commit/PR.

All product components and packages are stored in a single place making source code easier to find.

Works well alongside a microservice architecture where each component is its own package within a monorepo.

Testing of dependencies can be done in the same PR.

Keeping the monorepo at the product level allows git history against a single product and keeps the repo a manageable size. It also allows access restriction at the product level.

Further reading


AWS accounts and test environments

Each product should have the following AWS accounts with the minimum following environments:

AWS Account: Integration (int)

  • PR environments
  • Integration environment (optional)

AWS Account: Production (prod)

Rationale

Fewer static environments (Reduces environment rot, lowers cost, removes bottlenecks) Quicker releases: having fewer environments from the PR to Production results in quicker releases as every change approved is merged and pushed to the Production environment. Aligned AWS accounts and environments across product teams. Clarifies what environments to connect across products.

Further reading


Front-End Engineering

Preferred React frameworks

Next.JS

Rationale

React has been chosen due to a combination of its ability to handle large scale complex frontends and it being mature, well supported and has a large community of users. React is backed by Facebook. The concepts such as one-way data flow means apps are usually predicable and easy to test and with its virtual DOM diff algorithms it can handle large complex changing front ends efficiently.

Next.JS is recommended for:

  1. Stand alone static pages with JS which are preferred over single page applications (npm run build && npm run export)
  2. Apps that require Server Side Rendering (SSR)
  3. Apps that need to be fast for the end user using Static Site Generation on the server (SSG)
  4. Apps that need to work with Social Sharing (as you need the head meta data to be there before it gets to the browser)
  5. Apps that where Search Engine Optimisation (SEO) is important

Further reading


Preferred JS/TS Form Libraries

React Hook Form (for forms), Zod (for validation)

Rationale

React Hook Form (RHF) is a flexible, mature, well-documented and actively maintained open source library, and it's an alternative to form libraries like Formik. What makes it stand out is its default performance story. The technique it leverages to achieve this performance is using uncontrolled forms (as opposed to controlled forms that you'd either implement with Formik or naively implement by hand in React) and this vastly reduces the number of re-renders. It uses a plug-in mechanism to integrate with validation libraries like Zod and Yup, and those specific integrations are supported by the official RHF project.

Further reading


Preferred Styling Libraries

Styled Components, CRUK React Component Library

Rationale

Styled Components is a widely adopted, well supported and documented CSS in JS library. CSS in JS is a preferred method of styling as it is provides many benefits such as reusable components and automatic name spacing avoid the common issue with CSS selector collisions and issues with scalability. It also handles theming well, which is why the React component library has been built with it.

Further reading


Preferred Testing Libraries

Jest, Vitest, Cypress, React Testing Library, Playwright

Rationale

Jest is the most common test runner for modern JS development. It is used for rudimentary unit tests. Vitest is a modern contender that is Jest-compatible that should be a drop-in replacement for Jest. It includes a lot sane defaults and interesting concurrency modes for test execution.

Cypress is our preferred testing tool it is well known by our QA team. It can be used in interactive or headless mode where a real browser is used to test real browser behaviour. It has a rock solid and comprehensive API and multiple add-on modules written by its large community. The only caveat is if your tests need to jump multiple domains; in this scenario we would recommend using Playwright.

React Testing Library does a good job of being a fast framework that doesn’t require a browser. It uses real DOM elements to test with instead of shallow rendering like enzyme, so it is much more closely aligned with real user experience.

Further reading