Rules-as-Code: Encoding Rules in a Government Context — Part 1

I am a developer fellow for Code for Canada, a non-profit organization that works with government agencies to deliver better digital services to the public. I am part of a team of three that is working with Employment and Social Development Canada (ESDC) for a 9-month fellowship. We have been working on a prototype for a tool called a Policy Difference Engine (PDE). The purpose of this tool is to measure how a change to a rule may impact a population. The key component of a PDE is a reliable encoding of the “rule”, which here refers mainly to a piece of government policy/regulation/legislation. In this series, we’ll introduce the concept of Rules-as-Code, discuss the value behind it, and show you what it looks like in practice using an example from our fellowship.

This is the first post of the series, where we present a working definition of Rules-as-Code. The second and third posts will follow.

Introduction

We will begin with a brief example to illustrate a Policy Difference Engine (PDE). Suppose we have a government regulation that determines how much money a parent/caregiver is eligible for under a childcare benefit. We want to study the impact of changing this rule. If we take 100 simulated individual applicants, and run them against a coded version of the existing rule, then we can see how much each person is entitled to under the current system. Next, we take an updated version of this rule representing the proposed changes, and we run the same 100 individuals against this updated rule. This tells us how much each person is entitled to under the new rules. This process gives us a piece of the picture of how this rule change might impact the population. Conceptually it is a simple tool — we need a set of data points representing individuals, and we need the set of rules and the proposed change. We run each person against the rule and the change, and we aggregate and visualize the results.

The PDE relies on having a reliable encoding of the rules. The coded regulation/legislation must be captured accurately in the system, otherwise the results are unreliable. Furthermore, this PDE will not be the only application that could benefit from a reliable encoding of the rules — other types of applications that the public would interact with on a daily basis could make use of this as well. This may sound like the common software development practice of ensuring you have the right business requirements and reusing components — and it is! But there are some important aspects of working in the government space that can add some extra complexity. This complexity motivates an approach called “Rules-as-Code”.

Defining RaC

What is Rules-as-Code? Your first impression might be that it’s simply a coded version of some rules. Technically true, but far from the whole story. First we will start with the idea of “rules”. While the approaches listed here may apply beyond a government context, we will narrow our definition of rules to refer to some government document written in a human language. This could be a large piece of legislation, a 3-page regulation, a 12-line policy, and anything in between. It is still a fairly broad category, but the point is that we are operating in a government context. These rules will posit important definitions (for example, concretely defining a benefit), answer important questions (am I eligible for a certain benefit?), and lay out calculations (How much am I entitled to?).

To make use of these rules in digital systems, they need to be coded. These “coded rules” are everywhere — any application that makes use of some government rule will have the rule coded somewhere in the system. So the question becomes: what extra characteristics should these coded rules have when working in a government context? Here are some that we’ve identified:

The code for these rules should be visible to all — no black boxes. Giving people access to the code that makes important decisions about their lives can help build trust. It also allows the systems to be open to feedback, since anyone can look at the code and identify any issues with the system, whether it be technical bugs or more systemic issues and gaps in policies.

It is important to keep the rules precise in their scope. It should be encoding the questions and definitions laid out by the written rule, and nothing more. So you might have one system that encodes the entire Old Age Security Act. This system would answer questions such as “Am I eligible for OAS”, “How much am I eligible for”, “What is the maximum amount that someone can receive?”, etc. Then you would have another system that encodes the entire Employment Insurance Act, which is much larger in scope (in this case you may break this into a few inter-connected systems). The goal is to make these systems a coded version of the rule in question, so answering questions beyond the scope of the written document may cause confusion. This has interesting design and architectural considerations, but we will not discuss them here.

Another goal of these rules systems is that many different applications can be built on top of them. If two separate applications, say a chatbot and an accounting tool — need some info about the Canada Labour Code, then we don’t want to be building this underlying system twice. Build it once and allow these user-facing applications to make use of it (for example, as an API or software library). This is a standard goal for most software development contexts — “Don’t repeat yourself” — but it is worth emphasizing here as well. These are the rules that define important aspects of our lives, so we want a consistent experience when navigating the different tools that rely on them. The written rules themselves are heavy in legalese and ambiguities abound, which leaves them open to different interpretations. If we have two separate applications that have their own interpretation of an important government rule, then the people that the rule affects will have a conflicting experience. Ideally we could have a single source of truth that is open, robust, and reusable.

If we want to have a single source of truth for these government rules, then we need to make sure that these rules are accurate and reliable. The best way to guarantee reliability with these documents that are mired in ambiguous legalese is to bring policy experts into the process. Subjecting a written rule to a technical lens will bring out any inherent ambiguities. Machines are not able to make guesses (not counting randomization), so it will require that the rules have a clear and logical flow. Experts are needed to help identify and analyze these ambiguities, provide insight to how they are resolved in practice, and help ensure that nothing is lost in the process of translating the written rule into concrete technical requirements.

Suppose we start coding a robust and reusable rules system collaboratively with policy experts. How do we know when we are finished? This is largely where the policy experts will come in. We can join this expertise with another best-practice from software development: test-driven development. As the rules are developed (or even before), the collaborative team should be coming up with concrete cases to test the rules against. The nature of these tests will of course depend on the rule you are working with, but suppose we are building an eligibility rule that determines eligibility based on several factors. We can write tests for all possible combinations of factors with their expected output (with validation from the policy experts) and ensure these are passing as the code is developed.

So while there may be other characteristics that are important when working in a government context, the ones listed above are an important starting point. We can now define systems that meet these criteria as “Rules-as-Code” systems.

In the next part of the series, we will discuss the value of RaC by walking through a concrete scenario.

Developer working in Civic Tech