
CTO, walking the talk of lean, true agility, XP, TDD/DDD and Continuous Delivery. #NoScrum #NoEstimates. Homebrewer and gearhead in my spare time.
Berlin, Germany
Joined March 2009
- Tweets6.9K
- Following537
- Followers501
- Likes4.4K
It was quite hard for me at the beginning but eventually it stopped being so draining. If I'm not running 4 or 5 sessions at the same time nowadays, it actually feels weird.
I've seen them all, the only one I'm still looking for a solution is 4. Looking forward to finding a skill or something that can refactor the tests periodically or even better catch this type of slop as soon as the test file is saved.
It's probably time to be more specific about slop anti-patterns in code and define how slop manifests exactly (assuming functionally working code).
From what I have seen,
1. Over engineering. This is probably the biggest. Unnecessary logical layers and abstractions everywhere. Overly verbose.
2. Inconsistencies. Using multiple different patterns for common concerns like auth/logging/metrics etc in different parts of the codebase. Or inconsistent UI components. Inconsistent naming.
3. Over-granularity. Too many files, too many modules.
4. Test slop. Excessive tests trying to cover weird edge cases. Or complex test fixtures.
5. Correctness bugs. Partially or incorrectly implemented features because of hallucinations or operator oversight.
6. Release overengineering. Fixation with backwards compatible, 'safe' releases leading to complex migration paths, schemas etc.
7. Security obsession. Overly cautious with auth/logging/owasp-10 etc leading to undebuggable systems.
8. Triviality fixation. Fixing every insignificant code review issue reported by AI code review tools.
What else?
Remove ALL comments, especially if it's a fully agentic codebase. Code and tests must be self-explanatory, comments are noisy, unnecessary and may actually confuse the agent and make it slower. If you don't believe it, run an experiment yourself.
I’m seeing this issue in some repos.
Anthropic’s v5 models system prompt says to match the surrounding code’s style. Thus, if your code has verbose comments, it will copy that style.
So:
1. Remove existing verbose comments. Then Claude isn’t tempted to copy the verbose comment style.
2. Add instruction: “Only add comments as a last resort for weird cases. Prefer short comments.”
If you allow your organization to issue AWS keys, you're just asking to be hacked. It's 2026, every AWS root account should issue a global no keys policy for all child accounts, period. No freaking excuses.
SIGNAL CONFIRMED.
9,300+ exposed AWS keys found, still valid, full account access. Not hacked, just left in a public repo.
Change your keys on a schedule, not after someone breaks in.
bleepingcomputer.com/news/se…
It's not that you don't need memory, truth is it can actually harm you. I've banned memory, documentation and comments from my codebases and it made my agents better. Prose, in any form, goes stale very quickly and the agent doesn't always know that. The truth must be in the code
The two authors of Pi share three design principles in this 3-minute video:
→ Coding doesn’t need a separate memory system
Code is the ground truth, and it keeps changing. Maintaining a separate memory that describes the code creates one more thing to maintain and keep in sync.
Models can usually infer a project’s structure and coding style after reading one or two files. If they need help navigating it, a folder list with short descriptions is enough.
For a chat bot, the ground truth is the conversation log. They append questions and answers from Slack channels to JSONL, then query the history with jq.
→ Bash is all you need
Models already know Bash and can combine commands and scripts themselves. They don’t use MCP for Sentry data. Instead, they built an on-demand Skill that handles authentication and pulls the data in a fixed format.
→ Load tool output into context only when needed
When Sentry returns 52 items, the Skill puts only 3 into context and writes the rest to a JSON file. Once the model confirms the structure looks right, it reads the remaining items.
Renato Todorov retweeted
100% my experience as well.
I found it much better to discuss an overall strategy with the agent, then gradually drive each step of the implementation. I found that I often discover new use cases, potential refactorings or optimizations that I wouldn't have known initially.
Tried to one-shot a small distributed task execution engine based on rendezvous hashing. Spent a few days setting up a simple coding harness, with quality checks, planning and review, and detailed coding and testing guidelines. Then I spent some 30 minutes discussing the task with the planning agent. The agents took over and produced the complete solution in some 30 minutes. It took me another two days to clean it up (with prompting). Excluding harness setup time, I'm not sure I would have been any slower if I implemented the whole thing by hand. I'm certain I'd be much faster if I wrote this with multiple smaller prompts.
The majority of the problems were in the tests. The agent ignored the instructions to test observable behavior. Instead of having a test like "when a node is removed from the cluster, the remaining nodes take over its work", the test was more like "when a node is removed from the cluster, internal events X, Y, and Z happened in the given order". Basically, the tests were checking if the code is working as the code is written. This didn't give me sufficient confidence that the thing is doing what it's supposed to do.
Through a lot of microprompting I overhauled the entire test code, and in the process simplified the implementation, reduced LOC, increased test coverage, and made the tests focused on the actual behavior.
Some shower thoughts based on this small experiment:
- Next time I'll just try to supply the code sketches of the tests I want, and let the agent fill in the blanks. Hopefully that will produce better results.
- Despite all the quality checks and multiple agentic reviews, the code still suffered from a lot of "small papercuts". Basically, as with human-language prose, the models overcomplicate the coding prose and make it overly verbose, which makes the code harder to understand. And it still needs to be understood, at the very least by the agents. It seems neither quality checks nor agent reviews catch such issues.
- Given all this, especially the shape of the tests (and my past experiences with generated tests), I remain unconvinced about giving the agents full autonomy and not reviewing the code myself. At the very least I'll be very scrupulous about the tests.
- I remain committed to the "work in small chunks" approach. When the chunk of work is small I can provide a more precise description of what I want, I can more quickly review the code, catch possible issues earlier, and steer the agent before it strays too far.
- For the record I still like agentic development. I barely write any code by hand these days, and still enjoy the experience. I just remain skeptical about the "one-shot everything, review nothing" philosophy which seems to be more and more prevalent.
n.b.: this text has been written completely by hand 🙃
Renato Todorov retweeted
We just published our internal 37signals Manager Playbook.
basecamp.com/managers
Inside we share what’s expected of managers, team leadership philosophies of 37signals, our "Hell Yeah" standard, how to navigate difficult conversations, and how to balance management duties with core individual contributor work. Plus a whole lot more.
There are no "just managers" at 37signals, so the individual contributor bit is key.
Questions? Comments? Post 'em here and I'll do my best to make sense.
Renato Todorov retweeted
I've been working on an orchestration harness for a squad of agents. I want to have a squad leader agent that supervises a bevy of workers. The workers are analysts, reviewers, gherkin authors, QA authors, implementers, cleaners, code reviewers, hardeners, QA testers, architects, and senior implementers.
There is a fixed workflow from themes to stories to gherkin and QA, to code, unit tests, and acceptance tests, to cleaned code, to hardened code, to QA'd code, to architecture.
This fixed workflow can be described by a static FSM. So I had my agents build it. Then I had my agents build a simulator of my squad and drive the simulator through the FSM. Then I had them jitter the simulator, simulating delays and failures. I had them run monte-carlo testing for many runs.
The agents never would have thought of that kind of testing regime. They never would have build the simulator on their own and engaged in monte-carlo testing.
Don't tell me software engineering is dead.
If you've been working with AI for a while and you haven't realized that specs (and comments) should not live with code, you haven't been paying attention enough. Use ADRs for technical decisions, code+tests MUST be enough to give your agent the context it needs to do a good job
Replying to @JamesHurburgh
Specs are a cached representation of the code
As soon as a new commit arrives, the cache will likely go stale
Agents reading that stale cache will take it for ground truth
So, archive your specs
Renato Todorov retweeted
None of the work trackers (Jira, Linear..) have a concept of underwriting. Take any ticket and try to answer: What budget / capacity is this coming out of? Who authorized spending time on this instead of something else?
This is a hugely first-class piece of info, ontology-wise.
Renato Todorov retweeted
End-to-end tests do not work at scale, nor does staging infrastructure. Past a certain number of services, both turn into a liability, and a big one at that. It is nearly impossible to run a "company-in-a-box" environment at scale.
Staging is meant to be a smaller, calmer copy of production. In practice, it becomes its own fragile system. A shared database, shared services, and everything around them all need to be up, on the right version, and in the right state at the same time.
Running tests across services on top of that staging infrastructure is even more fragile. Test for service A now depends on service B being deployed, service C having the right data, and the staging database not being mid-migration because of someone else's change.
One flaky service and the whole suite goes red, for a reason that has nothing to do with the code being tested.
When that happens, nobody owns the failure, and it somehow becomes the responsibility of a central team (most likely DevOps, SRE, or Platform. Yesss... been in the same situation a decade ago).
What works instead is each service owning its own tests and mocking the responses of the services it depends on. No shared staging database. No waiting on five other teams to deploy before you can run a single test suite.
This gives you a clear separation of concerns. A service is responsible for its own contract and its own correctness, nothing more. Cross-service behavior gets verified through contract tests between two teams, not through a shared environment that everyone touches and no one owns.
It also shifts accountability to the left because there is no one to blame. If a mock does not match reality, that is a contract problem between two teams, caught early by the team that owns the code.
Fewer moving parts, less shared infrastructure to babysit.
Somehow, every company struggles with, there is no end to this problem, and there is probably a billion-dollar business to be built solving it :)
Hope this helps.
Renato Todorov retweeted
It's just not that hard. Pick the smallest most valuable (to the user/scustomers) thing. Build that. Get feedback and adjust if needed. Then, pick the next smallest-most-valuable thing. All that other garbage—meetings, ceremonies, backlogs, etc.—is just waste.
Renato Todorov retweeted
A new article on the perils of forgetting the basics in the heat of AI-assisted coding.
Link below
Renato Todorov retweeted
unpopular dockerfile takes (that actually work)
1 - stop using alpine — yes, it's tiny. but musl libc ≠ glibc. your python/node app will rebuild native deps from scratch or just... silently be slower. use -slim (debian-slim) instead. same size win, zero grief.
2 - layer order is your cache strategy. COPY your lockfile first, run install, then copy source. invalidating the install layer on every code change is a skill issue ngl
3 - multi-stage builds aren't just "best practice" — they're the actual reason your prod image doesn't ship gcc and 400mb of build tools. builder stage = bloat zone. final stage = lean mean container.
4 - COPY . . is fine actually — if your .dockerignore is correct. most pain here is from forgetting to ignore node_modules/, .git, *.log. fix the ignore file, not the COPY.
5 - one process per container is a vibe, not a law. if your app needs nginx + app server and you're not at k8s scale — just use supervisord. the "one process" dogma costs more complexity than it saves sometimes.
6 - pin your base image by digest, not tag. node:20 today ≠ node:20 in 6 months. prod broke because of a tag? that's a you problem tbh.
7 - BuildKit cache mounts (--mount=type=cache) will change your life. pip/apt/cargo cache between builds without it ending up in the final layer. nobody talks about this enough fr
there's no "best practice" in a vacuum. alpine is great for Go binaries. slim is great for Python. scratch is great for static bins. know your workload, then choose.
btw if you want something to catch all this stuff automatically -
check out dockerfile-roast — a linter written in Rust that literally roasts your Dockerfile. 63 rules, brutally honest output (but it can also provide just dry facts, no roast), runs on any OS or as a docker container
github.com/immanuwell/docker…
#docker #devops #kubernetes #backend #linux #rust #sre #containers


























