{"slug": "dev-log-deleting-code-and-breaking-the-build-on-purpose", "title": "Dev Log: deleting code and breaking the build on purpose", "summary": "A developer building Munchausen v1.0, a mock-data generator for .NET, started by deleting the existing prototype and deliberately breaking the build to test new guardrails. The project uses PublicApiAnalyzers to enforce a deliberate public API contract, and a canary class was used to verify the analyzer catches unintended public symbols. The initial milestone (M0) established the project scaffold with zero public API, while future milestones will tackle determinism and cycle detection.", "body_md": "Day one of building Munchausen v1.0 started with deleting the existing implementation and deliberately breaking its replacement.\n\nMunchausen is a mock-data generator for .NET that infers realistic values from\n\nyour types. Before writing v1.0, I spent time designing the API and architecture,\n\nthen captured the result in a single design document. At the end, I divided the\n\nimplementation into stages: M0 for the repository scaffold, M1 for determinism,\n\nand later milestones for metadata, inference, compilation, and runtime behavior.\n\nThe plan gives me a route through the project. Implementation is where I find out\n\nwhether those ideas actually hold together, and M0 was the first test.\n\nThe repo already had a prototype from years ago, an early `Lie`\n\n/\n\n`ModelGenerator`\n\n/ `ValuesGenerator`\n\ntrio and a `.travis.yml`\n\npinned to a\n\ndotnet-1.0 preview. My first instinct was to keep it nearby. Some of it might be\n\nuseful, and deleting code always feels more dramatic than leaving it alone.\n\nReading it changed my mind. The prototype reflected an earlier idea of the\n\nlibrary, and keeping its types invited me to preserve decisions I had already\n\nreconsidered. Removing it gave me a clean place to test the new design without\n\nnegotiating with the old one. The history is still there if I need it.\n\nOne idea from the design was that the public API should be a deliberate contract,\n\nnot whatever happens to escape from the assembly. I added `PublicApiAnalyzers`\n\n,\n\nwhich tracks every public symbol in two text files. At M0 those files contain no\n\nAPI entries. The public surface starts at zero and grows only when I consciously\n\nadd to it.\n\nConfiguring the analyzer was easy. Trusting it was different. I could see that\n\nthe package was installed and the build was green, but that did not prove it\n\nwould catch the mistake I cared about. So I added a mistake on purpose.\n\nI wrote a throwaway `Canary`\n\nclass with one public property and no XML comments,\n\nthen committed it. The build went red with exactly the errors I hoped to see:\n\n`RS0016`\n\n(this public symbol isn't declared in the API files) for the type, its\n\ngetter, and even its implicit constructor, plus `CS1591`\n\nfor the missing comments.\n\nOne little class tripped both wires at once. Then I removed the canary commit,\n\nrebuilt, and watched the build go green again.\n\nI expected a quick configuration check. Instead, I learned that a green build\n\nonly shows the current code passes. A deliberate failure proves the build can\n\nprotect a boundary I care about. When later milestones introduce public API, I\n\nknow accidental additions cannot quietly slip through.\n\nThe rest of M0 turned design choices into places where future work can happen:\n\n`net8.0`\n\n, nullable reference types, warnings treated as errors, required XML\n\ncomments, and a `Directory.Build.props`\n\nthat keeps those choices consistent. I\n\nadded CI and created six projects for the package, unit tests, acceptance tests,\n\ndeterminism tests, benchmarks, and shared test models.\n\nThe shared models include `Car`\n\n, `Owner`\n\n, `Customer`\n\n/`Order`\n\n/`Item`\n\n, a\n\npositional record, an init-only type, and `Employee`\n\nwhose `Manager`\n\nis another\n\n`Employee`\n\n. That last model is a question waiting for a later milestone: what\n\nhappens when generation encounters a cycle? I do not need the answer yet, but\n\nputting the model in place now means I cannot conveniently forget the problem\n\nwhen recursion and cycle detection arrive.\n\nZero features. Zero public API. A green build, a CI pipeline, and a guardrail\n\nI've personally watched fail and recover. More importantly, I finished M0 with a\n\nbetter understanding of the design than I had when it existed only on paper.\n\nStarting from zero is not empty progress when the boundaries themselves are part\n\nof what you are building.\n\nM1 takes on the determinism core. Munchausen promises that the same seed produces\n\nthe same data forever, across machines, OSes, and .NET versions. .NET doesn't\n\nguarantee that `System.Random`\n\nwill preserve its algorithm across versions, so\n\nI'm building an owned PRNG (xoshiro256** seeded by SplitMix64) and validating\n\nit against *published* reference vectors. If my numbers don't match the ones the\n\nalgorithm's authors published, my code is wrong, full stop. That's the kind of\n\nunambiguous test I love. More soon.", "url": "https://wpnews.pro/news/dev-log-deleting-code-and-breaking-the-build-on-purpose", "canonical_source": "https://dev.to/ernestohs/day-one-deleting-code-and-breaking-the-build-on-purpose-4lib", "published_at": "2026-06-15 05:35:00+00:00", "updated_at": "2026-06-15 05:40:35.862058+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence"], "entities": ["Munchausen", ".NET", "PublicApiAnalyzers", "System.Random"], "alternates": {"html": "https://wpnews.pro/news/dev-log-deleting-code-and-breaking-the-build-on-purpose", "markdown": "https://wpnews.pro/news/dev-log-deleting-code-and-breaking-the-build-on-purpose.md", "text": "https://wpnews.pro/news/dev-log-deleting-code-and-breaking-the-build-on-purpose.txt", "jsonld": "https://wpnews.pro/news/dev-log-deleting-code-and-breaking-the-build-on-purpose.jsonld"}}