# Code Quality in Data Science

Laszlo Sragner, Hypergolic | MLOps Meetup | Episode 105 | 23:18
Hosted by Demetrios Brinkmann

Source: https://www.youtube.com/watch?v=vlG2PZeJ5ig
Channel: MLOps Community, now AAIF Live (https://www.youtube.com/@AAIFLive-x1r). Summarised by MLOps Talks.
Page: https://mlopstalks.com/talks/code-quality-in-data-science
Published: 2022-07-14
Tags: testing

## TL;DR
- Machine learning products accumulate technical debt because their requirements and business context keep changing during development.
- Refactoring requires fast tests and experimental operational symmetry, which means running the same code on a laptop, in testing, during evaluation, and in production.
- Clean architecture with dependency injection, adapters, factories, and strategies keeps business logic stable while data sources, infrastructure, and models change.

## Summary
Laszlo Sragner explains why machine learning products need software engineering practices. These products often have long lifespans, solve fuzzy business problems, and change while they are being built. Teams also create friction when data scientists hand exploratory work to machine learning engineers, since feedback then takes longer to reach the original code. Sragner defines technical debt as taking a planned step toward knowledge with a way to correct it later. Refactoring pays that debt down, but only when code can be tested quickly and run consistently across environments. His clean architecture puts domain models and business logic at the center, with data sources, infrastructure, databases, and external services around them. Dependency injection and inversion of control reduce coupling. Adapter, factory, and strategy patterns isolate external services, data construction, and model choices. The result is code that can be explored in notebooks, tested with small data, and moved into production without rewriting the central logic.

## Key ideas
### Machine learning products accumulate debt because their problems keep changing
[02:02](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=122s)
Sragner distinguishes an ML product from infrastructure and data analysis. An ML product is an autonomous business process with a long lifespan and an end-to-end input-output relationship. Its requirements are hard to specify because real-world problems contain edge cases and ad hoc rules. The business problem also changes while the team is solving it, so the product is always catching up. The long lifespan makes removing technical debt worthwhile. He also separates debt from unfinished work: missing documentation, infrastructure, features, and broken models are not automatically technical debt.

### Technical debt is planned learning, and refactoring is how teams repay it
[10:33](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=633s)
Sragner uses Ward Cunningham's original idea of technical debt: a team takes a step in an unknown direction while keeping a plan for returning to the desired design. He rejects the credit-card comparison because debt should produce a useful return. Paying it back requires code that is clean enough to refactor. Refactoring means changing the code without changing its behavior. Once a problem has been solved, the team can reshape the implementation so that future changes are easier. This requires fast testing and a consistent way to run the code.

### Experimental operational symmetry keeps one implementation across environments
[13:21](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=801s)
Experimental operational symmetry, or EOS, means running the same code on a developer's laptop, in testing, during model evaluation, during training, and in production. Sragner presents this consistency as a condition for safe refactoring. If a class depends directly on a database or a GPU that is unavailable on a developer's machine, the team cannot run a test locally. Without a reliable test, it cannot confidently change the implementation. EOS makes it possible to replace the surrounding environment while keeping the central business code unchanged.

### Decoupling separates business logic from infrastructure
[14:21](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=861s)
Decoupling reduces dependencies between system components. It lets a team split a problem into smaller parts and hide database, computing, and external-service details from the ML product. Sragner describes this as breaking the situation where changing one thing changes everything. Inversion of control lets infrastructure call the main entry point of the product instead of the product directly controlling every dependency. Dependency injection then connects an abstract Python class to external interfaces. Tests can inject files, a file system, or mocks, while production can inject real services.

### Clean architecture puts the domain model at the center
[17:55](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=1075s)
The central part of Sragner's architecture contains the domain model, business logic, and the models that automate the business problem. Data sets, feature engineering, databases, computing infrastructure, and external services sit around that center. Most attention and refactoring happen in the central code. The outer components can be replaced for testing, evaluation, or production without changing the business logic. This arrangement also lets teams distribute responsibility, since infrastructure components can be handled by other teams without forcing changes in the product's core.

### Three patterns isolate the changes that happen often in ML systems
[21:28](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=1288s)
Sragner recommends three patterns for this structure. An adapter wraps an external service, such as a SQL database, behind an interface so local tests can use a file-based implementation. A factory creates domain-specific objects from a data source, allowing the rest of the product to work with terms such as a customer instead of raw data frames. A strategy isolates algorithmic choices. The main code can call a model through a common interface without knowing whether the implementation is a deep model, a random forest, or another algorithm.

### A small test pipeline and explicit interfaces support fast iteration
[18:50](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=1130s)
His suggested workflow starts by defining data classes and the business logic. Data sources are wrapped with factories, then a test environment runs the same pipeline on one percent of the data. Sragner says this is enough to catch typos and stylistic errors. The team defines interfaces as the actions it wants to perform on the data and groups them into service classes. External production services are wrapped with adapters. The same code can then move from testing to production, while new experiments use strategy implementations instead of edits to production logic.

### Notebook exploration can use the same product code
[20:35](https://www.youtube.com/watch?v=vlG2PZeJ5ig&t=1235s)
Sragner does not ask data scientists to abandon notebooks. Factories can be instantiated in a notebook to load domain data, which can then be converted into data frames for analysis and plotting. Because the main program is a class, it can also be instantiated in the notebook with the appropriate plugins. This lets the data scientist work with code that resembles the production setup and try new strategies locally. The notebook remains an analysis environment while the product logic stays in the same structure used for testing and deployment.

## Notable quotes
- Laszlo Sragner: "Machine learning is the continuation of software engineering by other means." (00:31)
- Laszlo Sragner: "Technical debt is an attempt to gain knowledge with a plan to correct it later." (10:33)
- Laszlo Sragner: "Refactoring means changing the code without changing its behavior." (12:18)
- Laszlo Sragner: "You treat the algorithm as an external resource to your code." (17:05)
- Laszlo Sragner: "ML is inherently unspecifiable, tech debt is inevitable." (22:23)

## Tools & references mentioned
- Carl von Clausewitz
- Ward Cunningham
- Clean Architecture
- experimental operational symmetry
- EOS
- inversion of control
- dependency injection
- adapter pattern
- factory pattern
- strategy pattern
- Python
- Laszlo's blog

## Who should watch
- You are building an ML product that will run for a long time and expect its requirements to change.
- Your data science and machine learning engineering work is split across teams, and handoffs are slowing down feedback.
- You want a practical structure for testing notebook work and model experiments before moving them into production.

## Editor's note

Laszlo Sragner argues that refactoring is only safe when the same code can run on a laptop, in testing, during evaluation, and in production. ZenML lets teams write workflows as Python steps and run the same pipeline code on a laptop, Kubernetes, Airflow, Kubeflow, or cloud services by changing the configured stack. Each run records its steps, inputs, outputs, and code version.

Written by the MLOps Talks editors (the ZenML team), not by the speaker.

## Related talks

- [Impact of SWE in ML Projects](https://mlopstalks.com/talks/impact-of-swe-in-ml-projects) (Laszlo Sragner & Tim Blazina, 55:42)
- [Eliminating Garbage In/Garbage Out for Analytics and ML](https://mlopstalks.com/talks/eliminating-garbage-in-garbage-out-for-analytics-and-ml) (Roy Hasson & Santona Tuli, Upsolver, 50:38)
- [Build a Culture of ML Testing and Model Quality](https://mlopstalks.com/talks/build-a-culture-of-ml-testing-and-model-quality) (Mohamed Elgendy, Kolena, 51:14)
- [Clean Code for Data Scientists](https://mlopstalks.com/talks/clean-code-for-data-scientists) (Matt Sharp, Shopify, 46:13)
- [Data Engineering for ML](https://mlopstalks.com/talks/data-engineering-for-ml) (Chad Sanderson, Convoy, 57:54)
