Damfinos
ArticlesCategories
Programming

Code as a Dual Language: From Machine Instructions to Domain Models

Published 2026-05-13 07:01:18 · Programming

Overview

As artificial intelligence agents increasingly generate and maintain code, a fundamental question arises: will traditional source code disappear? To answer that, we must first understand what code is. Code serves two intertwined purposes: it provides precise instructions that a machine can execute, and it captures a conceptual model of the problem domain. This tutorial explores these dual roles, showing you how to design code that is both machine-readable and human-meaningful. You'll learn to build a vocabulary that bridges the gap between real-world concepts and computational logic, and see how this perspective shapes the way we work with large language models (LLMs) today.

Code as a Dual Language: From Machine Instructions to Domain Models
Source: martinfowler.com

By the end of this guide, you'll be able to structure your code so that it communicates intent, adapts to change, and remains intelligible to both humans and machines—a skill that grows more critical as AI becomes a coding partner.

Prerequisites

To follow this tutorial, you should have:

  • Basic familiarity with at least one programming language (examples use Python 3.x)
  • Understanding of fundamental programming concepts (variables, functions, conditionals)
  • Access to a code editor and a Python environment (optional but recommended)

Step‑by‑Step Instructions

1. Decompose the Problem into a Conceptual Model

Before writing a single line of code, define the core concepts of your domain. For example, consider an online shopping cart. The key concepts are Product, Cart, Customer, and Order. Each has attributes and behaviors: a product has a name and price; a cart holds items; a customer has a shipping address; an order finalizes a purchase.

Task: List the nouns and verbs in your problem statement. Nouns become classes or data structures; verbs become methods or functions.

# Conceptual model (pseudocode)
Product: name, price
Cart: items (list of Product), add_item(), remove_item(), total_price()
Customer: name, address
Order: cart, customer, confirm()

This conceptual model is the “thinking tool” that your code will represent. It lets you reason about the system without getting lost in machine details.

2. Choose a Vocabulary for Machine Instructions

Now translate the model into actual code. The language you choose provides a set of instructions (syntax, operators, control structures) that the machine understands. Your job is to map each domain concept to these instructions while preserving the conceptual integrity.

For instance, in Python:

class Product:
def __init__(self, name, price):
self.name = name
self.price = price

class Cart:
def __init__(self):
self.items = []

def add_item(self, product):
self.items.append(product)

def total_price(self):
return sum(p.price for p in self.items)

Notice how the class names and method names directly echo the domain language. This is the essence of building a vocabulary to talk to the machine—you teach the machine the meaning of “add_item” and “total_price”.

3. Embed the Model into Execution Flow

Code is not just a static description; it must execute. Combine your domain objects with control flow to achieve real behavior. For example, a checkout process:

def checkout(customer, cart):
order = Order(customer, cart)
order.confirm()
return order

Here, checkout is a high-level step that uses the conceptual model (Customer, Cart, Order) to drive machine actions. The machine sees function calls and object mutations; the human sees “creating an order” and “confirming it.” This duality reduces cognitive load.

4. Refine the Vocabulary with LLMs as a Partner

Large language models can now generate code from natural language prompts. But to get useful output, you must supply them with a clear conceptual vocabulary. When you ask an LLM to “add a discount to the cart,” you need the model (and the LLM) to share an understanding of what “discount” means—a percentage off total price, a fixed amount, or a promo code? By explicitly defining such terms in your code comments or documentation, you bridge the gap between human intention and machine execution.

Example prompt: “Write a method apply_discount(self, discount_code) for the Cart class. Use the concept of Discount defined in the docstring.”

Feeding the LLM your domain vocabulary helps it generate code that fits your model, rather than producing generic, hard‑to‑maintain logic.

Common Mistakes

❌ Mixing Abstraction Levels

A frequent error is mixing low‑level machine details with high‑level domain logic in the same function. For instance, handling file I/O inside a method that should only update a list, or optimising database queries in a method that merely adds an item to a cart. This obfuscates the conceptual model and makes the code rigid.

Fix: Keep domain methods pure—they operate on domain objects and delegate infrastructure concerns (e.g., saving to disk, sending HTTP requests) to separate modules.

❌ Poor Naming

Names like do_stuff() or data destroy the vocabulary. The machine runs them, but a human (or an LLM) cannot infer what they represent. Over time, the code loses its role as a thinking tool.

Fix: Use descriptive names that match the domain: apply_loyalty_discount() instead of discount2(). Even if the name is longer, clarity pays off.

❌ Ignoring the Future of Code

Some developers assume that with LLMs writing code, source code will become obsolete. This ignores the fact that LLMs still need a consistent domain model to produce coherent changes. If the conceptual model is missing, the generated code will be disjointed and buggy.

Fix: Continue to invest in clean domain models and clear vocabularies—they are the substrate on which LLMs operate.

Summary

Code is not merely a set of machine instructions; it is a dual artifact that simultaneously speaks to the computer and to human reasoners. By starting with a conceptual model, choosing a vocabulary that maps domain terms to programming constructs, and deliberately structuring execution flow around that model, you create code that is both executable and intelligible. As LLMs become more involved in coding, this duality becomes even more critical: the machine reads the instructions, and the model guides the LLM’s generation. Future‑proof your code by keeping the conceptual model explicit, and you will be ready to collaborate with AI—not replaced by it.