Preparing your learning space...
25% through Rapid Prototyping tutorials
You'll build your first real Forward Deployed Engineer prototype — deciding what to build, picking the fastest possible stack, and shipping a rough version in a day — then sharpen it into a Minimum Viable Product (MVP): the smallest thing a real user can use to tell you if the idea is worth it.
An FDE prototype is a working slice of a business workflow — real data moving through a simplified version of the eventual product. Your first one does not have to be impressive. It has to be honest: it shows the customer something concrete they can react to.
The sweet spot is a single workflow, end to end. Not "the whole CRM tool" — "look up a customer's orders and show their lifetime value." One route, one question, one screen. Anything bigger and you'll spend the week wiring things instead of learning.
Note: the first prototype's real output is a conversation with a customer — the code is a means to that end.
Ask: what single thing, if wrong, sinks the whole idea? That's your "riskiest assumption." Build around that, not around the easy bits.
| If your biggest unknown is… | ...then prototype this |
|---|---|
| Will anyone use it? | A clickable tool they can try |
| Does the AI answer help? | One chatbot with real context |
| Can we pull the data? | One API call wired to real data |
| Will they pay? | A price screen and a "subscribe" button |
If you're unsure which is the riskiest, that's your answer: you don't understand the problem well enough to build the right thing. Go re-interview the customer first (the loop from Tutorial 1).
Speed is a feature here. Choose tools where the gap between idea and something on screen is smallest. A proven fast combination for FDE prototypes:
| Need | Fast choice |
|---|---|
| Web UI that's just data | Streamlit or Gradio (Python) |
| A quick backend/API | FastAPI (Python) |
| Chatbot | an LLM SDK (OpenAI/Anthropic) |
| Fake data | Faker library |
Avoid, at this stage: setting up a database you don't need yet, a front-end framework build pipeline, user accounts, microservices. Each of those adds hours before you've learned anything.
# A Streamlit "tool" in ~10 lines — real data on screen, fast
import streamlit as st
import pandas as pd
df = pd.read_csv("customers.csv") # pull your real or mock data
st.title("Customer Lookup")
name = st.text_input("Customer name")
st.dataframe(df[df["name"].str.contains(name, case=False)])
Explanation: in a handful of lines you get a searchable tool the customer can actually click. This is the prototype loop's "build" step done in minutes, leaving budget for the test and learn steps.
Time-box the first prototype to a single working day (the "day box"). A day forces judgment: you physically cannot build everything, so you must separate the 20% that proves the idea from the 80% that doesn't.
Roughly:
If a day feels too tight, that's actually a warning sign you chose too big a slice — cut scope, not the deadline.
Best Practice: you learn more from a working half-product demoed to a real user than from a "complete" one nobody sees. A day-box guarantees the demo happens.
The fastest way to validate the idea is often to not connect anything at all. Use hard-coded or mock data (Tutorial 6) to make the flow feel real before spending time on real integrations.
# Fake but believable data to test flow, not plumbing
orders = [
{"id": 101, "customer": "Acme", "amount": 1200.00, "date": "2026-08-01"},
{"id": 102, "customer": "Nile", "amount": 480.00, "date": "2026-08-14"},
{"id": 103, "customer": "Acme", "amount": 3200.50, "date": "2026-08-19"},
]
total = sum(o["amount"] for o in orders if o["customer"] == customer_name)
Explanation: this lets the customer react to the concept — the metric, the layout — without you building authentication or a database. Only worry about real plumbing once the idea survives this test.
Your prototype should look intentionally rough but not broken. The bar is: a real user takes it seriously enough to give real feedback, but it's obviously not finished — that invitation to critique is exactly what you want.
Once the prototype wins a "yes, I'd use this, keep going," the goal shifts. The prototype proved the idea was walkable; the Minimum Viable Product (MVP) is the smallest version of it that a set of users can adopt and rely on for real. The difference:
The MVP crosses the "if it broke tomorrow, someone would be harmed" line from Tutorial 1. Mock data, hard-coded values, and manual run-it-yourself no longer cut it.
"Minimum" is easy to get wrong. It means fewest features that solve the core problem, not cheapest thing that technically runs, and not a half-built clone of the eventual product.
Ask of every planned feature: does it serve the user's core task, or is it a nice-to-have we assumed? Anything that only a minority of users need, or that's decoration, is cut.
The reframe that helps many: an MVP is bold, working, and thin. Bold because it commits to a real solution, working because users depend on it, and thin because you shaved every edge off the first release.
Before writing a line, write the product's core loop in one sentence: the minimum the user does, end to end, to get value.
A customer looks up an account → sees open invoices → pays one. Done.
That sentence is your scope checklist. Every screen you keep must be part of that loop; every screen outside it is a candidate to cut. If your MVP has a page that isn't in the loop, you've already over-built.
Here is the smallest honest MVP for that "pay an invoice" loop — a FastAPI endpoint plus a simple in-memory store:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Payment(BaseModel):
invoice_id: int
amount: float
paid_invoices = set() # stand-in for a real DB in prototyping
@app.get("/invoices/{account_id}")
def invoices(account_id: int):
# fetch from a real store/repository in the production version
return [{"id": 1, "amount": 100.0, "due": "2026-09-01", "paid": False}]
@app.post("/pay")
def pay(payment: Payment):
if payment.amount <= 0:
raise HTTPException(status_code=400, detail="amount must be positive")
paid_invoices.add(payment.invoice_id)
return {"status": "paid", "invoice_id": payment.invoice_id}
Explanation: the MVP does the whole core loop — list invoices, accept a payment, record it. Validation on the money amount is one small, exactly-right hardening step for the "real user might be hurt" stage. Auth, retries, a proper database: backlog, not scope.
The fastest route to "minimum" is deciding what to not build yet:
Common Mistake: shipping an MVP that's really a prototype — users depend on it but it still breaks if you're not running it. And the reverse: shipping a full product to a nobody-has-confirmed-yet audience.
Save your progress and earn XP for completing tutorials.
4 questions · Pass with 70%+
1What should your first prototype focus on?
2What is the recommended time-box for a first prototype?
3What does "minimum" mean in MVP (Minimum Viable Product)?
4Which of these belongs in an MVP's first version?
Technology
Forward Deployed Engineer
Lesson group
Rapid Prototyping
Progress
25% complete