[{"data":1,"prerenderedAt":528},["ShallowReactive",2],{"posts":3},[4,282,418,475],{"id":5,"title":6,"body":7,"date":270,"description":271,"extension":272,"featured":140,"image":273,"meta":274,"navigation":140,"path":275,"readingTime":109,"seo":276,"stem":277,"tags":278,"updated":280,"__hash__":281},"blog\u002Fblog\u002Fbuilding-with-intention.md","Building with intention, one small step at a time",{"type":8,"value":9,"toc":264},"minimark",[10,18,21,26,29,32,48,54,58,61,64,188,192,195,198,202,205,257,260],[11,12,13,14],"p",{},"Good software starts before the first line of code. It starts with a question: ",[15,16,17],"strong",{},"what should be easier for the person using this?",[11,19,20],{},"This journal is a place for exploring that question. These opening notes are examples of the topics this blog will cover: thoughtful engineering, small experiments, and the lessons hidden in everyday development.",[22,23,25],"h2",{"id":24},"start-with-a-problem-you-can-explain","Start with a problem you can explain",[11,27,28],{},"An idea becomes much easier to build when you can describe the problem in a single sentence. If that sentence needs three paragraphs of context, spend more time understanding the problem before choosing a framework.",[11,30,31],{},"A useful starting point is a short list:",[33,34,35,39,42,45],"ul",{},[36,37,38],"li",{},"Who experiences the problem?",[36,40,41],{},"What are they trying to accomplish?",[36,43,44],{},"What gets in the way today?",[36,46,47],{},"How will we know that our solution helped?",[49,50,51],"blockquote",{},[11,52,53],{},"Clarity is a feature. It makes every decision that follows a little easier.",[22,55,57],{"id":56},"build-the-smallest-useful-version","Build the smallest useful version",[11,59,60],{},"Small does not have to mean careless. A focused first version can still have accessible controls, understandable errors, and a clear path through the interface.",[11,62,63],{},"The goal is to reduce the number of assumptions you need to make. Deliver one complete journey, learn from it, and use that feedback to decide what comes next.",[65,66,71],"pre",{"className":67,"code":68,"language":69,"meta":70,"style":70},"language-ts shiki shiki-themes github-light github-dark","const iteration = {\n  problem: 'Make one task easier',\n  scope: 'One complete user journey',\n  feedback: 'Observe, ask, and improve',\n}\n\nfunction nextStep(learning: string) {\n  return { ...iteration, learning }\n}\n","ts","",[72,73,74,94,107,118,129,135,142,168,183],"code",{"__ignoreMap":70},[75,76,79,83,87,90],"span",{"class":77,"line":78},"line",1,[75,80,82],{"class":81},"szBVR","const",[75,84,86],{"class":85},"sj4cs"," iteration",[75,88,89],{"class":81}," =",[75,91,93],{"class":92},"sVt8B"," {\n",[75,95,97,100,104],{"class":77,"line":96},2,[75,98,99],{"class":92},"  problem: ",[75,101,103],{"class":102},"sZZnC","'Make one task easier'",[75,105,106],{"class":92},",\n",[75,108,110,113,116],{"class":77,"line":109},3,[75,111,112],{"class":92},"  scope: ",[75,114,115],{"class":102},"'One complete user journey'",[75,117,106],{"class":92},[75,119,121,124,127],{"class":77,"line":120},4,[75,122,123],{"class":92},"  feedback: ",[75,125,126],{"class":102},"'Observe, ask, and improve'",[75,128,106],{"class":92},[75,130,132],{"class":77,"line":131},5,[75,133,134],{"class":92},"}\n",[75,136,138],{"class":77,"line":137},6,[75,139,141],{"emptyLinePlaceholder":140},true,"\n",[75,143,145,148,152,155,159,162,165],{"class":77,"line":144},7,[75,146,147],{"class":81},"function",[75,149,151],{"class":150},"sScJk"," nextStep",[75,153,154],{"class":92},"(",[75,156,158],{"class":157},"s4XuR","learning",[75,160,161],{"class":81},":",[75,163,164],{"class":85}," string",[75,166,167],{"class":92},") {\n",[75,169,171,174,177,180],{"class":77,"line":170},8,[75,172,173],{"class":81},"  return",[75,175,176],{"class":92}," { ",[75,178,179],{"class":81},"...",[75,181,182],{"class":92},"iteration, learning }\n",[75,184,186],{"class":77,"line":185},9,[75,187,134],{"class":92},[22,189,191],{"id":190},"leave-room-to-learn","Leave room to learn",[11,193,194],{},"Architecture is a set of decisions made with incomplete information. Keep boundaries clear, name things carefully, and avoid making every choice permanent before you have evidence.",[11,196,197],{},"A small module with an explicit input and output is often a better starting point than a flexible abstraction nobody needs yet.",[22,199,201],{"id":200},"write-down-the-tradeoffs","Write down the tradeoffs",[11,203,204],{},"A short decision note is a gift to your future self. Capture the context, the option you chose, and the reason it made sense at the time.",[206,207,208,221],"table",{},[209,210,211],"thead",{},[212,213,214,218],"tr",{},[215,216,217],"th",{},"Question",[215,219,220],{},"What to capture",[222,223,224,233,241,249],"tbody",{},[212,225,226,230],{},[227,228,229],"td",{},"What changed?",[227,231,232],{},"The problem or constraint",[212,234,235,238],{},[227,236,237],{},"What did we choose?",[227,239,240],{},"The smallest viable decision",[212,242,243,246],{},[227,244,245],{},"Why this approach?",[227,247,248],{},"Benefits and known tradeoffs",[212,250,251,254],{},[227,252,253],{},"When should we revisit it?",[227,255,256],{},"A concrete signal",[11,258,259],{},"The result is more than working software. It is a system you can understand, change, and keep improving.",[261,262,263],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":70,"searchDepth":96,"depth":96,"links":265},[266,267,268,269],{"id":24,"depth":96,"text":25},{"id":56,"depth":96,"text":57},{"id":190,"depth":96,"text":191},{"id":200,"depth":96,"text":201},"2026-09-19","A practical approach to turning a rough idea into useful software — without losing sight of the problem you set out to solve.","md","\u002Fsocial-card.png",{},"\u002Fblog\u002Fbuilding-with-intention",{"title":6,"description":271},"blog\u002Fbuilding-with-intention",[279],"Software engineering",null,"TRzvOwuLNJf5pE80Qg2z7vIz-hKcTUzWuasvpQTakBg",{"id":283,"title":284,"body":285,"date":408,"description":409,"extension":272,"featured":410,"image":273,"meta":411,"navigation":140,"path":412,"readingTime":96,"seo":413,"stem":414,"tags":415,"updated":280,"__hash__":417},"blog\u002Fblog\u002Freliable-api-boundaries.md","Reliable APIs start at the boundaries",{"type":8,"value":286,"toc":403},[287,290,294,297,383,387,390,394,397,400],[11,288,289],{},"An API boundary is where your assumptions meet someone else's code. Making that boundary explicit reduces surprises on both sides.",[22,291,293],{"id":292},"validate-before-doing-work","Validate before doing work",[11,295,296],{},"Validate the shape of an incoming request before passing it into the application. Keep transport concerns separate from business rules: a missing field and an unavailable product are different kinds of problems.",[65,298,302],{"className":299,"code":300,"language":301,"meta":70,"style":70},"language-csharp shiki shiki-themes github-light github-dark","public record CreateNoteRequest(string Title, string Body);\n\napp.MapPost(\"\u002Fnotes\", (CreateNoteRequest request) =>\n{\n    if (string.IsNullOrWhiteSpace(request.Title))\n    {\n        return Results.ValidationProblem(new Dictionary\u003Cstring, string[]>\n        {\n            [\"title\"] = [\"A title is required.\"]\n        });\n    }\n\n    \u002F\u002F Demonstration only: persist the note in a real application.\n    return Results.Ok(new { title = request.Title.Trim() });\n});\n","csharp",[72,303,304,309,313,318,323,328,333,338,343,348,354,360,365,371,377],{"__ignoreMap":70},[75,305,306],{"class":77,"line":78},[75,307,308],{},"public record CreateNoteRequest(string Title, string Body);\n",[75,310,311],{"class":77,"line":96},[75,312,141],{"emptyLinePlaceholder":140},[75,314,315],{"class":77,"line":109},[75,316,317],{},"app.MapPost(\"\u002Fnotes\", (CreateNoteRequest request) =>\n",[75,319,320],{"class":77,"line":120},[75,321,322],{},"{\n",[75,324,325],{"class":77,"line":131},[75,326,327],{},"    if (string.IsNullOrWhiteSpace(request.Title))\n",[75,329,330],{"class":77,"line":137},[75,331,332],{},"    {\n",[75,334,335],{"class":77,"line":144},[75,336,337],{},"        return Results.ValidationProblem(new Dictionary\u003Cstring, string[]>\n",[75,339,340],{"class":77,"line":170},[75,341,342],{},"        {\n",[75,344,345],{"class":77,"line":185},[75,346,347],{},"            [\"title\"] = [\"A title is required.\"]\n",[75,349,351],{"class":77,"line":350},10,[75,352,353],{},"        });\n",[75,355,357],{"class":77,"line":356},11,[75,358,359],{},"    }\n",[75,361,363],{"class":77,"line":362},12,[75,364,141],{"emptyLinePlaceholder":140},[75,366,368],{"class":77,"line":367},13,[75,369,370],{},"    \u002F\u002F Demonstration only: persist the note in a real application.\n",[75,372,374],{"class":77,"line":373},14,[75,375,376],{},"    return Results.Ok(new { title = request.Title.Trim() });\n",[75,378,380],{"class":77,"line":379},15,[75,381,382],{},"});\n",[22,384,386],{"id":385},"make-failures-understandable","Make failures understandable",[11,388,389],{},"A useful error tells a caller what went wrong and what they can do next. Use consistent status codes and a stable error shape. Keep stack traces and internal details in your logs.",[22,391,393],{"id":392},"design-for-retries","Design for retries",[11,395,396],{},"Networks fail. Clients retry. For operations with side effects, decide how to recognize a repeated request before the first duplicate arrives.",[11,398,399],{},"The implementation depends on your system, but the question is universal: can this operation safely happen twice?",[261,401,402],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":70,"searchDepth":96,"depth":96,"links":404},[405,406,407],{"id":292,"depth":96,"text":293},{"id":385,"depth":96,"text":386},{"id":392,"depth":96,"text":393},"2026-09-17","Clear contracts, useful errors, and a few deliberate choices that make services easier to work with.",false,{},"\u002Fblog\u002Freliable-api-boundaries",{"title":284,"description":409},"blog\u002Freliable-api-boundaries",[416,279],".NET","CZlWgOX1j0Kj7tLRT--KJ3k4CCHPdVZlrJ2BqKMP9oA",{"id":419,"title":420,"body":421,"date":466,"description":467,"extension":272,"featured":410,"image":273,"meta":468,"navigation":140,"path":469,"readingTime":96,"seo":470,"stem":471,"tags":472,"updated":280,"__hash__":474},"blog\u002Fblog\u002Fai-experiments-that-teach.md","Make your AI experiments teach you something",{"type":8,"value":422,"toc":461},[423,426,430,433,437,440,451,455,458],[11,424,425],{},"A compelling demo can be the beginning of a useful idea. To learn whether it actually works, give the experiment a question it can answer.",[22,427,429],{"id":428},"keep-a-baseline","Keep a baseline",[11,431,432],{},"Before adding a model to a workflow, record how the task works today. A simple rules-based solution may be enough, and it provides a useful comparison when it is not.",[22,434,436],{"id":435},"collect-representative-examples","Collect representative examples",[11,438,439],{},"A small set of realistic inputs is more useful than a single carefully chosen prompt. Include ordinary cases, ambiguous cases, and cases where the right behavior is to ask for more information.",[33,441,442,445,448],{},[36,443,444],{},"Define what a good answer must contain.",[36,446,447],{},"Record examples of unacceptable outputs.",[36,449,450],{},"Keep evaluation examples separate from prompt development examples.",[22,452,454],{"id":453},"inspect-the-failures","Inspect the failures",[11,456,457],{},"An average score is only part of the story. Group failures by cause, then choose one improvement to test. Changing the prompt, retrieval, and model together makes it harder to understand which change helped.",[11,459,460],{},"The goal is repeatable learning: a record of what you tried, what changed, and what you still do not know.",{"title":70,"searchDepth":96,"depth":96,"links":462},[463,464,465],{"id":428,"depth":96,"text":429},{"id":435,"depth":96,"text":436},{"id":453,"depth":96,"text":454},"2026-09-14","Start with a small question, keep a baseline, and turn a promising demo into an experiment you can evaluate.",{},"\u002Fblog\u002Fai-experiments-that-teach",{"title":420,"description":467},"blog\u002Fai-experiments-that-teach",[473],"Artificial intelligence","WJ_dnI3VFnGWOaLI34Qii7MHDQmUHCufu6CaHDYI56A",{"id":476,"title":477,"body":478,"date":518,"description":519,"extension":272,"featured":410,"image":273,"meta":520,"navigation":140,"path":521,"readingTime":96,"seo":522,"stem":523,"tags":524,"updated":280,"__hash__":527},"blog\u002Fblog\u002Fshipping-is-part-of-building.md","Shipping is part of building",{"type":8,"value":479,"toc":513},[480,483,487,490,493,497,500,503,507,510],[11,481,482],{},"A feature is not finished when it works on a laptop. It needs a repeatable way to reach users and a clear way to recover when something goes wrong.",[22,484,486],{"id":485},"shorten-the-path-to-production","Shorten the path to production",[11,488,489],{},"Start with a small deployment pipeline. Build the application, run the checks that matter, and produce an artifact you can deploy consistently.",[11,491,492],{},"Keep environment-specific configuration outside the application code. Document required variables and provide safe examples without credentials.",[22,494,496],{"id":495},"make-the-system-observable","Make the system observable",[11,498,499],{},"Decide what you need to know before an incident happens. Useful signals include failed requests, slow operations, and whether a background task completed.",[11,501,502],{},"Logs should help answer a question. Avoid recording sensitive request bodies simply because they are available.",[22,504,506],{"id":505},"practice-recovery","Practice recovery",[11,508,509],{},"A rollback plan is more valuable when you have tried it. Know which changes are reversible and which need a forward fix, especially when a release changes stored data.",[11,511,512],{},"Reliable delivery is a habit built through small, repeatable steps.",{"title":70,"searchDepth":96,"depth":96,"links":514},[515,516,517],{"id":485,"depth":96,"text":486},{"id":495,"depth":96,"text":496},{"id":505,"depth":96,"text":506},"2026-09-10","Bring deployment, observability, and recovery into the development loop from the beginning.",{},"\u002Fblog\u002Fshipping-is-part-of-building",{"title":477,"description":519},"blog\u002Fshipping-is-part-of-building",[525,526],"DevOps","Full-stack","EhDns5ttyhKfL-iIASOX9hbMzoKQmv2E5u5xPkdmgMw",1789824594512]