Tip: Stop using /init for AGENTS.md to get better performance My latest deep-dive: https://lnkd.in/gkmZ3HJs ✍ As we transition deeper into AI-assisted engineering and background agent orchestration, there's a common ritual: setting up a new project, running an auto-generation tool, and committing a comprehensive AGENTS.md context file. It feels like the responsible thing to do. But recent 2026 research from ETH Zurich and others reveals a different reality: auto-generated context files can actually reduce task success by 2-3% while inflating costs by over 20%. Why? Because coding agents can already discover your directory structure, tech stack, and module explanations on their own. Handing them an auto-generated summary just adds noise, burns tokens, and dilutes their attention from the actual task. So, what actually earns a line in your AGENTS.md? 1. The undiscoverable: Tooling gotchas that change operations 2. Operational landmines: "The legacy/ directory is deprecated but imported by production - do not delete." 3. Non-obvious conventions: Custom middleware patterns that shouldn't be refactored to standard conventions. If an agent can discover it by reading your code, delete it from the file. A better mental model: Treat your AGENTS.md as a living list of codebase smells you haven't fixed yet. If an agent keeps reaching for the wrong dependency or putting utilities in the wrong folder, don't just add a prose instruction to the context file. Restructure the code, add a linter rule, or improve the test coverage. Treat it as a diagnostic tool, fix the underlying friction, and then delete the line. I dive into the data, the "pink elephant" problem of context anchoring, and why monolithic context files need to evolve into dynamic routing layers in my latest post. How is your team currently managing context for your background coding agents? Are you relying on static files, or exploring more dynamic context loading? Let me know in the comments. #ai #programming #softwareengineering
Best Programming Practices for Clean Code
বিশেষজ্ঞ পেশাদারদের থেকে সেরা LinkedIn সামগ্রী এক্সপ্লোর করুন।
-
-
Karpathy's LLM Knowledge Bases post went viral this week, and rightfully so. The idea is simple: raw documents go in, an LLM processes them into a structured wiki, your agent queries that wiki at runtime. No fancy RAG pipeline, no vector database. Just compiled knowledge your agent can navigate. Everyone is applying this to external data: docs, papers, research articles. I went a different direction. The raw material in my version isn't articles from the web. It's Claude Code session logs. Every time I work on the codebase, hooks automatically capture what got built, what decisions were made, what didn't work and why. A daily flush script compiles those logs into wiki articles in my Obsidian vault. When I start a new session, the agent searches that wiki before writing a single line of code. The result feels different from a good CLAUDE.md. It's not just static documentation! It's a living record of every architectural decision, every "we tried X and it broke because Y." Institutional memory, but searchable. The loop compounds quickly. Ask a question, the agent finds a relevant wiki article from three weeks ago, gives a better answer, and that answer eventually feeds back into the wiki. The longer you use it, the more context the agent has about your codebase specifically (not codebases in general, yours). Setup is one prompt into Claude Code: hooks, daily flush script, wiki structure, all generated automatically. Karpathy's insight was "stop RAG-ing raw documents, start compiling them." Most developers are losing context between every session. All that institutional knowledge evaporates. Compiling your session logs applies the same idea one level closer to home. I just posted a full breakdown on YouTube with the complete architecture walkthrough and a live demo of setting up the whole system. Link to my GitHub repo in the replies too!
-
Every migration you will ever do is a Ship of Theseus problem. The ancient Greeks had a paradox: if you replace every plank of a ship one by one, is it still the same ship? We face this every day, except the ship is in production :) The naive version of a migration is a full cutover: stop the old system, start the new one. It almost never works at scale. What actually happens is a slow, plank-by-plank replacement. Let me give you some examples... Database migrations are the clearest example. Moving from MySQL to PostgreSQL takes time. You run both databases in parallel, write to both (dual-write), and slowly shift small portions of reads to Postgres while monitoring for inconsistencies. Then, you gradually port the entire codebase. Language migrations follow the same pattern. You never rewrite everything from one language to another and flip the switch. It is also done on a piece-by-piece basis. A similar strategy is followed during monolith-to-microservices migrations. So, if you are planning something big, consider breaking it into planks and changing one at a time until your entire ship is new. Pro tip: use this analogy to sound smart in meetings and discussions :) It always works.
-
The 10 Rules NASA Swears By to Write Bulletproof Code: 0. Restrict to simple control flow ↳ No goto, setjmp, longjmp, or recursion. Keep it linear and predictable. This ensures your code is easily verifiable and avoids infinite loops or unpredictable behavior. 1. Fixed loop bounds ↳ Every loop must have a statically provable upper bound. No infinite loops unless explicitly required (e.g., schedulers). This prevents runaway code and ensures bounded execution. 2. No dynamic memory allocation after initilization ↳ Say goodbye to malloc and free. Use pre-allocated memory only. This eliminates memory leaks, fragmentation, and unpredictable behavior. 3. Keep functions short ↳ No function should exceed 60 lines. Each function should be a single, logical unit that’s easy to understand and verify. 4. Assertion density: 2 per function ↳ Use assertions to catch anomalous conditions. They must be side-effect-free and trigger explicit recovery actions. This is your safety net for unexpected errors. 5. Declare data at the smallest scope ↳ Minimize variable scope to prevent misuse and simplify debugging. This enforces data hiding and reduces the risk of corruption. 6. Check all function returns and parameters ↳ Never ignore return values or skip parameter validation. This ensures error propagation and prevents silent failures. 7. Limit the preprocessor ↳ Use the preprocessor only for includes and simple macros. Avoid token pasting, recursion, and excessive conditional compilation. Keep your code clear and analyzable. 8. Restrict pointer use ↳ No more than one level of dereferencing. No function pointers. This reduces complexity and makes your code easier to analyze. 9. Compile with all warnings enabled ↳ Your code must be compiled with zero warnings in the most pedantic settings. Use static analyzers daily to catch issues early. Some of these rules can be seen as hard to follow, but you can't allow room for error when lives are at stake. Which ones are you still applying? #softwareengineering #systemdesign ~~~ 👉🏻 Join 46,001+ software engineers getting curated system design deep dives, trends, and tools (it's free): ➔ https://lnkd.in/dCuS8YAt ~~~ If you found this valuable: 👨🏼💻 Follow Alexandre Zajac 🔖 Bookmark this post for later ♻️ Repost to help someone in your network
-
Rewrites feel clean at the start. Then reality shows up. Missed edge cases. Broken behavior. Delayed releases. A second system nobody fully trusts. A safer option is to migrate incrementally. That’s where the Strangler Fig Pattern shines. Instead of replacing the whole legacy API at once, you put a reverse proxy in front of it and start routing traffic endpoint by endpoint. Old system keeps running. New system takes over gradually. Risk stays contained. In my example, I start with a Node.js API, add YARP as a reverse proxy, and then migrate individual endpoints into a modern .NET 10 API. The nice part is that this works just as well for old .NET Framework apps. You don’t need a giant rewrite to modernize a legacy system. You need a controlled migration path. I break down the full implementation here: https://lnkd.in/dg_zf-MV
-
No, you won't be vibe coding your way to production. Not if you prioritise quality, safety, security, and long-term maintainability at scale. Recently coined by former OpenAI co-founder Andrej Karpathy, "vibe coding" describes an AI-coding approach where developers focus on iterative prompt refinement to generate desired output, with minimal concern for the LLM-generated code implementation. At Canva, our assessment — based on extensive and ongoing evaluation of AI coding assistants — is that these tools must be carefully supervised by skilled engineers, particularly for production tasks. Engineers need to guide, assess, correct, and ultimately own the output as if they had written every line themselves. Our experimentation consistently reveals errors in tool-generated code ranging from superficial (style inconsistencies) to dangerous (incorrect, insecure, or non-performant code). Our engineering culture is built on code ownership and peer review. Rather than challenging these principles, our adoption of AI coding assistants has reinforced their importance. We've implemented a strict "human in the loop" approach that maintains rigorous peer review and meaningful code ownership of AI-generated code. Vibe coding presents significant risks for production engineering: - Short-term: Introduction of defects and security vulnerabilities - Medium to long-term: Compromised maintainability, increased technical debt, and reduced system understandability From a cultural perspective, vibe coding directly undermines peer review processes. Generating vast amounts of code from single prompts effectively DoS attacks reviewers, overwhelming their capacity for meaningful assessment. Currently we see one narrow use case where vibe coding is exciting: spikes, proofs of concept, and prototypes. These are always throwaway code. LLM-assisted generation offers enormous value in rapidly testing and validating ideas with implementations we will ultimately discard. With rapidly expanding LLM capabilities and context windows, we continuously reassess our trust in LLM output. However, we maintain that skilled engineers play a critical role in guiding, assessing, and owning tool output as an immutable principle of sound software engineering.
-
High-quality code makes your work short-lived. Poorly written code ensures the company will always need your help. 😜 Funny — yet many people still follow this mindset. Here’s the hard truth: Across my career, from freshers to senior leaders, I’ve seen professionals who deliberately complicate work, avoid documentation, refuse to share knowledge, and quietly build a dependency around themselves. It’s not incompetence — it’s strategy. A strategy that slows teams down, breeds silos, and creates a dangerous single point of failure. And while it may offer short-term “job security,” it kills long-term team health, innovation, and trust. For leaders, these situations are the most challenging because the person often looks productive on the surface. But behind the scenes, the team becomes fragile, and delivery risks multiply. In engineering, we avoid single points of failure in systems. We should avoid them in people too. 💡 Hard-Hitting Tips for Leaders to Fix This 1️⃣ Make knowledge sharing non-negotiable Mandate documentation, code reviews, and walkthroughs. If knowledge lives only in someone’s head, that’s a risk — not a strength. 2️⃣ Remove dependency incentives Reward collaboration, not silo-building. Make team outcomes matter more than individual heroics. 3️⃣ Rotate responsibilities Let others touch the “critical” areas. If someone resists, that’s a red flag — not loyalty. 4️⃣ Build a culture where transparency is expected Open communication, shared ownership, and regular alignments reduce the power of hidden information. 5️⃣ Address the behaviour early Silence is approval. The longer you let it grow, the harder it becomes to fix. 6️⃣ Make it safe for others to speak Often the team knows who the blocker is — but they need psychological safety to raise concerns. 7️⃣ Lead by example Leaders who share knowledge freely create teams that do the same. Healthy teams grow when knowledge flows. Strong leaders rise when they dismantle silos. And real progress happens only when success is shared — not hoarded. #Leadership #TeamWork #EngineeringCulture #TechLeadership #TeamDynamics #OrgCulture #KnowledgeSharing #GrowthMindset #PeopleManagement #LeadershipTips #CriticalResource #SoftwareEngineering #MunnaPrawin #BUMI #SmartLife
-
Bad code quality? No one knows how to modify other people's code? Just pair up! 𝗣𝗮𝗶𝗿 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 𝗙𝘂𝗻𝗱𝗮𝗺𝗲𝗻𝘁𝗮𝗹𝘀: 𝗣𝗮𝗶𝗿 𝗽𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 is a where two programmers work together at one workstation. One, the "driver," writes code while the other, the "navigator," reviews each line of code as it's typed, thinking strategically about the direction and spotting potential issues. T hey switch roles frequently to maintain engagement and share perspectives. 𝗠𝗼𝗯 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 extends this concept to more than two developers working on the same code simultaneously. One person is at the keyboard (the driver) while the rest of the team collaboratively navigates. The driver role typically rotates every 15-30 minutes. 𝗙𝗶𝗿𝘀𝘁 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲𝘀: 1. Continuous code review: Code is reviewed instantly as it's written, catching issues early 2. Knowledge sharing: Less experienced developers learn from veterans, while veterans gain fresh perspectives 3. Collective ownership: The code belongs to the team, not individuals 4. Real-time problem solving: Complex problems are tackled with multiple viewpoints simultaneously 5. Reduced cognitive load: The workload is shared between multiple minds But I know there is a lot of 𝗿𝗲𝘀𝗶𝘀𝘁𝗮𝗻𝗰𝗲 to pair programming. - Two developers doing one person's job - Slows down development and reduces output - Developers prefer working alone - Hard to coordinate across teams/time zones - Constant collaboration is exhausting Effective Implementation Tips: 1. Start gradually - perhaps with just a few hours per day 2. Rotate pairs regularly to spread knowledge 3. Create comfortable workstations designed for two people 4. Establish clear pairing protocols and communication guidelines 5. Use pairing selectively for complex tasks or knowledge transfer 6. Regularly retrospect on pairing effectiveness and adjust accordingly For companies considering pair programming, it's crucial to understand that it's not an all-or-nothing approach. Most successful implementations use a hybrid model where pairing is used strategically for complex tasks, onboarding, or critical features, while simpler tasks might be handled solo. Do you pair? Are you even allowed to pair? Or are you actively encourage to pair?
-
As a client project manager, I consistently found that offshore software development teams from major providers like Infosys, Accenture, IBM, and others delivered software that failed 1/3rd of our UAT tests after the provider's independent dedicated QA teams passed it. And when we got a fix back, it failed at the same rate, meaning some features cycled through Dev/QA/UAT ten times before they worked. I got to know some of the onshore technical leaders from these companies well enough for them to tell me confidentially that we were getting such poor quality because the offshore teams were full of junior developers who didn't know what they were doing and didn't use any modern software engineering practices like Test Driven Development. And their dedicated QA teams couldn't prevent these quality issues because they were full of junior testers who didn't know what they were doing, didn't automate tests and were ordered to test and pass everything quickly to avoid falling behind schedule. So, poor quality development and QA practices were built into the system development process, and independent QA teams didn't fix it. Independent dedicated QA teams are an outdated and costly approach to quality. It's like a car factory that consistently produces defect-ridden vehicles only to disassemble and fix them later. Instead of testing and fixing features at the end, we should build quality into the process from the start. Modern engineering teams do this by working in cross-functional teams. Teams that use test-driven development approaches to define testable requirements and continuously review, test, and integrate their work. This allows them to catch and address issues early, resulting in faster, more efficient, and higher-quality development. In modern engineering teams, QA specialists are quality champions. Their expertise strengthens the team’s ability to build robust systems, ensuring quality is integral to how the product is built from the outset. The old model, where testing is done after development, belongs in the past. Today, quality is everyone’s responsibility—not through role dilution but through shared accountability, collaboration, and modern engineering practices.
-
Claude Code just shipped something most developers haven't noticed yet. Agent Teams. Not one AI coding assistant. A full team of AI agents — working in parallel — talking to each other — on your codebase. Here's what changes everything → 𝗪𝗵𝗮𝘁 𝗔𝗿𝗲 𝗔𝗴𝗲𝗻𝘁 𝗧𝗲𝗮𝗺𝘀? → Multiple Claude Code instances coordinated as a team → One session acts as Team Lead — assigns tasks, synthesizes results → Teammates work independently with their own context windows → They message each other directly — no bottleneck through the lead This is NOT the same as subagents. Subagents report back to a parent. That's it. One-way. Agent Teams talk to each other. Share findings. Challenge assumptions. Self-coordinate. Think: contractors on separate errands vs. a project team in the same room. 𝟰 𝗣𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻 𝗧𝗲𝗮𝗺 𝗣𝗮𝘁𝘁𝗲𝗿𝗻𝘀 𝗧𝗵𝗮𝘁 𝗔𝗰𝘁𝘂𝗮𝗹𝗹𝘆 𝗪𝗼𝗿𝗸 𝟭. 𝗙𝘂𝗹𝗹-𝗦𝘁𝗮𝗰𝗸 𝗧𝗲𝗮𝗺 Lead/Architect → Frontend → Backend → Testing → Reviewer Each agent owns a layer. No stepping on each other's code. 𝟮. 𝗗𝗲𝗯𝘂𝗴 𝗗𝗲𝗯𝗮𝘁𝗲 𝗧𝗲𝗮𝗺 Spawn 3-5 agents with competing hypotheses. They actively try to disprove each other. The theory that survives is the actual root cause. Why this works → sequential debugging suffers from anchoring bias. Once you explore one theory, everything after is biased toward it. 𝟯. 𝗤𝗔 𝗧𝗲𝗮𝗺 Security reviewer + Performance agent + UX quality agent. Pro tip: route models — Opus for deep debugging, Sonnet for perf, Haiku for UX. 𝟰. 𝗪𝗿𝗶𝘁𝗶𝗻𝗴 𝗧𝗲𝗮𝗺 Context Gatherer ↔ Writer ↔ Editor All run simultaneously. The writer requests context mid-task. 𝟳 𝗕𝗲𝘀𝘁 𝗣𝗿𝗮𝗰𝘁𝗶𝗰𝗲𝘀 𝗜'𝘃𝗲 𝗟𝗲𝗮𝗿𝗻𝗲𝗱 → Always plan BEFORE spawning — without a plan, agents go random and waste tokens → CLAUDE. md is your force multiplier — 3 agents reading clear docs >> 3 agents exploring blindly → Set quality bar explicitly — tell the lead, instructions trickle down → Define roles prescriptively for expensive tasks → Monitor context usage — single agent fills 80-90% on large codebases, splitting keeps each at ~40% → Use model routing to control costs → Know that idle agents auto-kill themselves 𝗧𝗵𝗲 𝗣𝗮𝗿𝘁 𝗠𝗼𝘀𝘁 𝗣𝗲𝗼𝗽𝗹𝗲 𝗠𝗶𝘀𝘀 Agent Teams' killer feature isn't parallelism. It's collaboration. Agents debating each other. Agents reviewing each other's code. Agents challenging assumptions that a single agent would never question. That's a fundamentally different quality of output. I drew out the complete architecture, patterns, and decision framework in one handwritten cheatsheet (see image). The gap between "uses Claude Code" and "orchestrates Claude Code teams" is about to get very wide. Which side do you want to be on?