Software Engineering for AI
Modular Design and Software Architecture · 15 min
The IEEE Software Engineering Body of Knowledge (SWEBOK) treats software design as its own knowledge area, distinct from requirements and construction, precisely because how a system's pieces are divided and connected determines whether it can be understood, changed, and reused later without ever touching correctness in isolation. A well-modularized design separates a system into components, each responsible for one clear piece of functionality, communicating through defined interfaces rather than by reaching into one another's internals. Consider a concrete worked example: an AI training script that loads data, cleans it, trains a model, and evaluates it, all inline in one function, versus the same logic split into four modules — `load_data()`, `clean_data()`, `train_model()`, and `evaluate_model()` — each independently testable and each replaceable (swap in a different data source, or a different model) without rewriting the rest.
Two properties from classical software design vocabulary make this concrete: cohesion, how closely related the responsibilities within a single module are, and coupling, how much one module depends on another's internal details rather than its public interface. High cohesion within `clean_data()` (it does one thing — cleaning) and low coupling between it and `train_model()` (the latter only needs the cleaned data it receives, not any knowledge of how cleaning happened) together produce a design where a bug in data cleaning cannot silently corrupt the training logic, and where either module can be tested with the small, deterministic unit tests introduced in the programming module, using a handful of known inputs and expected outputs.
This matters more, not less, for AI systems than for typical software, because AI code churns constantly — a new dataset, a new model architecture, a new preprocessing step — and code that started as a one-off research script is routinely pressed into production service. SWEBOK's framing of design as a distinct discipline with its own principles and the ACM/IEEE CS2013 curricular guidelines' emphasis on software design fundamentals as a core competency for computer science graduates both reflect the same underlying reality: a system built as loosely coupled, independently testable modules survives that churn, while an 800-line monolithic script has to be understood in its entirety before any single piece can be changed safely.
APIs and Documentation · 15 min
An application programming interface (API) is the boundary a module exposes to the rest of a system — the functions, classes, or network endpoints other code is allowed to call, deliberately hiding everything else. Google's API design guide, developed for the company's own networked services since 2014 and now public, centers its recommendations on resource-oriented design: organizing an API around named resources (such as `users` or `models`) and applying a small, consistent set of standard methods to them — Get, List, Create, Update, and Delete — rather than inventing a differently shaped, one-off endpoint for every operation. Worked example: a model-serving API exposing `GET /models/{id}` to retrieve one model's metadata and `POST /models` to register a new one is immediately predictable to any developer familiar with the pattern, whereas an endpoint named `/doTheModelThing` is not, no matter how well it works.
Documentation at the code level follows a parallel discipline. PEP 257 defines a docstring as a string literal that is the first statement in a module, function, class, or method, and specifies that a one-line docstring should fit on a single line, keep its opening and closing triple quotes on that same line, and describe the function's effect as an imperative command — "Return the cleaned dataset" rather than "Returns the cleaned dataset" — while a multi-line docstring adds a blank line after the summary before a longer description of arguments, return values, and side effects, with the closing quotes on their own line. Applied to the `clean_data()` module from the previous lesson, a compliant docstring might read `"""Remove readings below zero from a list of sensor values."""` as its summary line — short, imperative, and immediately answering "what does calling this do," which is exactly what a teammate needs before reading the implementation.
Together, a resource-oriented API and PEP 257-style docstrings solve the same underlying problem from two different angles: they let another developer — or a future version of the same developer — use a module correctly without first reading its entire implementation. This is not a cosmetic nicety; SWEBOK's inclusion of software construction and quality practices alongside design reflects that undocumented, ad hoc interfaces are a leading cause of the maintenance cost that eventually makes a codebase too risky to change, which is precisely the failure mode this module's essential question describes.
Version Control and Maintainable AI Systems · 15 min
Version control is, in its simplest definition, a system that records changes to a set of files over time so that specific past versions can be recalled, compared, and restored later; the Git documentation traces its evolution from local systems that tracked patch sets on a single machine, through centralized systems like Subversion where one server holds the only complete history (a single point of failure if that server is lost), to distributed version control systems (DVCSs) like Git, where every clone of a repository is a full mirror including its entire history. This distributed design means that if the central hosting server disappears, any collaborator's local clone can restore the project's complete history — a guarantee no centralized system before it offered.
For AI codebases specifically, version control does more than protect against lost files. Because AI experiments routinely branch — one teammate tries a new preprocessing step, another experiments with a different model architecture — the ability to isolate each line of work in its own branch, test it independently, and merge only what proves out is what keeps a shared codebase from becoming a tangle of commented-out alternatives inside a single file. A commit history with clear, specific messages ("switch data cleaning to drop nulls instead of zero-filling them" rather than a bare "fix") turns the repository itself into a record of why the code looks the way it does — information that plain code, however well-documented at the function level, cannot carry on its own.
Modularity, clear APIs, PEP 257-compliant documentation, and disciplined version control are not four independent best practices to be adopted piecemeal; they compound. A well-modularized `clean_data()` function with a clear docstring is easy to unit-test in isolation (as covered in the programming module); a clean commit history makes it possible to find exactly when and why its behavior changed if a downstream test starts failing; and a resource-oriented API around the whole pipeline means a new team member can start calling it correctly within minutes rather than needing a guided tour through 800 lines of undifferentiated script. SWEBOK's treatment of these as interlocking knowledge areas rather than isolated tips is the professional-practice basis for treating AI research code with the same engineering rigor as any other production software from the start, rather than retrofitting it after the prototype has already become load-bearing.
Layers of Maintainability
Maintainable AI software rests on modular design, with a clear API and documentation, automated tests, and version-control history each building on the layer below.
- High cohesion inside a module and low coupling between modules let a bug in one piece stay contained instead of silently corrupting another.
- A resource-oriented API with standard methods (Get, List, Create, Update, Delete) is predictable to a new developer without reading the implementation.
- A distributed version control system means every clone is a full backup of the project's history, not just the central server.
Recall Practice
Glossary
- Modularity
- Dividing a system into components, each with one clear responsibility, that communicate through defined interfaces.
- Coupling
- The degree to which one module depends on another module's internal details rather than its public interface.
- API
- The set of functions, classes, or endpoints a module or service exposes for other code to call.
- Docstring
- A string literal, per PEP 257, that documents a module, function, class, or method as its first statement.
- Version control
- A system that records changes to files over time so specific past versions can be recalled and restored.
- Distributed version control system (DVCS)
- A version control system, like Git, in which every clone holds a full copy of the project's entire history.
Review a Module's API and Docstrings
Given a supplied short Python module excerpt (a few function signatures, one non-compliant docstring, and a printed commit-log excerpt with vague messages), learners identify on paper where modularity, PEP 257 docstring conventions, and commit-message clarity fall short of the standards covered in the lessons, and write out corrected versions. This is a virtual, reading-and-annotation exercise; no live repository or code is actually created or executed.
Ready to test yourself?
5 questions on this module.