[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f2nx3dplyjbr5d":3},{"_id":4,"slug":5,"title":6,"subtitle":7,"kind":8,"cards":9,"tags":57,"categories":59,"source":61,"lang":64,"author":65,"audioState":68,"stats":69,"publishedAt":72,"renderer":73},"6aba587eca21c797c7e98625","lean-software-development-in-practice-finding-muda-in-four-p-1b952ef5","Lean Software Development in Practice: Finding Muda in Four PHP Projects","Lean has one word that I like because it is brutally simple: Muda.","news",[10,12,17,22,27,32,37,42,47,52],{"headline":6,"body":7,"imageUrl":11,"sourceImageUrl":11},"https:\u002F\u002Fmedia2.dev.to\u002Fdynamic\u002Fimage\u002Fwidth=1200,height=627,fit=cover,gravity=auto,format=auto\u002Fhttps%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzwwe8zj5lgex7ymcu7q6.png",{"headline":13,"body":14,"imageUrl":15,"images":16},"In a factory, waste is often visible. Extra","In a factory, waste is often visible. Extra movement. Waiting. Too much inventory. Producing something before it is needed. In software, it is much better at hiding.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F1.webp",{"local":15},{"headline":18,"body":19,"imageUrl":20,"images":21},"An unused abstraction does not block a corridor","An unused abstraction does not block a corridor. A feature nobody asked for does not sit on a pallet. A public API that became too large does not look like inventory. But all of them still cost something.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F2.webp",{"local":20},{"headline":23,"body":24,"imageUrl":25,"images":26},"They have to be designed, written, tested, documented","They have to be designed, written, tested, documented and maintained. And once other developers start depending on them, removing them becomes much harder than adding them. That made me look at four of my own open-source PHP projects from a slightly different angle. Three are Symfony bundles: The fourth is a standalone CLI tool: I have already written separate technical articles about all four projects: This time, I do not want to explain again how the packages work. The more interesting question is: What did I deliberately choose not to build? What did I deliberately choose not to build? That is where the Lean part becomes interesting. Muda is not the same as \"more code\" This was the first thing I had to be careful about. Lean software development does not mean deleting code until everything is small. Sometimes more code is exactly what prevents a real failure.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F3.webp",{"local":25},{"headline":28,"body":29,"imageUrl":30,"images":31},"For example, in HttpIdempotencyBundle the idempotency record is","For example, in HttpIdempotencyBundle the idempotency record is read again after acquiring the lock.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F4.webp",{"local":30},{"headline":33,"body":34,"imageUrl":35,"images":36},"Another request may have completed the operation between","Another request may have completed the operation between the first read and the moment the lock was acquired. Skipping the second read would make the code shorter, but also wrong. The same happens in OptimisticConcurrencyBundle. The HTTP layer checks If-Match, but Doctrine still performs its own optimistic-lock check during flush(). Two different race windows. How can this be done with fewer lines? How can this be done with fewer lines? Does this complexity protect something real, or does it exist only because it might be useful one day? Does this complexity protect something real, or does it exist only because it might be useful one day? OptimisticConcurrencyBundle: do not build concurrency twice The bundle solves a specific problem: preventing stale clients from silently overwriting newer data.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F5.webp",{"local":35},{"headline":38,"body":39,"imageUrl":40,"images":41},"A resource can expose an ETag: and a","A resource can expose an ETag: and a write can require the client to send the same representation version back: There is an obvious temptation here. Once you start solving concurrency, it is easy to keep going. The bundle could maintain its own entity versions. It could introduce its own locking mechanism. It could control transactions. It could become \"the concurrency layer\". But Doctrine already has optimistic locking through #[ORM\\Version]. So the bundle does not replace it. Is the representation used by this client stale? Is the representation used by this client stale? Did the entity change before the database write completed? Did the entity change before the database write completed?","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F6.webp",{"local":40},{"headline":43,"body":44,"imageUrl":45,"images":46},"Building a second persistence-level concurrency system would not","Building a second persistence-level concurrency system would not remove the need for Doctrine's protection. It would mostly add another implementation to understand and another set of failure cases to maintain. That is a form of Muda I see quite often in software: rebuilding something that another layer already does well. There is another small detail in this project that I now appreciate more. The supported public API is intentionally small. Most implementation classes are internal, and there is an architecture test that protects that boundary. Because every public class is a promise. If someone starts depending on it, changing it later becomes a backward-compatibility problem.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F7.webp",{"local":45},{"headline":48,"body":49,"imageUrl":50,"images":51},"A large public API can easily become a","A large public API can easily become a kind of inventory: things you now have to keep carrying even when you no longer want them. Sometimes the Lean choice is not removing code. Sometimes it is simply not exposing it. MaskedBundle: do not try to detect every secret in the universe MaskedBundle started from a practical problem. Sensitive data can end up in logs. Once you start thinking about automatic detection, the feature list grows very quickly. It is very easy to imagine a \"smart\" detector for all of them. It is also very easy to create a large pile of heuristics. The bundle takes a narrower approach.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F8.webp",{"local":50},{"headline":53,"body":54,"imageUrl":55,"images":56},"Automatic detection is conservative and currently focuses on","Automatic detection is conservative and currently focuses on payment-card candidates where there is enough structure to make a reasonably confident decision. When the application already knows a value is sensitive, it can pass it explicitly: That design looks simple, but the reason behind it matters.","\u002Fapi\u002Fmedia\u002Fposts\u002Flean-software-development-in-practice-finding-muda-in-four-p-1b952ef5\u002F9.webp",{"local":55},[58],"dev",[60],"Technology",{"name":62,"url":63},"Dev.to","https:\u002F\u002Fdev.to\u002Falkin\u002Flean-software-development-in-practice-finding-muda-in-four-php-projects-3m7c","en",{"handle":66,"displayName":67},"spots","Spots","queued",{"views":70,"likes":71,"saves":71,"shares":71,"completions":71,"opens":71,"skips":71,"depthSum":71},5,0,"2026-09-28T12:07:26.899Z","local"]