AI 资讯
Startups Don't Need "Perfect" Code. They Need "Malleable" Code
Why adaptability beats perfection in startup software development The Startup Trap: Building for a Future That Doesn't Exist Yet Many startup founders make the same mistake. They spend months building the "perfect" product architecture. The code is clean. The design patterns are flawless. The test coverage is near 100%. The infrastructure can scale to millions of users. There's just one problem: They don't have any users. In the startup world, survival depends on learning faster than competitors, not on creating the most elegant codebase. Product-market fit is uncertain. Customer needs change weekly. Business models evolve. Features that seemed critical last month become irrelevant the next. In that environment, the biggest advantage isn't perfect code. It's malleable code . Code that can bend, adapt, and evolve as the business learns. What Is Malleable Code? Malleable code is software that is easy to change. It isn't necessarily perfect. It isn't over-engineered. It isn't designed to solve every future problem. Instead, it's designed to support continuous experimentation. Malleable code allows teams to: Launch MVPs quickly Test assumptions rapidly Respond to customer feedback Pivot when necessary Add new features without major rewrites Remove failed features with minimal effort Think of it this way: Perfect code optimizes for certainty. Malleable code optimizes for uncertainty. And startups operate almost entirely in uncertainty. When you're still searching for product-market fit, the ability to adapt is often more valuable than technical elegance. Why "Perfect" Code Often Hurts Startups Software engineers love solving technical problems. It's natural. Building a scalable architecture feels productive. Refactoring code feels productive. Designing the perfect system feels productive. But startup success isn't measured by code quality. It's measured by business outcomes. Questions such as: Are customers using the product? Are they paying for it? Are they returning? A
AI 资讯
Mitigating Hallucinations in Theology AI: Implementing Groundedness Evaluation Pipelines
Mitigating Hallucinations in Theology AI: Implementing Groundedness Evaluation Pipelines For software developers and indie hackers, the era of building generic wrapper APIs is over. The real value now lies in highly specialized, niche vertical applications. One of the most fascinating, complex, and underserved niches is the intersection of artificial intelligence and religious doctrine. Building a catholic ai tool presents unique software engineering challenges. Unlike general-purpose chatbots, a theology ai application cannot afford to "hallucinate" or generate creative interpretations of established doctrines. In this space, an inaccurate answer is not just a software bug; it is a theological error. To build a high-quality, trustworthy catholic ai app , developers must move past basic prompt engineering. We must implement robust groundedness evaluation pipelines. This article explores the technical journey of building a specialized catholic ai chatbot , the catholic church stance on ai , our choice of tech stack, and how to build a production-grade groundedness pipeline to keep your AI aligned with official church teachings. The Catholic Church Stance on AI: Designing for Ethics and Trust Before writing a single line of Dart, Swift, or Python, we must understand the ethical landscape of ai and theology . The Vatican has taken an surprisingly proactive approach to artificial intelligence. Pope Francis has frequently spoken on the topic, advocating for "algor-ethics"—the ethical development of algorithms. The catholic church stance on ai emphasizes that technology must serve human dignity and remain aligned with truth. ┌─────────────────────────────────┐ │ The Vatican's Algor-ethics │ └────────────────┬────────────────┘ │ ┌─────────────────────────┴─────────────────────────┐ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ Human Agency │ │ Doctrinal Truth │ │ AI must assist, │ │ AI must not alter│ │ never replace │ │ established dogma│ └──────────────────┘ └─────────
AI 资讯
Context engineering is engineering work — not prompt-writing
TL;DR — When the spec is good, implementation needs less model. I started using a top-tier model to write the spec and a cheaper, faster one to implement it — still using the strong model, just spending it on the spec instead of the implementation. The gain isn't some magic prompt phrasing; it's the context: explicit business rules, audited project constraints, a defined output contract. That's systems engineering — the discipline of anyone who's kept real software alive, whatever their stack. Every backend dev knows the scene: the Swagger is out of date, the last hotfix shipped without a unit test, and the README.md documents a command nobody's used in six months. The code works. The docs lie. And the gap between the two is exactly where AI — and we — start to go wrong. I've spent the last few months developing with AI for real inside production projects, not tutorial greenfield. My takeaway was less about which model to use and more about a shift that already has a name: the move from prompt engineering to context engineering . The difference isn't semantic. Prompt engineering treats the problem as writing — finding the magic phrase. Context engineering treats it as what it always was: a systems engineering problem . And it's where my backend background applied most directly — though anyone who's kept a real system alive has the same instinct. The experiment that convinced me Let me start with the evidence, because that's what made me take this seriously. My reflex, for a long time, was to reach for the strongest model for everything — more expensive, smarter, fewer errors. Makes sense on paper. In practice, I saw something else. When the task's specification is well done — explicit business rules, audited project constraints, a defined output format — the model capability needed for implementation drops sharply. Enough to split the work by stage: I started using a top-tier model (currently Opus) to write the spec , and a cheaper, faster model (Sonnet) to implemen
AI 资讯
Repricing of Software Engineering Labor
I started my career in the late 2010s, and I have had a front-row seat to the growth of the industry that has given me everything: software engineering. Looking back over the last decade, I have mixed feelings about some of the calls I made. And I am seeing the same patterns play out again now. So for engineers who are confused about where this is headed and how to navigate it, here is how I think about it. Generalist SWEs were a product of cheap money The late 2010s, I saw an huge amount of startup funding, globally. Flipkart, Snapdeal, Jugnoo, and hundreds of others were scaling hard and one hiring pattern I saw was that: everyone wanted generalist software engineers. People who could easily get upto speed across the stack.- backend, frontend, infra, deployment and simply ship. Building software was expensive. Automation was still low. Kubernetes had just gone mainstream. Shipping still meant a surprising amount of manual work: SSH-ing into servers, copying artifacts around, running mvn builds by hand, debugging deployments straight in production, duct-taping infrastructure that today you would never touch. Companies fought over engineers who maximized feature throughput. Breadth was a premium, because every extra engineer increased the rate at which software got built. It helped because the money was also free and VCs rewarded growth over efficiency, and hiring software engineers in bulk was the easiest way to spend it. Pull up a resume from an engineer who started around that time and you will usually see the same shape: a long list of technologies and frameworks, broad and adaptable, but rarely deep in any one thing. There was no incentive to go deep. LLMs Changed The Dynamics LLMs did not kill software engineering. It compressed the cost of implementation. The work that got hit first was the work that was already standardized: CRUD apps; API integration and glue code; Framework-heavy backend work; Frontend scaffolding; Standard architectural patterns. What use
创业投融资
Thank you DEV community: the Thinking Engineer Toolkit is live
Over the past weeks, I’ve been sharing a series of posts that gravitate around one question: How do...
AI 资讯
The 80/20 Rule of AI Code — Why the Last 20% Takes 80% of Your Time
AI wrote the first 80% of my feature in 10 minutes. The code was clean. The logic made sense. The...
AI 资讯
The Engineer Identity Crisis: AI Didn't Take Your Job, It Doubled It
Everyone says our job got easier. The people doing it are quietly falling apart. Here's the part nobody at the dinner table wants to hear: AI didn't make software engineering easy. It made it relentless. Your uncle thinks you press a button now. Your PM thinks the estimate should be half what it used to be. LinkedIn thinks you're either an "AI-native 10x engineer" or a dinosaur waiting for the meteor. And somewhere in the middle of all that noise is you, doing two jobs at once and wondering when you stopped recognizing the one you signed up for. If that landed, keep reading. This one's for you. 💡 The Lie Everyone Has Agreed To Believe The story the world has settled on is simple: AI writes the code now, so the hard part is over. It's a comforting story. It's also wrong in a way that's hard to explain to anyone who hasn't sat in the chair. Yes, the blank-file problem is mostly solved. Boilerplate, scaffolding, the first rough pass at a function, all of that is faster than it's ever been. The problem is "writing the lines" was never the expensive part of this job. The expensive part was always judgment. Knowing what to build, knowing why it breaks, knowing which of the model's three confident suggestions is the one that quietly corrupts your data at 2 AM is where the engineer earns their salt. AI didn't remove that work. It buried it under a pile of plausible-looking output you now have to review, verify, and own. So the meter didn't slow down. It moved. You spend less time typing and far more time deciding, validating, and cleaning up. To everyone watching from outside, that looks like less work. From inside, it's a heavier cognitive load on a shorter clock. Sound familiar? The Treadmill Nobody Put On the Job Description The cost no one talks about is the half-life of what you know is collapsing. Five years ago you could learn a framework and ride it for a few years. Now a tool you mastered in January has three competitors and a new paradigm by June. New model, new c
AI 资讯
Clean Architecture in .NET 8: A 2026 Starter Template with 4 Projects, EF Core, and JWT Auth
I joined a team where the controller was 800 lines long, the business rules were scattered between the controller and the DbContext , and "to run the tests, spin up a SQL Server in Docker" was a sentence I heard every week. The fix was Clean Architecture. The argument I had with the team lead was about how to actually structure it. We argued for two weeks. Then I built this template so the next person wouldn't have to. This is the Clean Architecture .NET 8 starter template I wish someone had handed me on day one. Four projects, strict dependency direction, domain entities that own their own invariants, and an Application layer you can unit test with Moq — no database required. The whole repo is on GitHub , MIT-licensed, runs with dotnet run , and ships with xUnit tests, JWT auth, Swagger, Docker, and CI. This post is the explanation of why each project exists, what goes in it, and what I learned the hard way about getting Clean Architecture right in .NET. The problem Clean Architecture solves The naive way to build a .NET Web API is one project, one folder structure, and "everything talks to everything": MyApp/ Controllers/ ProductsController.cs ← HTTP stuff OrdersController.cs ← HTTP stuff + business rules Services/ ProductService.cs ← business rules + DbContext.SaveChanges Data/ AppDbContext.cs ← EF Core, entities Models/ Product.cs ← POCO with public setters This works for the first 1,000 lines. By 5,000 lines, the controller is doing five things at once. By 10,000, "to test this, I need a database" is the answer to every test question, and your CI takes 20 minutes because every test run spins up SQL Server. Clean Architecture says: separate the business rules from the HTTP boundary, separate the database from the business rules, and enforce it with project references. A controller is allowed to call a service. A service is allowed to call a repository. A repository is allowed to know about EF Core. Nothing is allowed to know about anything "above" it in the chai
AI 资讯
I Built RAG From Scratch in Python to Understand It. Here's What I Learned.
I had used LangChain's RAG chain in production for six months. I could not have told you, off the top of my head, what chunk_overlap did, or why cosine similarity is the right distance metric, or how nomic-embed-text actually turns a sentence into a vector. The high-level library abstracted all of it away. So one weekend I deleted the LangChain dependency and wrote a RAG pipeline from scratch in ~500 lines of plain Python. No framework, no magic. pypdf for text extraction. A 60-line chunker. ChromaDB for the vector store. Ollama for embeddings and the LLM. The whole thing is on GitHub — every module is under 200 lines, every test is deterministic, and you can read the whole thing in one sitting. This is the build log. Not a tutorial — the build log, with the parts that surprised me and the parts I got wrong the first time. Why bother The honest reason: I was using LangChain's RetrievalQA chain and getting answers I didn't trust. Sometimes the model would say "according to the document" when the document didn't say that. Sometimes the citations were wrong. I had no way to know if the chunker was dropping important context, or if the cosine similarity was picking the wrong neighbors, or if the prompt was actually constraining the model. The library was a black box. When you build it yourself, every layer is inspectable. When the answer is wrong, you can add a print statement in pipeline.py line 102 and see exactly which chunks were sent to the LLM. When the chunker cuts a sentence in half, you see it in the test fixtures. When the embedding model gives garbage for some inputs, you can swap in a different model with one constructor parameter. None of that is possible when the whole thing is RetrievalQA.from_chain_type(llm=..., retriever=...) . The other reason: the code I wrote is 500 lines, and it covers the same ground as a 50-line LangChain script. The extra 450 lines are comments, type hints, tests, and explicit error handling. That's the actual complexity. LangCha
AI 资讯
Build a Local RAG Chatbot in 30 Minutes with .NET 8, Ollama, and React
I uploaded a 40-page PDF of an internal API spec, asked "what's the rate limit for the search endpoint?", and got back: "100 requests per minute per API key, with bursts up to 200. See section 4.2 of the document." With citations. In about three seconds. The whole stack runs on my laptop. It cost me $0 in LLM credits during development because Ollama is free and local, and the embedder I used is also free and local. The repo is here — issues and PRs welcome. This is the build log. Not a tutorial where every step works the first time — a build log where I tell you which decisions held up and which ones I redid. The problem most "chat with your PDF" demos have Every "chat with your PDF" tutorial I read in early 2025 had the same shape: open OpenAI, paste your API key, call gpt-4 with a 50-page PDF stuffed into the context window, get an answer, pay $0.03 per question, repeat. That works for a demo. It does not work for a tool you'd actually use at work, because: The PDF might contain customer data, internal pricing, or unreleased features. You do not want that going to OpenAI's training pipeline or anyone's logs. The cost adds up. If your team uses it 50 times a day, that's $45/month per seat. The model hallucinates on long PDFs anyway. Stuff 100 pages into a 128k context window and the model starts forgetting the middle. The fix is RAG (Retrieval-Augmented Generation) — don't send the whole PDF, send only the 3-5 chunks that are actually relevant to the question. The rest of the work is the same: embed the chunks, embed the question, find the closest matches, send those to the LLM with the question. But the cost and the privacy story both improve by 100x. The actual ask: Upload a PDF. Ask questions. Get answers from the document with citations, in under 5 seconds, with no data leaving my laptop and no monthly bill. The architecture One .NET 8 solution, one React app, one Ollama process, zero cloud dependencies. [ PDF Upload ] | v +-------------------+ chunks +-------
AI 资讯
From Stack Trace to Suggested Fix in 4 Seconds: Building a Self-Healing .NET API Gateway.
Last Tuesday my API gateway caught a NullReferenceException , streamed it to a dashboard in real-time, and pushed a draft code fix to the browser tab of the on-call engineer — before I finished reading the error myself. That sentence used to be vendor marketing. Now it's just my Program.cs . This is the architecture post-mortem. I built it on weekends. It runs in Docker. It cost me exactly $0 in LLM credits during development because Groq's free tier is generous and Ollama works as a swap-in. The repo is here — issues and PRs welcome. The problem most .NET teams have Production errors are caught, logged to a file, and forgotten. Engineers find out from a Slack ping twenty minutes later, if at all. By the time someone looks, the original request context is gone, the user's session has expired, and the stack trace is buried four layers deep in System.* calls. "Self-healing" is a word vendors use to mean "auto-restart the pod." I wanted something better. The actual ask: When an exception is thrown in service A, give the engineer (a) a clear root cause, (b) a suggested fix, and (c) a draft code patch — in under 30 seconds. Not a magic black box. Not an auto-applied patch. Just: catch the error, give the model the right context, push the analysis to a human in real-time, and let the human close the loop. The architecture One .NET solution, four projects, four NuGet packages, no new infrastructure beyond what you probably already have. [ HTTP request ] | v +-------------------+ enqueue +---------------------+ | SmartLogAnalyzer. | ---------------------> | Hangfire (Redis) | | Api | +----------+----------+ | (ErrorHandling | | | Middleware) | v +-------------------+ +---------------------+ | SmartLogAnalyzer. | | Worker | | (ErrorProcessingWorker) +-----+-------+-------+ | | AI call | | persist v v +-----------+ +-----------+ | Semantic | | MSSQL | | Kernel + | | (ErrorLog | | Groq LLM | | table) | +-----+-----+ +-----------+ | v +---------------------+ | SignalR Hub | | (
AI 资讯
What Kind of AI-Assisted Developer Are You? Take the quiz.
AI makes us faster, but does it make us better engineers, or just more dependent? As a follow-up...
AI 资讯
Stop reading to build a library. Start reading to solve a problem.
Most engineering reading lists are optimized for knowledge accumulation. Modern engineering rewards bottleneck elimination. Last week, a junior engineer showed me a "Top 10 Books Every Engineer Should Read" list. It looked almost identical to the lists I saw ten years ago. The same classics. The same process books. The same assumption: Read enough books and you'll become a better engineer. That's not how most high-performing teams learn. The best engineers I know don't build learning plans around books. They build learning plans around constraints. The Problem with standard reading lists Most reading lists assume that knowledge is universally valuable. In practice, engineering value is highly contextual. A backend engineer struggling with database contention does not need another chapter on Agile. A team spending thousands of dollars per month on LLM inference does not need a generic software craftsmanship book. A startup fighting latency issues does not need a leadership framework. They need solutions to the bottleneck directly in front of them. Reading lists rarely account for this. They optimize for completeness. Engineering rewards relevance. The Shift Most Engineers Miss The fundamentals still matter. Distributed systems matter. Databases matter. Networking matters. Operating systems matter. They are not obsolete. But they are no longer sufficient. Modern systems introduce constraints that barely existed a few years ago: AI inference costs Context window limitations Agent orchestration Evaluation pipelines Semantic caching Non-deterministic workflows Model routing Human-in-the-loop systems Many traditional reading lists never touch these problems. Yet these are exactly the problems teams are solving every day. The challenge is no longer simply writing correct software. The challenge is building reliable systems on top of components that are inherently probabilistic. What Changed For decades, engineers mostly worked with deterministic systems. Given the same inp
AI 资讯
Working with AI Means Thinking More, Not Less
Working with AI Means Thinking More, Not Less Yes, this text is long. Yes, it repeats itself in places. I did not clean that up. A text that sounded too smooth while arguing that AI forces you to think more, not less, would be at least slightly dishonest. This is not fast food for quick consumption. And yes, don’t worry: you won’t hear anything especially new here. That is part of the problem too. There is a popular and very seductive story about AI in software development. Now that the machine can write code, the human gets to think less. You just point it in the right direction, and the model will quickly and cheaply do a significant part of the work on its own. In that picture, AI is primarily an accelerator for code production, and human thinking gradually shifts from necessity to optional extra. I keep feeling more and more strongly that this description is dangerously wrong. A more accurate formula for my own experience right now is this: I’m the tech lead, the AI is the entire team in one body . And if you take that metaphor seriously, the conclusion is the exact opposite of the mainstream narrative. Working with AI is not a way to think less. It is a mode in which you need to think more, not less . Not because the AI is bad. But because it is too good at one very treacherous thing: it confidently and smoothly fills in what was left unsaid. I’m the tech lead, the AI is the team At first this metaphor felt like a neat formulation. Now it feels like a literal description of what is going on. If you treat AI as a very fast and very capable executor, a lot of things become clearer immediately. It really can wipe out months of routine work. It can spin up prototypes quickly, take over test scaffolding, try out alternatives, make local edits, help break a task into parts, and sometimes even suggest a decent direction. On the surface, this really does look like a silver bullet. Especially if the human knows the stack and can read code. The pace becomes so extreme th
AI 资讯
Treat prompt libraries as first-class deliverables for reliable AI code assistance
A working prompt library is the main event, not an appendix. The industry still treats prompts as some half-baked spitball left in a README, or, worse, a plaintext blob stapled to package.json and forgotten. That's a waste of compute and credibility. What powers reliable AI-assisted refactoring, onboarding, or even next-gen code IDEs is not the size of the model but the clarity and context supplied by the actual, shipped prompt set. OTF kits turn this lesson into a repeatable deliverable: every paid template includes 20+ production-tested prompts tied to the real file structure, component API, and product-specific conventions. This is not a suggestion; it's structural. The takeaway: a real prompt library is as important as your component library. Treat it like one. Start with the pain: why blank chat boxes don't scale The web is full of “integrations” that paste a blank chat input over your codebase and call it an “AI coding assistant.” The result: hallucinated function names, invented conventions, broken import paths. Here’s what happens in real life: Dev: "Add a social login button." AI (blank prompt): "Sure! Insert <SocialLoginButton> in your LoginScreen.js." Dev: (There’s no such component. There's not even a LoginScreen.js.) Short: A generic prompt with zero context simply can't know your conventions, files, or patterns. The agent will either fail, hallucinate, or pepper you with clarifying questions you have already answered in your product architecture. Takeaway: Prompting without context is coding without types — fragile guesses instead of structured outcomes. What a first-class prompt library enables When the prompt library ships with the codebase, it looks like this: Every prompt knows the folder structure (e.g., features/auth , screens/Settings/index.tsx ). Conventions are hard-coded: naming, import styles, design token usage. Endpoints and integration points (e.g., “update the Stripe webhook handler in api/webhooks/stripe.ts ”) are spelled out. The promp
AI 资讯
A Few Months Ago, Agentic Development Felt Overwhelming
A few months ago, I was overwhelmed by everything happening in AI. Every week there was a new coding assistant, a new workflow, or someone claiming they built an app in just a few hours. It felt like if you weren't keeping up, you'd be left behind. I tried almost everything. Cursor. ChatGPT. Claude Code. Lovable. At first, I kept switching between tools, hoping one of them would magically make me a better developer. It didn't. The biggest lesson I learned wasn't about choosing the best AI tool. It was learning how to work with AI. These days, I don't start by asking AI to write code. I start by explaining the problem. I describe the feature, the business requirements, the edge cases, and what I want the final result to look like. Sometimes I ask ChatGPT to help me plan the implementation first. Once everything is clear, I pass that plan to an agentic coding assistant and start building. That one change made a huge difference. I spend less time writing boilerplate and more time thinking about architecture, user experience, and solving the actual problem. AI still gets things wrong, so I review everything before it goes into production. But instead of writing every single line myself, I'm guiding the process. Looking back, the first few months were the hardest. Now it just feels normal. The tools will keep changing, but I think the real skill is learning how to communicate with AI and use it as part of your development process. That's something worth investing in.
AI 资讯
After 12 Years of Programming, I Realized I Don’t Love Coding
I’ve been a software engineer for more than 12 years. And like many developers, I’ve been watching AI improve at an incredible speed. Every new model seems smarter than the one before it. Tasks that used to take hours can now be done in minutes. Problems that required deep research can often be solved with a simple prompt. A few years ago, we used to say: Think of AI as a junior developer. That made sense at the time. But today, I don’t think that’s true anymore. AI still makes mistakes. Sometimes very obvious ones. But it also comes up with solutions that surprise me. Sometimes it finds an approach I wouldn’t have thought of immediately. Sometimes it helps me solve a problem much faster than I could on my own. And honestly, that’s both exciting and a little scary. But the biggest thing AI changed wasn’t how I write software. It changed how I think about my work. For most of my career, I thought I loved writing code. I spent years doing it. At work, on side projects, and whenever I had free time. Then AI became part of my daily workflow. In the last month, I’ve built more projects than I normally would in an entire year. Ideas that had been sitting in my notes for years suddenly became possible. And that’s when I realized something important: I don’t actually love writing code. I love building things. I love taking an idea and turning it into something real. I love creating products, solving problems, and seeing something that only existed in my head become something people can use. Code was simply the tool I used to do that. And now AI is another tool. That’s why I don’t hate it. In many ways, AI has helped me build more than ever before. It helped me revisit old ideas that I never had time to work on. It helped me experiment faster. It even encouraged me to explore areas outside software development, like animation and content creation. And this isn’t just happening to programmers. AI is changing design. It’s changing writing. It’s changing marketing. It’s changin
AI 资讯
AI Can Write the Code. Who Gives It the Context?
When you talk to ChatGPT about a subject you understand well, you quickly notice something. The first answer is rarely the final answer. You add context. You correct an assumption. You explain what has already been tried. You point out that one proposed solution conflicts with another part of the system. After a few iterations, the answer becomes useful. The same thing happens when AI writes code for real products. The difference is that a slightly incorrect explanation in a chat is usually harmless. Slightly incorrect code can become part of your product, pass a superficial review, and remain there for years. This is why successful AI adoption in software engineering is not primarily about generating more code. It is about context engineering : giving AI enough context, constraints, and feedback to generate code that belongs in your system. The First Answer Is Usually Not Enough AI coding tools are very good at producing plausible solutions. That word matters: plausible. The code may compile. The tests may pass. The implementation may even look clean when reviewed in isolation. But software does not exist in isolation. A change must fit the broader system architecture : the current architecture existing domain rules security requirements operational constraints established conventions previous technical decisions future product direction An AI assistant does not automatically understand those things. It knows the code it can see and the engineering context you provide. Everything outside that window must be inferred. And inference is where divergence begins. If you trust the first response without validating its assumptions, you are usually not accelerating engineering. You are accelerating uncertainty. Lack of Context Creates Duplication One of the first visible effects is duplication. AI does not necessarily know that your application already has: a validation helper for the same domain rule an established authorization pattern a shared API client a retry mechani
AI 资讯
Mastering Design Principles: Dependency Inversion in Kotlin
Abstract In modern software engineering, writing code that simply "works" is only the first step. The real challenge lies in designing systems that are maintainable, scalable, and easy to test. This article explores the Dependency Inversion Principle (DIP), the final pillar of the SOLID design principles. Through a practical, real-world example in Kotlin, we will demonstrate how to transition from a tightly coupled architecture to an abstraction-based design. This shift dramatically improves our codebase, facilitates unit testing, and prepares our applications for future growth. Introduction: The Chaos of Coupling As applications grow, it is common to see how a minor change in a database schema or a third-party API triggers a domino effect, breaking unrelated parts of the system. This fragility is a direct consequence of tight coupling. Software design principles, particularly SOLID, were established to prevent this architectural decay. Today, we focus on the "D" in SOLID: the Dependency Inversion Principle (DIP). This principle establishes two core rules: High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces). Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions. The Scenario: An E-commerce Payment Processor Imagine you are building the billing system for an online store. To process purchases, the system needs to connect to a payment gateway, such as PayPal. The Bad Way: Tight Coupling (Violating DIP) In this initial design, our high-level business logic (OrderProcessor) directly instantiates and depends on the concrete low-level class (PayPalService). // Low-level component (Concrete detail) class PayPalService { fun executePayment(amount: Double) { println("Processing payment of $$amount via PayPal API.") } } // High-level component (Business logic) class OrderProcessor { // Tight coupling: this class depends directly on a concrete implementation private val
AI 资讯
Your Nouns Are Not Your Architecture
A common way to design an application is to begin with its nouns: User Product Order Payment Then each noun receives the standard architectural starter pack: UserController UserService UserRepository The controller receives users, the service services them, and the repository stores them somewhere responsible. This is noun-oriented architecture : treating every important thing in the domain as if it were automatically a useful software boundary. It works for simple CRUD systems. Unfortunately, most applications eventually do something. The noun becomes a drawer Consider a typical UserService : register() findByEmail() resetPassword() changeAddress() disableAccount() mergeAccounts() assignRole() calculateDiscount() These operations all involve a user. That is approximately where their similarity ends. They have different rules, dependencies, side effects, security concerns, owners, and reasons to change. They live together because User was the nearest available noun when the folders were created. As more behaviour accumulates, UserService becomes the official location for anything vaguely user-shaped. Other components depend on it. It gradually depends on authentication, email, permissions, billing, auditing, and several services added during incidents nobody wishes to revisit. The noun becomes both a dependency of everything and a consumer of everything. The folder remains impressively tidy. Name the capability, not the material A better starting question is not: What things exist in this system? It is: What must this system be capable of doing? That leads to components such as: UserRegistrar PasswordResetter AccountMerger OrderPlacer PaymentRefunder SubscriptionCanceller These are agentive names . They name the component responsible for performing a capability. Compare: UserService with: PasswordResetter UserService tells us which noun is nearby. PasswordResetter tells us what the component is for. That difference produces better architectural questions: What rules