[{"data":1,"prerenderedAt":2664},["ShallowReactive",2],{"blog-the-new-engineering-loop":3,"related-the-new-engineering-loop":331},{"id":4,"title":5,"body":6,"date":316,"description":317,"extension":318,"image":319,"meta":320,"navigation":321,"path":322,"readingTime":323,"seo":324,"stem":325,"tags":326,"__hash__":330},"blog/blog/the-new-engineering-loop.md","The New Engineering Loop: Architect, Delegate, Review, Repeat",{"type":7,"value":8,"toc":306},"minimark",[9,13,16,19,22,25,28,31,34,39,42,45,48,51,67,70,73,79,82,85,111,114,117,120,124,127,130,133,136,156,159,162,165,168,171,174,178,181,184,187,190,193,196,199,219,222,225,229,232,235,238,241,244,247,250,254,257,260,263,266,269,272,275,278,281,285,288,291,294,297,300,303],[10,11,12],"p",{},"There is a real shift happening in software engineering, and pretending otherwise is dumb.",[10,14,15],{},"More of the day-to-day act of programming is becoming delegatable. Not all of it. Not the hard parts. Not the accountability. But a surprising amount of the mechanical middle is now fair game. Boilerplate, refactors, tests, repetitive CRUD, documentation scaffolding, migration scripts, admin tools, one-off data transforms, component variations, adapter layers. A lot of the stuff that used to eat half a week can now show up in half an hour.",[10,17,18],{},"That does not mean engineering is disappearing. It means the loop is changing.",[10,20,21],{},"The old loop looked something like this: understand the problem, write the code, run the code, fix the code, ship the code.",[10,23,24],{},"The new loop looks more like this: understand the problem, architect the shape of the solution, delegate chunks of execution, review what came back, repair the gaps, then ship the result.",[10,26,27],{},"That is not a small adjustment. It changes where leverage lives. It changes what senior engineers spend time on. It changes what junior engineers need to learn. It changes how teams should define quality. And if you do not notice the shift, you end up optimizing for the wrong thing.",[10,29,30],{},"The job is starting to look less like typing every line yourself and more like running a control tower. You are routing work, setting constraints, sequencing dependencies, watching for collisions, and taking manual control the second something looks off.",[10,32,33],{},"That sounds efficient because it is. It also sounds dangerous because it is that too.",[35,36,38],"h2",{"id":37},"delegation-only-works-when-the-work-is-well-shaped","Delegation Only Works When the Work Is Well-Shaped",[10,40,41],{},"Most people are still trying to use AI like an eager intern with infinite stamina. That is the wrong mental model.",[10,43,44],{},"The useful model is this: you are working with a fast but unreliable implementation engine. It does not actually know what matters unless you tell it. It does not understand your business in the way you think it does. It will confidently fill in blanks with plausible garbage if you leave room for interpretation.",[10,46,47],{},"So the first skill that matters more now is decomposition.",[10,49,50],{},"Can you break a problem into pieces that are:",[52,53,54,58,61,64],"ul",{},[55,56,57],"li",{},"Independently understandable",[55,59,60],{},"Small enough to verify",[55,62,63],{},"Constrained enough to execute safely",[55,65,66],{},"Ordered in a way that limits blast radius",[10,68,69],{},"That is architecture, even when the problem is small.",[10,71,72],{},"The bad version of delegation sounds like this:",[74,75,76],"blockquote",{},[10,77,78],{},"Build the billing sync for our legacy customer records and make sure it handles all the edge cases.",[10,80,81],{},"That prompt is vague, overloaded, and almost guaranteed to produce something superficially complete and structurally wrong.",[10,83,84],{},"The better version looks like actual engineering:",[52,86,87,90,93,96,99,102,105,108],{},[55,88,89],{},"Define the source of truth",[55,91,92],{},"List the record states that matter",[55,94,95],{},"Specify the external API contract",[55,97,98],{},"Name the failure cases that must not be dropped",[55,100,101],{},"Separate mapping logic from transport logic",[55,103,104],{},"Require idempotency",[55,106,107],{},"Require logging for reconciliation",[55,109,110],{},"Require tests around duplicate deliveries and partial failures",[10,112,113],{},"At that point, the prompt is not magic. It is just a compact spec. And the better the spec, the better the delegated output.",[10,115,116],{},"That means a lot of engineering leverage is moving toward people who can reduce ambiguity. Not people who can produce the most words. Not people who can write the most baroque prompt incantations. People who can think clearly about boundaries, invariants, and failure modes.",[10,118,119],{},"That is not hype. That is systems work.",[35,121,123],{"id":122},"prompting-is-becoming-a-design-skill","Prompting Is Becoming a Design Skill",[10,125,126],{},"I think people talk about prompting in the most unserious way possible.",[10,128,129],{},"They treat it like a bag of clever phrases. A secret handshake. A collection of formatting tricks. Sometimes that helps at the margins, but that is not the core skill. The real skill is specifying intent with enough precision that execution can be delegated without surrendering correctness.",[10,131,132],{},"In other words, good prompting is mostly architecture and review discipline wearing a fake mustache.",[10,134,135],{},"A strong prompt usually contains the same things a good technical design contains:",[52,137,138,141,144,147,150,153],{},[55,139,140],{},"Clear objective",[55,142,143],{},"Constraints",[55,145,146],{},"Inputs and outputs",[55,148,149],{},"Non-goals",[55,151,152],{},"Edge cases",[55,154,155],{},"Acceptance criteria",[10,157,158],{},"If you are vague about any of those, the result gets weird fast.",[10,160,161],{},"This is why some engineers feel like AI is incredible and others feel like it is useless. Often they are not using different models. They are bringing different levels of technical clarity to the interaction.",[10,163,164],{},"If your prompt is \"clean this up,\" you deserve the chaos that follows.",[10,166,167],{},"If your prompt is \"refactor this module to isolate the persistence layer behind an interface, preserve current behavior, keep the public API stable, and add regression tests for these three edge cases,\" now we are getting somewhere.",[10,169,170],{},"The important shift is that design intent has to become more explicit earlier in the loop. You cannot hide behind \"I will work it out while coding\" to the same degree, because the quality of what you delegate depends on what you decided up front.",[10,172,173],{},"That is one reason I think architecture is becoming more important, not less. When implementation gets cheaper, decision quality matters more.",[35,175,177],{"id":176},"review-is-no-longer-a-nice-to-have","Review Is No Longer a Nice-to-Have",[10,179,180],{},"If delegation expands, review becomes the choke point for quality.",[10,182,183],{},"That should make perfect sense, but a lot of teams are still treating AI output like a shortcut around engineering rigor. That is how you end up with a repo full of polished-looking nonsense.",[10,185,186],{},"Generated code often has a particular smell. It is locally reasonable and globally untrustworthy. The function seems fine. The types look respectable. The tests appear confident. Then you pull on one thread and realize it misunderstood transaction boundaries, skipped a domain invariant, duplicated logic that should stay centralized, or quietly changed behavior in a way that only shows up under production load.",[10,188,189],{},"This is why style review is not enough.",[10,191,192],{},"The old bad pull request had obvious tells. Inconsistent naming. Weird formatting. Missing tests. A careless engineer giving themselves away.",[10,194,195],{},"The new bad pull request can look immaculate.",[10,197,198],{},"That means review has to focus on deeper questions:",[52,200,201,204,207,210,213,216],{},[55,202,203],{},"Is the behavior actually correct?",[55,205,206],{},"Are the invariants preserved?",[55,208,209],{},"Does this fit the architecture or just imitate it?",[55,211,212],{},"Is the abstraction helping, or did we just hide complexity behind another layer?",[55,214,215],{},"What assumptions did the implementation make without proving them?",[55,217,218],{},"What happens when the happy path fails?",[10,220,221],{},"Those questions are slower than scanning for code style. Too bad. They matter more.",[10,223,224],{},"If your team is increasing the amount of code produced through agents, then code review needs to get stricter, not looser. Faster code generation should buy time for better judgment, not justify lower standards.",[35,226,228],{"id":227},"the-most-valuable-engineers-will-be-the-ones-who-can-recover","The Most Valuable Engineers Will Be the Ones Who Can Recover",[10,230,231],{},"Here is the part people skip when they talk about AI-assisted engineering: somebody still has to save the project when the generated solution falls apart.",[10,233,234],{},"Somebody has to notice the coupling problem.\nSomebody has to trace the production incident.\nSomebody has to figure out why the retry policy is amplifying duplicate writes.\nSomebody has to explain why the test passed and the system still broke.",[10,236,237],{},"That work does not go away. It becomes more concentrated.",[10,239,240],{},"When the easy code is cheap, the hard parts become the job.",[10,242,243],{},"This is why I do not buy the idea that engineers are turning into prompt managers. Prompting is part of the loop now, sure. Delegation is part of the loop. But the real value is still in judgment. Knowing what to build, knowing how to split it up, knowing how to inspect it, and knowing how to recover when reality refuses to match the plan.",[10,245,246],{},"The engineer who can take manual control when the abstractions fail is still the engineer you want in the room.",[10,248,249],{},"In fact, I would argue they are more valuable now, because it is getting easier for teams to produce a lot of code without producing a lot of understanding.",[35,251,253],{"id":252},"you-still-need-reps","You Still Need Reps",[10,255,256],{},"This is where a lot of people are going to get themselves into trouble.",[10,258,259],{},"If more of the loop becomes delegation and supervision, it is tempting to stop doing the hands-on parts entirely. That feels efficient right up until it is not.",[10,261,262],{},"You cannot supervise well in a domain where you no longer have tactile familiarity.",[10,264,265],{},"If you never write query-heavy code anymore, your ability to spot bad data access patterns degrades.\nIf you never debug the ugly production issue yourself, your incident instincts soften.\nIf you never write tests from first principles, you stop noticing when generated tests are decorative instead of protective.\nIf you never read the stack traces, inspect the network calls, or trace the state transitions, you eventually lose the thread.",[10,267,268],{},"And then your supervision becomes ceremonial.",[10,270,271],{},"You are no longer reviewing from understanding. You are reviewing from vibes.",[10,273,274],{},"That is a terrible place to be.",[10,276,277],{},"I think strong teams are going to treat hands-on work the way good athletes treat drills. Not every rep needs to happen under game-day pressure, but the reps still need to happen. Engineers should still write real code. Still debug real failures. Still sketch solutions before handing them off. Still form opinions before asking the machine to autocomplete their thinking.",[10,279,280],{},"The point is not purity. The point is calibration.",[35,282,284],{"id":283},"this-shift-is-real-but-it-is-not-an-excuse-to-get-soft","This Shift Is Real, but It Is Not an Excuse to Get Soft",[10,286,287],{},"I am not interested in the fake binary where you either reject AI entirely or surrender all implementation to it. Both positions are lazy.",[10,289,290],{},"The practical reality is that engineering is becoming a higher-leverage orchestration job in many contexts. More of us will spend more time defining the work than typing every character of the work. That is real. Teams that ignore it will move slower for no reason.",[10,292,293],{},"But the opposite mistake is just as bad. If you let the tooling replace your contact with the underlying system, you will lose the exact instincts that make delegation safe in the first place.",[10,295,296],{},"So yes, the loop is changing.",[10,298,299],{},"Architect more deliberately.\nDelegate more intentionally.\nReview more skeptically.\nRepeat as often as needed.",[10,301,302],{},"Just do not confuse less typing with less engineering.",[10,304,305],{},"The typing was never the whole job. It was just the most visible part.",{"title":307,"searchDepth":308,"depth":308,"links":309},"",2,[310,311,312,313,314,315],{"id":37,"depth":308,"text":38},{"id":122,"depth":308,"text":123},{"id":176,"depth":308,"text":177},{"id":227,"depth":308,"text":228},{"id":252,"depth":308,"text":253},{"id":283,"depth":308,"text":284},"2026-03-19","AI is shifting engineering work upward toward decomposition, constraints, review, and recovery, but only if we stay sharp enough to judge what it produces.","md",null,{},true,"/blog/the-new-engineering-loop",9,{"title":5,"description":317},"blog/the-new-engineering-loop",[327,328,329],"Architecture","Leadership","Code","g5XCRSwTq8g_sRFMj0YHcXoHhYESe_SJyVGa405MfBY",[332,679,2058],{"id":333,"title":334,"body":335,"date":671,"description":672,"extension":318,"image":319,"meta":673,"navigation":321,"path":674,"readingTime":323,"seo":675,"stem":676,"tags":677,"__hash__":678},"blog/blog/dont-outsource-your-instincts.md","Don’t Outsource Your Instincts",{"type":7,"value":336,"toc":657},[337,340,346,349,352,355,358,361,365,368,371,374,377,380,383,386,389,392,395,398,401,404,407,410,414,417,420,423,426,429,446,449,452,455,459,462,465,468,471,474,477,480,483,486,489,492,495,499,502,505,510,513,516,519,523,526,529,532,535,539,542,545,548,551,555,558,561,564,567,570,574,577,580,597,600,617,620,623,626,629,632,636,639,642,645,648,651,654],[10,338,339],{},"I say some version of this to my team all the time:",[10,341,342],{},[343,344,345],"strong",{},"Don’t use AI to outsource your knowledge. Use it to enhance and speed up what you already know how to do.",[10,347,348],{},"I keep repeating it because the temptation is obvious. The tools are fast. They are available all the time. They sound confident. They can produce a lot of output in a hurry. When you are tired, behind, or context-swamped, it is incredibly easy to let them take over parts of the job you should still be doing yourself.",[10,350,351],{},"That is the risk.",[10,353,354],{},"Not that the tools will write bad code. Of course they will sometimes write bad code. Humans do that too.",[10,356,357],{},"The real risk is that you slowly stop exercising the muscles that let you tell the difference.",[10,359,360],{},"That is a much more serious problem than a bad suggestion in a chat window. Bad suggestions can be rejected. Atrophied judgment is harder to fix.",[35,362,364],{"id":363},"the-failure-mode-is-becoming-a-passenger","The Failure Mode Is Becoming a Passenger",[10,366,367],{},"There is a certain kind of engineer who looks productive in an AI-heavy environment right up until you ask one hard follow-up question.",[10,369,370],{},"Why is this query structured that way?",[10,372,373],{},"Not sure, the model suggested it.",[10,375,376],{},"Why are we confident this retry logic is safe?",[10,378,379],{},"It looked right and the tests passed.",[10,381,382],{},"Why did we choose this abstraction boundary?",[10,384,385],{},"It seemed cleaner.",[10,387,388],{},"Why is the cache invalidation handled here instead of at the write path?",[10,390,391],{},"Silence.",[10,393,394],{},"That is what becoming a passenger sounds like.",[10,396,397],{},"You are still touching the wheel, but you are no longer really driving.",[10,399,400],{},"And to be clear, this is not a junior engineer problem. Senior people can drift into this just as easily, sometimes faster. Experience can create a false sense that your taste alone will catch everything. It will not. Taste matters, but taste without active technical contact turns into aesthetic preference with better vocabulary.",[10,402,403],{},"If you stop reasoning through the system yourself, eventually you stop noticing what the system is doing.",[10,405,406],{},"That is why I dislike the framing that AI \"frees us from the boring parts\" with no downside. Some repetitive work absolutely should be delegated. Good. Please do that. But a lot of what people call boring is actually where technical instinct gets reinforced.",[10,408,409],{},"Reading a diff carefully is not glamorous. Tracing a bug across three services is not glamorous. Working through a failing test instead of re-prompting until it goes green is definitely not glamorous. But that is where your map of the system stays accurate.",[35,411,413],{"id":412},"skill-atrophy-does-not-announce-itself","Skill Atrophy Does Not Announce Itself",[10,415,416],{},"The tricky part is that you do not feel yourself getting rusty in real time.",[10,418,419],{},"You feel faster.",[10,421,422],{},"You feel assisted.",[10,424,425],{},"You feel like you are clearing tickets at an impressive clip.",[10,427,428],{},"Meanwhile, some important things may be quietly slipping:",[52,430,431,434,437,440,443],{},[55,432,433],{},"Your first instinct is to ask for an answer instead of forming a hypothesis",[55,435,436],{},"Your tolerance for reading unfamiliar code drops",[55,438,439],{},"Your ability to reason about performance from the code alone gets weaker",[55,441,442],{},"Your debugging loop starts with re-prompting instead of investigation",[55,444,445],{},"You accept tests as proof even when you did not inspect what they actually protect",[10,447,448],{},"That is not acceleration. That is dependency wearing a productivity costume.",[10,450,451],{},"I am not making a moral argument here. I am making a practical one. The moment a novel failure shows up, borrowed competence gets exposed. The moment the generated code collides with a weird domain rule, a flaky third-party service, an ugly migration path, or a production-only concurrency issue, you are back to fundamentals whether you like it or not.",[10,453,454],{},"And if you have spent six months outsourcing the fundamentals, that moment is going to hurt.",[35,456,458],{"id":457},"use-ai-after-you-have-a-point-of-view","Use AI After You Have a Point of View",[10,460,461],{},"One of the simplest ways to stay sharp is this: do not start with the model when the problem matters.",[10,463,464],{},"Start by thinking.",[10,466,467],{},"Not for an hour. Not to prove your purity. Just long enough to establish a point of view.",[10,469,470],{},"What do you think the bug is?\nWhat do you think the right shape of the solution is?\nWhat constraints matter?\nWhat part are you least sure about?\nWhat would you try if the tool vanished for the next thirty minutes?",[10,472,473],{},"That matters because AI is much more useful as a multiplier on direction than as a substitute for direction.",[10,475,476],{},"If you already have a hypothesis, you can use the tool to pressure-test it, accelerate implementation, compare alternatives, generate scaffolding, or fill in syntax you do not feel like typing.",[10,478,479],{},"If you do not have a hypothesis, you are mostly inviting the tool to think on your behalf.",[10,481,482],{},"That can feel productive, but it is a bad long-term trade.",[10,484,485],{},"I want engineers who can say, \"Here is my current read on the problem, here are the likely failure points, and here is where I want help moving faster.\"",[10,487,488],{},"That person is using AI well.",[10,490,491],{},"I do not want engineers who say, \"I pasted in the file and this is what it gave me.\"",[10,493,494],{},"That is not engineering leverage. That is surrender with better formatting.",[35,496,498],{"id":497},"the-habits-that-keep-you-dangerous","The Habits That Keep You Dangerous",[10,500,501],{},"If you want to use these tools heavily without getting soft, you need habits that keep your instincts alive.",[10,503,504],{},"Nothing fancy. Just disciplined reps.",[506,507,509],"h3",{"id":508},"_1-trace-at-least-some-bugs-manually","1. Trace at Least Some Bugs Manually",[10,511,512],{},"Do not let every debugging session begin and end in a prompt window.",[10,514,515],{},"Read the stack trace.\nInspect the logs.\nWalk the request path.\nCheck the state transitions.\nReproduce the issue yourself before you ask for a summary.",[10,517,518],{},"You do not have to do this for every tiny paper cut. But if the problem is real, your brain should touch the system directly before delegation takes over.",[506,520,522],{"id":521},"_2-read-diffs-like-you-mean-it","2. Read Diffs Like You Mean It",[10,524,525],{},"Generated code has a way of looking finished before it is correct. The formatting is clean. The comments sound confident. The tests appear thoughtful. None of that guarantees the behavior is right.",[10,527,528],{},"So read the diff.",[10,530,531],{},"Not just for style. Read it for assumptions. Read it for hidden coupling. Read it for duplicated logic, suspicious abstractions, and strangely convenient defaults. Read it as if you expect it to contain one subtle lie, because sometimes it does.",[10,533,534],{},"The goal is not paranoia. The goal is contact.",[506,536,538],{"id":537},"_3-write-important-parts-by-hand","3. Write Important Parts by Hand",[10,540,541],{},"Some code should still go through your fingers.",[10,543,544],{},"Boundary definitions. Core domain logic. Complex state transitions. Tricky queries. Recovery code. Anything where correctness depends on real understanding and not just pattern matching.",[10,546,547],{},"I am not saying every important function must be handwritten like a love letter from 2009. I am saying there is value in still doing difficult work yourself often enough to keep your instincts calibrated.",[10,549,550],{},"When you handwrite hard code, you are forced to notice the shape of the problem. You do not get to skip straight to the plausible answer.",[506,552,554],{"id":553},"_4-form-a-hypothesis-before-asking-for-help","4. Form a Hypothesis Before Asking for Help",[10,556,557],{},"This might be the highest-leverage habit of the bunch.",[10,559,560],{},"Before you ask AI why something is broken, write down your guess. Even if it is wrong. Especially if it is wrong.",[10,562,563],{},"That tiny pause trains you to stay in the problem. It keeps your diagnostic muscles engaged. It also gives you a much better basis for evaluating the answer you get back.",[10,565,566],{},"If the suggestion contradicts your hypothesis, great. Now you have something to compare. If you skip the hypothesis step entirely, you are much more likely to accept the first plausible explanation because it sounds coherent.",[10,568,569],{},"Coherent is not the same as true.",[35,571,573],{"id":572},"assisted-engineering-versus-borrowed-competence","Assisted Engineering Versus Borrowed Competence",[10,575,576],{},"This is the distinction I care about most.",[10,578,579],{},"Assisted engineering looks like this:",[52,581,582,585,588,591,594],{},[55,583,584],{},"You understand the task",[55,586,587],{},"You have a view on the solution",[55,589,590],{},"You use AI to move faster",[55,592,593],{},"You review the output with real judgment",[55,595,596],{},"You can explain and defend the final result",[10,598,599],{},"Borrowed competence looks like this:",[52,601,602,605,608,611,614],{},[55,603,604],{},"You do not fully understand the task",[55,606,607],{},"You delegate your way to a plausible artifact",[55,609,610],{},"You rely on surface confidence as validation",[55,612,613],{},"You cannot explain the tradeoffs",[55,615,616],{},"You struggle the moment something deviates from the happy path",[10,618,619],{},"One of those scales your effectiveness. The other creates a thin shell of productivity around a shrinking core of understanding.",[10,621,622],{},"If that sounds harsh, good. It should.",[10,624,625],{},"Because the industry is going to reward visible output for a while before it catches up to the difference. Some people are going to look faster than they really are. Some teams are going to mistake throughput for capability. Some leaders are going to count lines, tickets, and turnaround time while the actual depth of the organization erodes underneath them.",[10,627,628],{},"Then something important will break.",[10,630,631],{},"And that is when everyone will suddenly care whether the team still knows how to think.",[35,633,635],{"id":634},"keep-the-tool-keep-the-edge","Keep the Tool, Keep the Edge",[10,637,638],{},"I am not interested in anti-AI chest beating. That is mostly insecurity dressed up as principle. The tools are useful. We should use them. They can save time, reduce drudgery, explore options, and help strong engineers move faster.",[10,640,641],{},"But they should make you sharper, not softer.",[10,643,644],{},"That means using them from a position of knowledge.\nThat means staying in contact with the system.\nThat means keeping enough hands-on reps that your judgment stays grounded in reality instead of style.",[10,646,647],{},"Use AI to accelerate what you understand.\nUse it to reduce the boring parts.\nUse it to explore alternatives faster.\nUse it to pressure-test your thinking.",[10,649,650],{},"Just do not use it as a replacement for thinking.",[10,652,653],{},"Because once you outsource your instincts, you are not really speeding yourself up anymore.",[10,655,656],{},"You are just giving away the part of the job that made you valuable in the first place.",{"title":307,"searchDepth":308,"depth":308,"links":658},[659,660,661,662,669,670],{"id":363,"depth":308,"text":364},{"id":412,"depth":308,"text":413},{"id":457,"depth":308,"text":458},{"id":497,"depth":308,"text":498,"children":663},[664,666,667,668],{"id":508,"depth":665,"text":509},3,{"id":521,"depth":665,"text":522},{"id":537,"depth":665,"text":538},{"id":553,"depth":665,"text":554},{"id":572,"depth":308,"text":573},{"id":634,"depth":308,"text":635},"2026-05-28","AI should speed up what you already know how to do, not replace the judgment, debugging instincts, and technical literacy that make you effective.",{},"/blog/dont-outsource-your-instincts",{"title":334,"description":672},"blog/dont-outsource-your-instincts",[328,329,327],"uztWufHY_3StM-KxaWmCcm-gK7H5oBKowsldb7GFcU0",{"id":680,"title":681,"body":682,"date":2050,"description":2051,"extension":318,"image":319,"meta":2052,"navigation":321,"path":2053,"readingTime":983,"seo":2054,"stem":2055,"tags":2056,"__hash__":2057},"blog/blog/explicit-over-clever.md","Explicit is the New Clever: A Manifesto for the Perpetually Exhausted",{"type":7,"value":683,"toc":2037},[684,692,698,701,705,708,739,742,841,844,861,865,876,880,891,1090,1104,1108,1111,1282,1289,1300,1310,1476,1487,1491,1498,1501,1559,1562,1630,1633,1656,1663,1667,1670,1677,1680,1684,1687,1789,1792,1806,1809,1978,1981,1998,2002,2005,2012,2015,2022,2025,2028,2033],[10,685,686,687,691],{},"Let's cut the crap. We've all been there - it's 2 AM, you're mainlining cold brew, and you write a one-liner that makes you feel like the Leonardo da Vinci of JavaScript. It's a beautiful, elegant, ",[688,689,690],"em",{},"clever"," piece of code that chains six array methods, uses a bitwise operator \"because it's faster,\" and fits in a single 120-character line.",[10,693,694,695],{},"Three months later, you stumble across that same line while debugging a production incident. You stare at it like it's ancient Sanskrit written by a drunkard. ",[688,696,697],{},"What does this do? Why does it exist? Who hurt me?",[10,699,700],{},"This, friends, is the cleverness tax. And it's time we stop paying it.",[35,702,704],{"id":703},"the-siren-song-of-clever-code","The Siren Song of Clever Code",[10,706,707],{},"Clever code is ego-driven code. It's you flexing on your future self-and trust me, future you is tired, has forgotten everything, and just wants to go home. Clever code is:",[52,709,710,716,722,728],{},[55,711,712,715],{},[343,713,714],{},"Dense",": One line doing twelve things",[55,717,718,721],{},[343,719,720],{},"Context-dependent",": Requires understanding three other files to grok",[55,723,724,727],{},[343,725,726],{},"Brittle",": Breaks in ways that make no sense",[55,729,730,733,734,738],{},[343,731,732],{},"AI-hostile",": Even Claude struggles to untangle your ",[735,736,737],"code",{},"reduce"," chain",[10,740,741],{},"Here's a real example I found in our codebase last week (names changed to protect the guilty):",[743,744,748],"pre",{"className":745,"code":746,"language":747,"meta":307,"style":307},"language-ts shiki shiki-themes github-dark","// The \"clever\" way\nconst stats = users.reduce((a, u) => ((a[u.dept] = (a[u.dept] || 0) + u.hours), a), {} as Record\u003Cstring, number>);\n","ts",[735,749,750,759],{"__ignoreMap":307},[751,752,755],"span",{"class":753,"line":754},"line",1,[751,756,758],{"class":757},"sAwPA","// The \"clever\" way\n",[751,760,761,765,769,772,776,779,782,786,789,792,795,798,801,804,807,810,813,815,818,821,824,827,830,833,835,838],{"class":753,"line":308},[751,762,764],{"class":763},"snl16","const",[751,766,768],{"class":767},"sDLfK"," stats",[751,770,771],{"class":763}," =",[751,773,775],{"class":774},"s95oV"," users.",[751,777,737],{"class":778},"svObZ",[751,780,781],{"class":774},"((",[751,783,785],{"class":784},"s9osk","a",[751,787,788],{"class":774},", ",[751,790,791],{"class":784},"u",[751,793,794],{"class":774},") ",[751,796,797],{"class":763},"=>",[751,799,800],{"class":774}," ((a[u.dept] ",[751,802,803],{"class":763},"=",[751,805,806],{"class":774}," (a[u.dept] ",[751,808,809],{"class":763},"||",[751,811,812],{"class":767}," 0",[751,814,794],{"class":774},[751,816,817],{"class":763},"+",[751,819,820],{"class":774}," u.hours), a), {} ",[751,822,823],{"class":763},"as",[751,825,826],{"class":778}," Record",[751,828,829],{"class":774},"\u003C",[751,831,832],{"class":767},"string",[751,834,788],{"class":774},[751,836,837],{"class":767},"number",[751,839,840],{"class":774},">);\n",[10,842,843],{},"Sure, it works. It's also a war crime. Let's count the sins:",[52,845,846,852,855,858],{},[55,847,848,849,851],{},"Side effects in a ",[735,850,737],{}," (unforgivable)",[55,853,854],{},"Comma operator (are we writing C now?)",[55,856,857],{},"Type assertion because TypeScript rightly hates this",[55,859,860],{},"Zero colocation of interface definitions",[35,862,864],{"id":863},"the-explicit-gospel-repeat-yourself-just-a-little","The Explicit Gospel: Repeat Yourself, Just a Little",[10,866,867,868,871,872,875],{},"Here's the thing they don't teach you in Clean Code workshops: ",[343,869,870],{},"sometimes repeating yourself is fine",". Not DRY heresy - ",[688,873,874],{},"strategic"," repetition. The kind that makes your code read like a damn children's book.",[506,877,879],{"id":878},"principle-1-colocate-your-types-like-they-owe-you-money","Principle #1: Colocate Your Types Like They Owe You Money",[10,881,882,883,886,887,890],{},"Stop putting all your interfaces in a ",[735,884,885],{},"types.ts"," file three directories away. It's 2024. We have tree-shaking. Put that interface where it's ",[688,888,889],{},"used",".",[743,892,894],{"className":745,"code":893,"language":747,"meta":307,"style":307},"// ❌ The \"organized\" way (read: annoying)\n// ~/types/user.ts\nexport interface UserStats {\n  department: string;\n  totalHours: number;\n}\n\n// ~/utils/analytics.ts\nimport { UserStats } from '~/types/user'\n\n// ✅ The explicit way\n// ~/utils/analytics.ts\ninterface DepartmentHourStats {\n  department: string;\n  totalHours: number;\n}\n\nfunction calculateDepartmentHours(users: User[]): Record\u003Cstring, DepartmentHourStats> {\n  // ...\n}\n",[735,895,896,901,906,920,935,948,954,960,966,981,986,992,997,1008,1019,1030,1035,1040,1079,1085],{"__ignoreMap":307},[751,897,898],{"class":753,"line":754},[751,899,900],{"class":757},"// ❌ The \"organized\" way (read: annoying)\n",[751,902,903],{"class":753,"line":308},[751,904,905],{"class":757},"// ~/types/user.ts\n",[751,907,908,911,914,917],{"class":753,"line":665},[751,909,910],{"class":763},"export",[751,912,913],{"class":763}," interface",[751,915,916],{"class":778}," UserStats",[751,918,919],{"class":774}," {\n",[751,921,923,926,929,932],{"class":753,"line":922},4,[751,924,925],{"class":784},"  department",[751,927,928],{"class":763},":",[751,930,931],{"class":767}," string",[751,933,934],{"class":774},";\n",[751,936,938,941,943,946],{"class":753,"line":937},5,[751,939,940],{"class":784},"  totalHours",[751,942,928],{"class":763},[751,944,945],{"class":767}," number",[751,947,934],{"class":774},[751,949,951],{"class":753,"line":950},6,[751,952,953],{"class":774},"}\n",[751,955,957],{"class":753,"line":956},7,[751,958,959],{"emptyLinePlaceholder":321},"\n",[751,961,963],{"class":753,"line":962},8,[751,964,965],{"class":757},"// ~/utils/analytics.ts\n",[751,967,968,971,974,977],{"class":753,"line":323},[751,969,970],{"class":763},"import",[751,972,973],{"class":774}," { UserStats } ",[751,975,976],{"class":763},"from",[751,978,980],{"class":979},"sU2Wk"," '~/types/user'\n",[751,982,984],{"class":753,"line":983},10,[751,985,959],{"emptyLinePlaceholder":321},[751,987,989],{"class":753,"line":988},11,[751,990,991],{"class":757},"// ✅ The explicit way\n",[751,993,995],{"class":753,"line":994},12,[751,996,965],{"class":757},[751,998,1000,1003,1006],{"class":753,"line":999},13,[751,1001,1002],{"class":763},"interface",[751,1004,1005],{"class":778}," DepartmentHourStats",[751,1007,919],{"class":774},[751,1009,1011,1013,1015,1017],{"class":753,"line":1010},14,[751,1012,925],{"class":784},[751,1014,928],{"class":763},[751,1016,931],{"class":767},[751,1018,934],{"class":774},[751,1020,1022,1024,1026,1028],{"class":753,"line":1021},15,[751,1023,940],{"class":784},[751,1025,928],{"class":763},[751,1027,945],{"class":767},[751,1029,934],{"class":774},[751,1031,1033],{"class":753,"line":1032},16,[751,1034,953],{"class":774},[751,1036,1038],{"class":753,"line":1037},17,[751,1039,959],{"emptyLinePlaceholder":321},[751,1041,1043,1046,1049,1052,1055,1057,1060,1063,1065,1067,1069,1071,1073,1076],{"class":753,"line":1042},18,[751,1044,1045],{"class":763},"function",[751,1047,1048],{"class":778}," calculateDepartmentHours",[751,1050,1051],{"class":774},"(",[751,1053,1054],{"class":784},"users",[751,1056,928],{"class":763},[751,1058,1059],{"class":778}," User",[751,1061,1062],{"class":774},"[])",[751,1064,928],{"class":763},[751,1066,826],{"class":778},[751,1068,829],{"class":774},[751,1070,832],{"class":767},[751,1072,788],{"class":774},[751,1074,1075],{"class":778},"DepartmentHourStats",[751,1077,1078],{"class":774},"> {\n",[751,1080,1082],{"class":753,"line":1081},19,[751,1083,1084],{"class":757},"  // ...\n",[751,1086,1088],{"class":753,"line":1087},20,[751,1089,953],{"class":774},[10,1091,1092,1093,1096,1097,1100,1101,890],{},"\"But now I have duplicate interfaces!\" Yeah, and? If two modules need the ",[688,1094,1095],{},"exact same shape"," but have different semantic meaning, they should ",[688,1098,1099],{},"have different interfaces",". If they truly share meaning, ",[688,1102,1103],{},"extract it when it hurts, not before",[506,1105,1107],{"id":1106},"principle-2-variables-are-free-confusion-is-expensive","Principle #2: Variables Are Free, Confusion is Expensive",[10,1109,1110],{},"Every time you inline a complex expression, a junior developer somewhere cries. Variables are zero-cost abstractions. Use them like you're trying to win a verbosity contest.",[743,1112,1114],{"className":745,"code":1113,"language":747,"meta":307,"style":307},"// ❌ Clever and compact\nconst active = users.filter(u => u.status === 'active' && u.lastLogin > Date.now() - 86400000);\n\n// ✅ Explicit and readable\nconst ONE_DAY_IN_MS = 86_400_000;\nconst yesterday = Date.now() - ONE_DAY_IN_MS;\nconst isRecentlyActive = (user: User) => user.status === 'active' && user.lastLogin > yesterday;\n\nconst recentlyActiveUsers = users.filter(isRecentlyActive);\n",[735,1115,1116,1121,1178,1182,1187,1201,1222,1262,1266],{"__ignoreMap":307},[751,1117,1118],{"class":753,"line":754},[751,1119,1120],{"class":757},"// ❌ Clever and compact\n",[751,1122,1123,1125,1128,1130,1132,1135,1137,1139,1142,1145,1148,1151,1154,1157,1160,1163,1166,1169,1172,1175],{"class":753,"line":308},[751,1124,764],{"class":763},[751,1126,1127],{"class":767}," active",[751,1129,771],{"class":763},[751,1131,775],{"class":774},[751,1133,1134],{"class":778},"filter",[751,1136,1051],{"class":774},[751,1138,791],{"class":784},[751,1140,1141],{"class":763}," =>",[751,1143,1144],{"class":774}," u.status ",[751,1146,1147],{"class":763},"===",[751,1149,1150],{"class":979}," 'active'",[751,1152,1153],{"class":763}," &&",[751,1155,1156],{"class":774}," u.lastLogin ",[751,1158,1159],{"class":763},">",[751,1161,1162],{"class":774}," Date.",[751,1164,1165],{"class":778},"now",[751,1167,1168],{"class":774},"() ",[751,1170,1171],{"class":763},"-",[751,1173,1174],{"class":767}," 86400000",[751,1176,1177],{"class":774},");\n",[751,1179,1180],{"class":753,"line":665},[751,1181,959],{"emptyLinePlaceholder":321},[751,1183,1184],{"class":753,"line":922},[751,1185,1186],{"class":757},"// ✅ Explicit and readable\n",[751,1188,1189,1191,1194,1196,1199],{"class":753,"line":937},[751,1190,764],{"class":763},[751,1192,1193],{"class":767}," ONE_DAY_IN_MS",[751,1195,771],{"class":763},[751,1197,1198],{"class":767}," 86_400_000",[751,1200,934],{"class":774},[751,1202,1203,1205,1208,1210,1212,1214,1216,1218,1220],{"class":753,"line":950},[751,1204,764],{"class":763},[751,1206,1207],{"class":767}," yesterday",[751,1209,771],{"class":763},[751,1211,1162],{"class":774},[751,1213,1165],{"class":778},[751,1215,1168],{"class":774},[751,1217,1171],{"class":763},[751,1219,1193],{"class":767},[751,1221,934],{"class":774},[751,1223,1224,1226,1229,1231,1234,1237,1239,1241,1243,1245,1248,1250,1252,1254,1257,1259],{"class":753,"line":956},[751,1225,764],{"class":763},[751,1227,1228],{"class":778}," isRecentlyActive",[751,1230,771],{"class":763},[751,1232,1233],{"class":774}," (",[751,1235,1236],{"class":784},"user",[751,1238,928],{"class":763},[751,1240,1059],{"class":778},[751,1242,794],{"class":774},[751,1244,797],{"class":763},[751,1246,1247],{"class":774}," user.status ",[751,1249,1147],{"class":763},[751,1251,1150],{"class":979},[751,1253,1153],{"class":763},[751,1255,1256],{"class":774}," user.lastLogin ",[751,1258,1159],{"class":763},[751,1260,1261],{"class":774}," yesterday;\n",[751,1263,1264],{"class":753,"line":962},[751,1265,959],{"emptyLinePlaceholder":321},[751,1267,1268,1270,1273,1275,1277,1279],{"class":753,"line":323},[751,1269,764],{"class":763},[751,1271,1272],{"class":767}," recentlyActiveUsers",[751,1274,771],{"class":763},[751,1276,775],{"class":774},[751,1278,1134],{"class":778},[751,1280,1281],{"class":774},"(isRecentlyActive);\n",[10,1283,1284,1285,1288],{},"\"But that's three lines instead of one!\" And? Your minifier will handle it. Your brain won't. The AI reading this will understand it instantly. The junior dev onboarding next week won't need to ask what ",[735,1286,1287],{},"86400000"," is.",[506,1290,1292,1293,1296,1297],{"id":1291},"principle-3-name-things-for-what-they-mean-not-what-they-do","Principle #3: Name Things for What They ",[688,1294,1295],{},"Mean",", Not What They ",[688,1298,1299],{},"Do",[10,1301,1302,1303,1306,1307,890],{},"This is the big one. That variable you create ",[688,1304,1305],{},"just"," to give a name to a value? That's not waste - that's ",[688,1308,1309],{},"documentation that compiles",[743,1311,1313],{"className":745,"code":1312,"language":747,"meta":307,"style":307},"// ❌ The inline special\nif (user.role.includes('admin') && user.permissions.includes('write') && !user.isSuspended) {\n  // ...\n}\n\n// ✅ The self-documenting way\nconst hasAdminRole = user.role.includes('admin');\nconst hasWritePermission = user.permissions.includes('write');\nconst isAccountActive = !user.isSuspended;\n\nconst canEditContent = hasAdminRole && hasWritePermission && isAccountActive;\n\nif (canEditContent) {\n  // ...\n}\n",[735,1314,1315,1320,1361,1365,1369,1373,1378,1398,1417,1431,1435,1457,1461,1468,1472],{"__ignoreMap":307},[751,1316,1317],{"class":753,"line":754},[751,1318,1319],{"class":757},"// ❌ The inline special\n",[751,1321,1322,1325,1328,1331,1333,1336,1338,1341,1344,1346,1348,1351,1353,1355,1358],{"class":753,"line":308},[751,1323,1324],{"class":763},"if",[751,1326,1327],{"class":774}," (user.role.",[751,1329,1330],{"class":778},"includes",[751,1332,1051],{"class":774},[751,1334,1335],{"class":979},"'admin'",[751,1337,794],{"class":774},[751,1339,1340],{"class":763},"&&",[751,1342,1343],{"class":774}," user.permissions.",[751,1345,1330],{"class":778},[751,1347,1051],{"class":774},[751,1349,1350],{"class":979},"'write'",[751,1352,794],{"class":774},[751,1354,1340],{"class":763},[751,1356,1357],{"class":763}," !",[751,1359,1360],{"class":774},"user.isSuspended) {\n",[751,1362,1363],{"class":753,"line":665},[751,1364,1084],{"class":757},[751,1366,1367],{"class":753,"line":922},[751,1368,953],{"class":774},[751,1370,1371],{"class":753,"line":937},[751,1372,959],{"emptyLinePlaceholder":321},[751,1374,1375],{"class":753,"line":950},[751,1376,1377],{"class":757},"// ✅ The self-documenting way\n",[751,1379,1380,1382,1385,1387,1390,1392,1394,1396],{"class":753,"line":956},[751,1381,764],{"class":763},[751,1383,1384],{"class":767}," hasAdminRole",[751,1386,771],{"class":763},[751,1388,1389],{"class":774}," user.role.",[751,1391,1330],{"class":778},[751,1393,1051],{"class":774},[751,1395,1335],{"class":979},[751,1397,1177],{"class":774},[751,1399,1400,1402,1405,1407,1409,1411,1413,1415],{"class":753,"line":962},[751,1401,764],{"class":763},[751,1403,1404],{"class":767}," hasWritePermission",[751,1406,771],{"class":763},[751,1408,1343],{"class":774},[751,1410,1330],{"class":778},[751,1412,1051],{"class":774},[751,1414,1350],{"class":979},[751,1416,1177],{"class":774},[751,1418,1419,1421,1424,1426,1428],{"class":753,"line":323},[751,1420,764],{"class":763},[751,1422,1423],{"class":767}," isAccountActive",[751,1425,771],{"class":763},[751,1427,1357],{"class":763},[751,1429,1430],{"class":774},"user.isSuspended;\n",[751,1432,1433],{"class":753,"line":983},[751,1434,959],{"emptyLinePlaceholder":321},[751,1436,1437,1439,1442,1444,1447,1449,1452,1454],{"class":753,"line":988},[751,1438,764],{"class":763},[751,1440,1441],{"class":767}," canEditContent",[751,1443,771],{"class":763},[751,1445,1446],{"class":774}," hasAdminRole ",[751,1448,1340],{"class":763},[751,1450,1451],{"class":774}," hasWritePermission ",[751,1453,1340],{"class":763},[751,1455,1456],{"class":774}," isAccountActive;\n",[751,1458,1459],{"class":753,"line":994},[751,1460,959],{"emptyLinePlaceholder":321},[751,1462,1463,1465],{"class":753,"line":999},[751,1464,1324],{"class":763},[751,1466,1467],{"class":774}," (canEditContent) {\n",[751,1469,1470],{"class":753,"line":1010},[751,1471,1084],{"class":757},[751,1473,1474],{"class":753,"line":1021},[751,1475,953],{"class":774},[10,1477,1478,1479,1482,1483,1486],{},"Yes, it's more lines. Yes, it feels \"wrong\" at first-like you're being paid by the keystroke. But that ",[735,1480,1481],{},"canEditContent"," variable? That's a ",[343,1484,1485],{},"domain concept",". It's now testable, debuggable, and shows up in your AI's context window with a clear name.",[35,1488,1490],{"id":1489},"the-ai-angle-explicit-code-is-prompt-engineering-for-machines","The AI Angle: Explicit Code is Prompt Engineering for Machines",[10,1492,1493,1494,1497],{},"Here's a spicy take: ",[343,1495,1496],{},"AI pair programming has made clever code even more dangerous",". When you write dense, clever nonsense, you're not just confusing future humans-you're confusing your AI assistant.",[10,1499,1500],{},"Modern AI tools (yes, even the fancy ones) parse code the same way humans do: by building a mental model. When you write:",[743,1502,1504],{"className":745,"code":1503,"language":747,"meta":307,"style":307},"const result = data.flatMap(x => x.items).reduce((a, b) => a + b.price, 0);\n",[735,1505,1506],{"__ignoreMap":307},[751,1507,1508,1510,1513,1515,1518,1521,1523,1526,1528,1531,1533,1535,1537,1539,1542,1544,1546,1549,1551,1554,1557],{"class":753,"line":754},[751,1509,764],{"class":763},[751,1511,1512],{"class":767}," result",[751,1514,771],{"class":763},[751,1516,1517],{"class":774}," data.",[751,1519,1520],{"class":778},"flatMap",[751,1522,1051],{"class":774},[751,1524,1525],{"class":784},"x",[751,1527,1141],{"class":763},[751,1529,1530],{"class":774}," x.items).",[751,1532,737],{"class":778},[751,1534,781],{"class":774},[751,1536,785],{"class":784},[751,1538,788],{"class":774},[751,1540,1541],{"class":784},"b",[751,1543,794],{"class":774},[751,1545,797],{"class":763},[751,1547,1548],{"class":774}," a ",[751,1550,817],{"class":763},[751,1552,1553],{"class":774}," b.price, ",[751,1555,1556],{"class":767},"0",[751,1558,1177],{"class":774},[10,1560,1561],{},"The AI has to reverse-engineer your intent. But when you write:",[743,1563,1565],{"className":745,"code":1564,"language":747,"meta":307,"style":307},"const allItems = data.flatMap(invoice => invoice.items);\nconst totalPrice = allItems.reduce((sum, item) => sum + item.price, 0);\n",[735,1566,1567,1590],{"__ignoreMap":307},[751,1568,1569,1571,1574,1576,1578,1580,1582,1585,1587],{"class":753,"line":754},[751,1570,764],{"class":763},[751,1572,1573],{"class":767}," allItems",[751,1575,771],{"class":763},[751,1577,1517],{"class":774},[751,1579,1520],{"class":778},[751,1581,1051],{"class":774},[751,1583,1584],{"class":784},"invoice",[751,1586,1141],{"class":763},[751,1588,1589],{"class":774}," invoice.items);\n",[751,1591,1592,1594,1597,1599,1602,1604,1606,1609,1611,1614,1616,1618,1621,1623,1626,1628],{"class":753,"line":308},[751,1593,764],{"class":763},[751,1595,1596],{"class":767}," totalPrice",[751,1598,771],{"class":763},[751,1600,1601],{"class":774}," allItems.",[751,1603,737],{"class":778},[751,1605,781],{"class":774},[751,1607,1608],{"class":784},"sum",[751,1610,788],{"class":774},[751,1612,1613],{"class":784},"item",[751,1615,794],{"class":774},[751,1617,797],{"class":763},[751,1619,1620],{"class":774}," sum ",[751,1622,817],{"class":763},[751,1624,1625],{"class":774}," item.price, ",[751,1627,1556],{"class":767},[751,1629,1177],{"class":774},[10,1631,1632],{},"The AI instantly understands:",[52,1634,1635,1641,1647,1650,1653],{},[55,1636,1637,1640],{},[735,1638,1639],{},"allItems"," is a flat array of items",[55,1642,1643,1646],{},[735,1644,1645],{},"totalPrice"," is a sum of prices",[55,1648,1649],{},"It can suggest better variable names",[55,1651,1652],{},"It can spot type mismatches",[55,1654,1655],{},"It can write tests that actually make sense",[10,1657,1658,1659,1662],{},"Explicit code is ",[343,1660,1661],{},"prompt engineering for your AI",". You're giving it the context it needs to be useful instead of just generating more clever garbage.",[35,1664,1666],{"id":1665},"the-psychological-hurdle-why-this-feels-like-losing","The Psychological Hurdle: Why This Feels Like Losing",[10,1668,1669],{},"I get it. After 20+ years of \"DRY\" being beaten into your skull, writing \"redundant\" code feels like failure. It feels like you're not \"smart enough\" to abstract it.",[10,1671,1672,1673,1676],{},"But here's the truth: ",[343,1674,1675],{},"Abstraction is a liability until proven otherwise",". Every abstraction adds indirection. Every indirection adds cognitive load. The best code is code that doesn't make you think.",[10,1678,1679],{},"That feeling of \"this is too verbose\"? That's your ego talking. Tell it to shut up and let your future self have a good night's sleep.",[35,1681,1683],{"id":1682},"a-real-world-nuxt-3-example","A Real-World Nuxt 3 Example",[10,1685,1686],{},"Let's bring this home with something from our actual stack. Here's a pattern I see constantly:",[743,1688,1690],{"className":745,"code":1689,"language":747,"meta":307,"style":307},"// ❌ The \"efficient\" way\nconst { data: projects } = await useAsyncData('projects', () => \n  $fetch(`/api/projects?status=${route.query.status || 'active'}&branch=${userStore.currentBranch.id}`)\n);\n",[735,1691,1692,1697,1737,1785],{"__ignoreMap":307},[751,1693,1694],{"class":753,"line":754},[751,1695,1696],{"class":757},"// ❌ The \"efficient\" way\n",[751,1698,1699,1701,1704,1707,1710,1713,1716,1718,1721,1724,1726,1729,1732,1734],{"class":753,"line":308},[751,1700,764],{"class":763},[751,1702,1703],{"class":774}," { ",[751,1705,1706],{"class":784},"data",[751,1708,1709],{"class":774},": ",[751,1711,1712],{"class":767},"projects",[751,1714,1715],{"class":774}," } ",[751,1717,803],{"class":763},[751,1719,1720],{"class":763}," await",[751,1722,1723],{"class":778}," useAsyncData",[751,1725,1051],{"class":774},[751,1727,1728],{"class":979},"'projects'",[751,1730,1731],{"class":774},", () ",[751,1733,797],{"class":763},[751,1735,1736],{"class":774}," \n",[751,1738,1739,1742,1744,1747,1750,1752,1755,1757,1760,1763,1766,1769,1771,1774,1776,1779,1782],{"class":753,"line":665},[751,1740,1741],{"class":778},"  $fetch",[751,1743,1051],{"class":774},[751,1745,1746],{"class":979},"`/api/projects?status=${",[751,1748,1749],{"class":774},"route",[751,1751,890],{"class":979},[751,1753,1754],{"class":774},"query",[751,1756,890],{"class":979},[751,1758,1759],{"class":774},"status",[751,1761,1762],{"class":763}," ||",[751,1764,1765],{"class":979}," 'active'}&branch=${",[751,1767,1768],{"class":774},"userStore",[751,1770,890],{"class":979},[751,1772,1773],{"class":774},"currentBranch",[751,1775,890],{"class":979},[751,1777,1778],{"class":774},"id",[751,1780,1781],{"class":979},"}`",[751,1783,1784],{"class":774},")\n",[751,1786,1787],{"class":753,"line":922},[751,1788,1177],{"class":774},[10,1790,1791],{},"Looks fine, right? Now try debugging why projects aren't loading when the query param is wrong. You need to know:",[52,1793,1794,1797,1800],{},[55,1795,1796],{},"The API endpoint structure",[55,1798,1799],{},"The default status logic",[55,1801,1802,1803,1805],{},"Where ",[735,1804,1773],{}," comes from",[10,1807,1808],{},"Now watch:",[743,1810,1812],{"className":745,"code":1811,"language":747,"meta":307,"style":307},"// ✅ The explicit way\nconst DEFAULT_PROJECT_STATUS = 'active';\nconst selectedStatus = route.query.status || DEFAULT_PROJECT_STATUS;\nconst currentBranchId = userStore.currentBranch.id;\n\nconst apiEndpoint = `/api/projects`;\nconst queryParams = new URLSearchParams({\n  status: selectedStatus,\n  branch: String(currentBranchId),\n});\n\nconst { data: projects } = await useAsyncData('projects', () => \n  $fetch(`${apiEndpoint}?${queryParams}`)\n);\n",[735,1813,1814,1818,1831,1849,1861,1865,1879,1897,1902,1913,1918,1922,1952,1974],{"__ignoreMap":307},[751,1815,1816],{"class":753,"line":754},[751,1817,991],{"class":757},[751,1819,1820,1822,1825,1827,1829],{"class":753,"line":308},[751,1821,764],{"class":763},[751,1823,1824],{"class":767}," DEFAULT_PROJECT_STATUS",[751,1826,771],{"class":763},[751,1828,1150],{"class":979},[751,1830,934],{"class":774},[751,1832,1833,1835,1838,1840,1843,1845,1847],{"class":753,"line":665},[751,1834,764],{"class":763},[751,1836,1837],{"class":767}," selectedStatus",[751,1839,771],{"class":763},[751,1841,1842],{"class":774}," route.query.status ",[751,1844,809],{"class":763},[751,1846,1824],{"class":767},[751,1848,934],{"class":774},[751,1850,1851,1853,1856,1858],{"class":753,"line":922},[751,1852,764],{"class":763},[751,1854,1855],{"class":767}," currentBranchId",[751,1857,771],{"class":763},[751,1859,1860],{"class":774}," userStore.currentBranch.id;\n",[751,1862,1863],{"class":753,"line":937},[751,1864,959],{"emptyLinePlaceholder":321},[751,1866,1867,1869,1872,1874,1877],{"class":753,"line":950},[751,1868,764],{"class":763},[751,1870,1871],{"class":767}," apiEndpoint",[751,1873,771],{"class":763},[751,1875,1876],{"class":979}," `/api/projects`",[751,1878,934],{"class":774},[751,1880,1881,1883,1886,1888,1891,1894],{"class":753,"line":956},[751,1882,764],{"class":763},[751,1884,1885],{"class":767}," queryParams",[751,1887,771],{"class":763},[751,1889,1890],{"class":763}," new",[751,1892,1893],{"class":778}," URLSearchParams",[751,1895,1896],{"class":774},"({\n",[751,1898,1899],{"class":753,"line":962},[751,1900,1901],{"class":774},"  status: selectedStatus,\n",[751,1903,1904,1907,1910],{"class":753,"line":323},[751,1905,1906],{"class":774},"  branch: ",[751,1908,1909],{"class":778},"String",[751,1911,1912],{"class":774},"(currentBranchId),\n",[751,1914,1915],{"class":753,"line":983},[751,1916,1917],{"class":774},"});\n",[751,1919,1920],{"class":753,"line":988},[751,1921,959],{"emptyLinePlaceholder":321},[751,1923,1924,1926,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946,1948,1950],{"class":753,"line":994},[751,1925,764],{"class":763},[751,1927,1703],{"class":774},[751,1929,1706],{"class":784},[751,1931,1709],{"class":774},[751,1933,1712],{"class":767},[751,1935,1715],{"class":774},[751,1937,803],{"class":763},[751,1939,1720],{"class":763},[751,1941,1723],{"class":778},[751,1943,1051],{"class":774},[751,1945,1728],{"class":979},[751,1947,1731],{"class":774},[751,1949,797],{"class":763},[751,1951,1736],{"class":774},[751,1953,1954,1956,1958,1961,1964,1967,1970,1972],{"class":753,"line":999},[751,1955,1741],{"class":778},[751,1957,1051],{"class":774},[751,1959,1960],{"class":979},"`${",[751,1962,1963],{"class":774},"apiEndpoint",[751,1965,1966],{"class":979},"}?${",[751,1968,1969],{"class":774},"queryParams",[751,1971,1781],{"class":979},[751,1973,1784],{"class":774},[751,1975,1976],{"class":753,"line":1010},[751,1977,1177],{"class":774},[10,1979,1980],{},"More code? Absolutely. But now you can:",[52,1982,1983,1986,1989,1992,1995],{},[55,1984,1985],{},"Console.log any step",[55,1987,1988],{},"Set breakpoints that make sense",[55,1990,1991],{},"Understand the API contract at a glance",[55,1993,1994],{},"Let your AI refactor individual pieces safely",[55,1996,1997],{},"Hand this to a junior dev without explanation",[35,1999,2001],{"id":2000},"the-verdict-be-kind-to-your-future-self-and-your-ai","The Verdict: Be Kind to Your Future Self (and Your AI)",[10,2003,2004],{},"Clever code is a party trick. Explicit code is a professional courtesy.",[10,2006,2007,2008,2011],{},"Next time you're tempted to chain five methods into a single expression, remember: ",[343,2009,2010],{},"you're not writing code for the compiler. You're writing it for a tired, distracted, possibly hungover version of yourself","-or an AI with a context window limit.",[10,2013,2014],{},"The compiler doesn't care about your variable names. The interpreter doesn't care about your extra lines. But the human (and the AI) reading it? They care a lot.",[10,2016,2017,2018,2021],{},"So be explicit. Be verbose. Be boring. Future you will thank you. Current you will spend less time in ",[735,2019,2020],{},"git blame"," wondering who the asshole was that wrote that garbage.",[10,2023,2024],{},"Spoiler: it was you. It was always you.",[2026,2027],"hr",{},[10,2029,2030],{},[688,2031,2032],{},"Now go forth and write code that reads like a damn children's book. Your team, your AI, and your 2 AM debugging self will thank you.",[2034,2035,2036],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#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 pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}",{"title":307,"searchDepth":308,"depth":308,"links":2038},[2039,2040,2046,2047,2048,2049],{"id":703,"depth":308,"text":704},{"id":863,"depth":308,"text":864,"children":2041},[2042,2043,2044],{"id":878,"depth":665,"text":879},{"id":1106,"depth":665,"text":1107},{"id":1291,"depth":665,"text":2045},"Principle #3: Name Things for What They Mean, Not What They Do",{"id":1489,"depth":308,"text":1490},{"id":1665,"depth":308,"text":1666},{"id":1682,"depth":308,"text":1683},{"id":2000,"depth":308,"text":2001},"2026-01-08","Why verbose, self-documenting code beats cleverness - and makes AI actually understand your intent.",{},"/blog/explicit-over-clever",{"title":681,"description":2051},"blog/explicit-over-clever",[327,329],"uHRtEDK-NLP5o7ylAl5RKU3wz3iwVktHUfv8lHv4n9I",{"id":2059,"title":2060,"body":2061,"date":2655,"description":2656,"extension":318,"image":319,"meta":2657,"navigation":321,"path":2658,"readingTime":962,"seo":2659,"stem":2660,"tags":2661,"__hash__":2663},"blog/blog/building-enterprise-software-lessons.md","5 Years Building Enterprise Software: Lessons Learned",{"type":7,"value":2062,"toc":2643},[2063,2066,2070,2073,2076,2090,2301,2305,2308,2311,2337,2340,2360,2363,2367,2370,2374,2377,2490,2494,2497,2508,2512,2515,2535,2539,2542,2545,2571,2574,2578,2581,2584,2610,2613,2617,2620,2623,2637,2640],[10,2064,2065],{},"After nearly five years of building Evergreen - a comprehensive enterprise platform that handles CRM, business intelligence, call center operations, and client portals-I've accumulated a wealth of lessons that I wish I'd known from day one.",[35,2067,2069],{"id":2068},"_1-start-with-the-data-model","1. Start with the Data Model",[10,2071,2072],{},"The single most important decision you'll make is your data model. Everything else - UI, features, integrations-can be changed relatively easily. Your core data model cannot.",[10,2074,2075],{},"Spend the time upfront to really understand:",[52,2077,2078,2081,2084,2087],{},[55,2079,2080],{},"What are the core entities in your domain?",[55,2082,2083],{},"How do they relate to each other?",[55,2085,2086],{},"What data will you need for reporting?",[55,2088,2089],{},"How might requirements evolve?",[743,2091,2095],{"className":2092,"code":2093,"language":2094,"meta":307,"style":307},"language-typescript shiki shiki-themes github-dark","// Early mistake: Tightly coupled address to customer\ninterface Customer {\n  name: string\n  address: string  // 🚫 What about multiple addresses?\n  city: string\n  state: string\n}\n\n// Better: Flexible, normalized structure\ninterface Customer {\n  id: string\n  name: string\n  addresses: Address[]  // ✅ Supports multiple, typed addresses\n  primaryAddressId: string\n}\n\ninterface Address {\n  id: string\n  type: 'billing' | 'service' | 'mailing'\n  street: string\n  city: string\n  state: string\n  zip: string\n}\n","typescript",[735,2096,2097,2102,2111,2121,2133,2142,2151,2155,2159,2164,2172,2181,2189,2205,2214,2218,2222,2230,2238,2259,2268,2277,2286,2296],{"__ignoreMap":307},[751,2098,2099],{"class":753,"line":754},[751,2100,2101],{"class":757},"// Early mistake: Tightly coupled address to customer\n",[751,2103,2104,2106,2109],{"class":753,"line":308},[751,2105,1002],{"class":763},[751,2107,2108],{"class":778}," Customer",[751,2110,919],{"class":774},[751,2112,2113,2116,2118],{"class":753,"line":665},[751,2114,2115],{"class":784},"  name",[751,2117,928],{"class":763},[751,2119,2120],{"class":767}," string\n",[751,2122,2123,2126,2128,2130],{"class":753,"line":922},[751,2124,2125],{"class":784},"  address",[751,2127,928],{"class":763},[751,2129,931],{"class":767},[751,2131,2132],{"class":757},"  // 🚫 What about multiple addresses?\n",[751,2134,2135,2138,2140],{"class":753,"line":937},[751,2136,2137],{"class":784},"  city",[751,2139,928],{"class":763},[751,2141,2120],{"class":767},[751,2143,2144,2147,2149],{"class":753,"line":950},[751,2145,2146],{"class":784},"  state",[751,2148,928],{"class":763},[751,2150,2120],{"class":767},[751,2152,2153],{"class":753,"line":956},[751,2154,953],{"class":774},[751,2156,2157],{"class":753,"line":962},[751,2158,959],{"emptyLinePlaceholder":321},[751,2160,2161],{"class":753,"line":323},[751,2162,2163],{"class":757},"// Better: Flexible, normalized structure\n",[751,2165,2166,2168,2170],{"class":753,"line":983},[751,2167,1002],{"class":763},[751,2169,2108],{"class":778},[751,2171,919],{"class":774},[751,2173,2174,2177,2179],{"class":753,"line":988},[751,2175,2176],{"class":784},"  id",[751,2178,928],{"class":763},[751,2180,2120],{"class":767},[751,2182,2183,2185,2187],{"class":753,"line":994},[751,2184,2115],{"class":784},[751,2186,928],{"class":763},[751,2188,2120],{"class":767},[751,2190,2191,2194,2196,2199,2202],{"class":753,"line":999},[751,2192,2193],{"class":784},"  addresses",[751,2195,928],{"class":763},[751,2197,2198],{"class":778}," Address",[751,2200,2201],{"class":774},"[]  ",[751,2203,2204],{"class":757},"// ✅ Supports multiple, typed addresses\n",[751,2206,2207,2210,2212],{"class":753,"line":1010},[751,2208,2209],{"class":784},"  primaryAddressId",[751,2211,928],{"class":763},[751,2213,2120],{"class":767},[751,2215,2216],{"class":753,"line":1021},[751,2217,953],{"class":774},[751,2219,2220],{"class":753,"line":1032},[751,2221,959],{"emptyLinePlaceholder":321},[751,2223,2224,2226,2228],{"class":753,"line":1037},[751,2225,1002],{"class":763},[751,2227,2198],{"class":778},[751,2229,919],{"class":774},[751,2231,2232,2234,2236],{"class":753,"line":1042},[751,2233,2176],{"class":784},[751,2235,928],{"class":763},[751,2237,2120],{"class":767},[751,2239,2240,2243,2245,2248,2251,2254,2256],{"class":753,"line":1081},[751,2241,2242],{"class":784},"  type",[751,2244,928],{"class":763},[751,2246,2247],{"class":979}," 'billing'",[751,2249,2250],{"class":763}," |",[751,2252,2253],{"class":979}," 'service'",[751,2255,2250],{"class":763},[751,2257,2258],{"class":979}," 'mailing'\n",[751,2260,2261,2264,2266],{"class":753,"line":1087},[751,2262,2263],{"class":784},"  street",[751,2265,928],{"class":763},[751,2267,2120],{"class":767},[751,2269,2271,2273,2275],{"class":753,"line":2270},21,[751,2272,2137],{"class":784},[751,2274,928],{"class":763},[751,2276,2120],{"class":767},[751,2278,2280,2282,2284],{"class":753,"line":2279},22,[751,2281,2146],{"class":784},[751,2283,928],{"class":763},[751,2285,2120],{"class":767},[751,2287,2289,2292,2294],{"class":753,"line":2288},23,[751,2290,2291],{"class":784},"  zip",[751,2293,928],{"class":763},[751,2295,2120],{"class":767},[751,2297,2299],{"class":753,"line":2298},24,[751,2300,953],{"class":774},[35,2302,2304],{"id":2303},"_2-boring-foundation-strategic-innovation","2. Boring Foundation, Strategic Innovation",[10,2306,2307],{},"When I started Evergreen, I was tempted to use cutting-edge patterns everywhere. The key lesson: keep your foundation boring, but don't be afraid to use advanced patterns where they genuinely solve problems.",[10,2309,2310],{},"Our core stack is deliberately boring:",[52,2312,2313,2319,2325,2331],{},[55,2314,2315,2318],{},[343,2316,2317],{},"PostgreSQL"," for everything database-related (with read replicas for BI)",[55,2320,2321,2324],{},[343,2322,2323],{},"Redis"," for caching and real-time features",[55,2326,2327,2330],{},[343,2328,2329],{},"Vue.js/Nuxt"," for the frontend",[55,2332,2333,2336],{},[343,2334,2335],{},"Nest.js"," for the backend",[10,2338,2339],{},"But we strategically adopted advanced patterns where they made sense:",[52,2341,2342,2348,2354],{},[55,2343,2344,2347],{},[343,2345,2346],{},"Event Sourcing"," for audit trails and complex workflows where we need complete history",[55,2349,2350,2353],{},[343,2351,2352],{},"Microservices"," for specific high-scale features that benefit from isolation",[55,2355,2356,2359],{},[343,2357,2358],{},"Queue-based Processing"," with BullMQ for background jobs and async operations",[10,2361,2362],{},"The lesson: Choose boring technology for your foundation, but don't dogmatically avoid modern patterns when they solve real problems. The key is being intentional about when to use what.",[35,2364,2366],{"id":2365},"_3-invest-in-developer-experience","3. Invest in Developer Experience",[10,2368,2369],{},"Every hour spent improving developer experience pays dividends for years. Some investments that have paid off massively:",[506,2371,2373],{"id":2372},"type-safety-everywhere","Type Safety Everywhere",[10,2375,2376],{},"TypeScript on both frontend and backend with shared types:",[743,2378,2380],{"className":2092,"code":2379,"language":2094,"meta":307,"style":307},"// shared/types/lead.ts\nexport interface Lead {\n  id: string\n  firstName: string\n  lastName: string\n  email: string\n  phone: string\n  source: LeadSource\n  score: number\n  createdAt: Date\n}\n\n// Used in both frontend and backend\n// Compile-time errors when contract changes\n",[735,2381,2382,2387,2398,2406,2415,2424,2433,2442,2452,2462,2472,2476,2480,2485],{"__ignoreMap":307},[751,2383,2384],{"class":753,"line":754},[751,2385,2386],{"class":757},"// shared/types/lead.ts\n",[751,2388,2389,2391,2393,2396],{"class":753,"line":308},[751,2390,910],{"class":763},[751,2392,913],{"class":763},[751,2394,2395],{"class":778}," Lead",[751,2397,919],{"class":774},[751,2399,2400,2402,2404],{"class":753,"line":665},[751,2401,2176],{"class":784},[751,2403,928],{"class":763},[751,2405,2120],{"class":767},[751,2407,2408,2411,2413],{"class":753,"line":922},[751,2409,2410],{"class":784},"  firstName",[751,2412,928],{"class":763},[751,2414,2120],{"class":767},[751,2416,2417,2420,2422],{"class":753,"line":937},[751,2418,2419],{"class":784},"  lastName",[751,2421,928],{"class":763},[751,2423,2120],{"class":767},[751,2425,2426,2429,2431],{"class":753,"line":950},[751,2427,2428],{"class":784},"  email",[751,2430,928],{"class":763},[751,2432,2120],{"class":767},[751,2434,2435,2438,2440],{"class":753,"line":956},[751,2436,2437],{"class":784},"  phone",[751,2439,928],{"class":763},[751,2441,2120],{"class":767},[751,2443,2444,2447,2449],{"class":753,"line":962},[751,2445,2446],{"class":784},"  source",[751,2448,928],{"class":763},[751,2450,2451],{"class":778}," LeadSource\n",[751,2453,2454,2457,2459],{"class":753,"line":323},[751,2455,2456],{"class":784},"  score",[751,2458,928],{"class":763},[751,2460,2461],{"class":767}," number\n",[751,2463,2464,2467,2469],{"class":753,"line":983},[751,2465,2466],{"class":784},"  createdAt",[751,2468,928],{"class":763},[751,2470,2471],{"class":778}," Date\n",[751,2473,2474],{"class":753,"line":988},[751,2475,953],{"class":774},[751,2477,2478],{"class":753,"line":994},[751,2479,959],{"emptyLinePlaceholder":321},[751,2481,2482],{"class":753,"line":999},[751,2483,2484],{"class":757},"// Used in both frontend and backend\n",[751,2486,2487],{"class":753,"line":1010},[751,2488,2489],{"class":757},"// Compile-time errors when contract changes\n",[506,2491,2493],{"id":2492},"automated-testing","Automated Testing",[10,2495,2496],{},"Not 100% coverage - that's diminishing returns. But comprehensive tests for:",[52,2498,2499,2502,2505],{},[55,2500,2501],{},"Critical business logic",[55,2503,2504],{},"API contracts",[55,2506,2507],{},"Complex UI interactions",[506,2509,2511],{"id":2510},"local-development","Local Development",[10,2513,2514],{},"One command to spin up the entire stack locally:",[743,2516,2520],{"className":2517,"code":2518,"language":2519,"meta":307,"style":307},"language-bash shiki shiki-themes github-dark","docker-compose up\n# Database, Redis, API, and frontend all running\n","bash",[735,2521,2522,2530],{"__ignoreMap":307},[751,2523,2524,2527],{"class":753,"line":754},[751,2525,2526],{"class":778},"docker-compose",[751,2528,2529],{"class":979}," up\n",[751,2531,2532],{"class":753,"line":308},[751,2533,2534],{"class":757},"# Database, Redis, API, and frontend all running\n",[35,2536,2538],{"id":2537},"_4-features-are-forever","4. Features Are Forever",[10,2540,2541],{},"Every feature you add becomes a feature you maintain. Forever.",[10,2543,2544],{},"Before adding anything, I now ask:",[52,2546,2547,2553,2559,2565],{},[55,2548,2549,2552],{},[343,2550,2551],{},"Who specifically needs this?"," \"Everyone\" is not an answer.",[55,2554,2555,2558],{},[343,2556,2557],{},"What problem does it solve?"," If you can't articulate it, don't build it.",[55,2560,2561,2564],{},[343,2562,2563],{},"What's the maintenance burden?"," Features have ongoing costs.",[55,2566,2567,2570],{},[343,2568,2569],{},"Can we solve this with existing features?"," Often yes.",[10,2572,2573],{},"The best code is code you don't write. The best feature is one you don't build.",[35,2575,2577],{"id":2576},"_5-communication-code","5. Communication > Code",[10,2579,2580],{},"As the team grew, I realized that communication became more important than any technical decision.",[10,2582,2583],{},"What helps:",[52,2585,2586,2592,2598,2604],{},[55,2587,2588,2591],{},[343,2589,2590],{},"Architecture Decision Records (ADRs)",": Document why you made choices, not just what you built",[55,2593,2594,2597],{},[343,2595,2596],{},"Runbooks",": Step-by-step guides for common operations",[55,2599,2600,2603],{},[343,2601,2602],{},"Incident postmortems",": Learn from failures without blame",[55,2605,2606,2609],{},[343,2607,2608],{},"Regular demos",": Show don't tell",[10,2611,2612],{},"Good documentation is a feature. It reduces bus factor, speeds up onboarding, and prevents repeated mistakes.",[35,2614,2616],{"id":2615},"looking-ahead","Looking Ahead",[10,2618,2619],{},"Five years in, Evergreen is more successful than I ever imagined. It's grown from a simple CRM to the nervous system of the entire business.",[10,2621,2622],{},"The next five years will bring new challenges-AI integration, mobile expansion, and scaling the team. But the foundational lessons remain the same:",[52,2624,2625,2628,2631,2634],{},[55,2626,2627],{},"Invest in foundations",[55,2629,2630],{},"Choose simplicity over cleverness",[55,2632,2633],{},"Communicate relentlessly",[55,2635,2636],{},"Build for maintainability",[10,2638,2639],{},"The best enterprise software isn't the most technically impressive; it's the software that reliably solves real problems, year after year.",[2034,2641,2642],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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);}",{"title":307,"searchDepth":308,"depth":308,"links":2644},[2645,2646,2647,2652,2653,2654],{"id":2068,"depth":308,"text":2069},{"id":2303,"depth":308,"text":2304},{"id":2365,"depth":308,"text":2366,"children":2648},[2649,2650,2651],{"id":2372,"depth":665,"text":2373},{"id":2492,"depth":665,"text":2493},{"id":2510,"depth":665,"text":2511},{"id":2537,"depth":308,"text":2538},{"id":2576,"depth":308,"text":2577},{"id":2615,"depth":308,"text":2616},"2025-06-15","Reflections on building and maintaining a large-scale business platform, from architecture decisions to team management.",{},"/blog/building-enterprise-software-lessons",{"title":2060,"description":2656},"blog/building-enterprise-software-lessons",[327,2662,328],"Enterprise","mXbZ1YoBLJt-6uMqAVcS_kqtoOLbAT1dKQqTF0JB2wg",1772860109114]