---
title: A Python Framework Where Doing the Right Thing Is the Default
description: My MSc thesis. 33 catalogued ML deployment habits, a decorator-shaped Python API, and a survey of working engineers on which actually got adopted.
date: 2026-05-09
period: '2022'
thumbnail:
  src: ./_assets/great-ai.png
  alt: Example Python code using the GreatAI API.
links:
  - label: PyPI
    url: https://pypi.org/project/great-ai/
  - label: Project site
    url: https://great-ai.scoutinscience.com
  - label: MSc thesis
    url: /media/downloads/great-ai-andras-schmelczer.pdf
    download: true
article:
  featuredOrder: 1
  tags: ['ai', 'systems', 'tools']
  role: Researcher and framework author
  stack: ['Python', 'decorators', 'FastAPI', 'survey design']
  scale: 33 deployment habits surveyed, 6 proposed additions, framework evaluated by working data scientists and engineers
  outcome: A pip-installable framework, an MSc thesis, and one strong opinion about API surface area
  audience: recruiter-relevant
  media:
    - type: image
      src: ./_assets/great-ai.png
      alt: Example Python code using GreatAI decorators and prediction helpers.
      caption: A working GreatAI service is about ten lines on top of a plain prediction function.
project:
  title: GreatAI
  description: One decorator on a Python function turned it into a deployed ML service. MSc thesis with a survey to back the API choices.
  selected: true
  technologies: ['Python', 'ML deployment', 'API design']
---

By the end of 2021 I had stopped believing that the people skipping ML deployment best practices were the problem. They knew the list. They agreed with the list. They had a deadline, and every item on the list cost five lines of glue. My MSc thesis turned that observation into the actual research question: not "what should engineers do" but "what API shape makes doing the right thing cheaper than not doing it". The framework that came out the other end, `great-ai`, is a decorator you put on a plain Python function. The thesis behind it is the part I'd still hand someone today.

## The thing nobody wants to admit

The literature has a long list of habits you're supposed to adopt when shipping an ML service: track inputs, version models, expose health, log decisions, keep predictions reproducible. Everyone agrees with the list; almost nobody implements all of it. I spent the bulk of the thesis cataloguing 33 such habits, proposing 6 more, and surveying engineers about which ones actually got applied in their day jobs. The pattern in the answers wasn't ignorance, laziness, or budget. It was that the visible cost of each habit (a few lines of glue, multiplied across a whole stack) kept outbidding the invisible cost of skipping it. So skipping it became the default, even among people who'd argue passionately for the list.

You don't fix a default with another lecture. You fix it by repricing the choice.

## What one decorator buys

`@GreatAI.create` takes a regular prediction function and gives back a deployed service: a REST endpoint whose request schema is derived from the function's own signature, a trace store that records every prediction with inputs, latency, and model versions (a local JSON database by default, MongoDB if you point it at one), a live dashboard with execution-time histograms and a filterable trace table, an LRU cache, and argument validation straight from the type hints. A second decorator, `@use_model`, injects versioned model artefacts from disk or S3 and stamps the version it used into every trace, so "which model said this?" always has an answer.

Two rules kept the API surface from sprawling:

- **Implicit behaviour only for cross-cutting concerns.** Logging, versioning, and tracing happen without being asked. Anything touching business logic stays explicit. The test I used: if it would surprise me while debugging, it doesn't get to be implicit.
- **Own the contract, leave the storage alone.** GreatAI defines the shape of a trace and provides defaults; where you persist things is your choice. The model registry stays somebody else's library.

## Measuring whether it worked

Opinions about API design are cheap, so I tried to buy slightly better ones. Working engineers got a deliberately mundane task (take a half-finished notebook pair training a financial-sentiment classifier, fill in the TODOs, and deploy it with GreatAI) followed by a standard technology-acceptance questionnaire. The sample was small (ten respondents, so directional rather than gospel), but the signal was consistent: perceived ease of use tracked intent to adopt almost linearly (r ≈ 0.8), independently of how much the respondents valued the functionality itself. Which was the thesis's premise restated as data: a framework that ticks every box but is awkward will lose to a smaller one that isn't.

## What I'd change

- I'd narrow it further. Anything GreatAI did that overlaps with MLflow, BentoML, or a modern observability stack would go. The durable part was always the decorator and the catalogue behind it, not the dashboard.
- I'd publish the survey instrument separately. The 33-habit catalogue and the adoption-versus-impact methodology outlive the framework; it's the part people still ask about.
- I'd stop saying "best practices". I used the phrase throughout the thesis and it has aged into corporate wallpaper. The honest name is "things that hurt later if you skip them".
