When we talk about being successful with AI-assisted coding, I think it’s easy to focus too much on the “magic” of the AI and forget the fundamentals. But success doesn’t come from just pressing generate. It comes from the same balance we’ve always needed in software: good ideas, the right technologies, and solid practices.
The first part is the idea itself. It’s tempting to throw every half-baked thought at an AI and hope it will shape it into a masterpiece. But that usually leads to messy, disconnected code. A better approach is to move step by step, layering features carefully so that modules fit together naturally. Just like in traditional coding, structure and pacing matter.
The second part is the technology. AI can write React code, for example, but it won’t decide for you whether state should sit inside a component, live in a shared context, or be managed through a dedicated state manager. Understanding those building blocks is what keeps a project performant, secure, and scalable. Without that knowledge, it’s very easy to end up with something fragile.
And then there are best practices. File sizes grow too large if you never pause to split them. APIs can quickly become unmaintainable if you don’t validate authentication properly. Test coverage, error handling, naming conventions — these are the details that separate “something that runs” from “something that lasts.”
There are other pieces too: version control discipline, clear documentation, and thinking about deployment early rather than as an afterthought. All of these add up. AI coding helps us move faster, but it doesn’t replace the craft, it amplifies it. And when we respect both the creativity of the idea and the discipline of the practice, that’s when we start to see real success.
Author: William
Give AI (Code) a chance

On LinkedIn we’re seeing so many posts about vibe coding. Some people are very positive about it, others very negative. One thing that stands out to me is that a lot of the criticism comes from expecting vibe coding to solve the hardest, most obscure parts of programming. But why would we expect AI to already be able to tackle the trickiest computer science challenges?
Medicine began thousands of years ago, but we didn’t expect heart surgery right away. Engineering has been around for centuries, but skyscrapers came much later. Programming languages are only a few decades old, and it took time before we had web sockets and modern encryption. Even space flight started more than fifty years ago, yet we’re still not on Mars.
But what it can do is amazing. We can already spin up entire websites from scratch, generate BI dashboards that pull together complex data, or scaffold API backends in minutes. It helps with testing, boilerplate code, documentation, and even brainstorming design ideas. These are all the kinds of tasks that normally take up time and energy, and now we can shift more of that effort into creative problem-solving. The fact that AI can reliably handle this level of work today is not a limitation—it’s progress worth celebrating.
So maybe we need to give AI the same patience. Instead of demanding that it solve the hardest coding problems right now, let’s allow it the years it needs to grow. Just as doctors needed centuries before achieving successful heart transplants, AI will need time to mature before we can expect it to handle the deepest corners of our code.
We can “Just rewrite it” now
One of the most surprising benefits of AI-assisted coding is that it finally makes rewriting a project practical.
Back in 1970, Winston W. Royce *, in his paper Managing the Development of Large Software Systems, suggested that the only way to build a great application is to write it twice. As he put it, “arrange matters so that the version finally delivered to the customer for operational deployment is actually the second version.”
The first pass teaches you what really works and what doesn’t. The second pass is when you get it right. In the past, rewriting a full project was too expensive and time-consuming, so most teams just pushed forward with whatever they had. But with AI code generation, we can now revisit the same idea multiple times without months of extra effort, refining it each time until it’s something truly solid.
It’s like old wisdom finally caught up with the tools we have today.
* Winston W. Royce, Managing the Development of Large Software Systems is usually seen as the origin of the Waterfall method of Software Engineering
It’s about knowing what can be done

I’ve seen quite a few posts lately talking about how important context is when using AI to code. I couldn’t agree more. For me, vibe coding isn’t about asking the AI what to code, it’s about explaining what we want to achieve. It reminds me of something I heard years ago—programming is less about knowing how to do something and more about knowing what can be done.
As a senior developer, I’ve built up a strong understanding of the tools at my disposal—React, REST APIs, SQL, and many others. I also know what I want to achieve with the products I’m developing. When I bring that knowledge into the conversation with AI, I can guide it in the right direction and ensure the tools are being used correctly. That combination feels like a genuine superpower.
I wouldn’t claim that AI makes me ten times faster, but it has changed the way I work. I’m now able to deliver far more value in the same amount of time. That shift in output and focus is where the real impact or AI Coding/Vibe coding lies.
Start Simple!

When we talk about software architecture, it’s easy to get lost in diagrams full of boxes, arrows, and buzzwords. But for most startup projects, the foundation doesn’t need to be complicated.
At its simplest, you need three layers. The front end, where users interact with your product. The back end, which includes authentication and the business logic that powers the experience. And the database, where the information lives. That’s enough to get started and build something meaningful.
And here’s the exciting part: today we can vibe code across all of these layers. Tools like Bolt.new make it quick to spin up front ends. ChatGPT or GitHub Copilot can help shape the back end and authentication logic. They can even guide you through setting up and querying your database. Beyond those, there’s a growing world of AI tools that can fit in wherever you need them.
You don’t need queues, event buses, or complex logging right away. Keep it simple, focus on delivering value, and let these tools accelerate your progress. The sophistication can always come later—when your product, team, and users are ready for it.
Vibe Coding is about Best Practices
The first part is the idea itself. It’s tempting to throw every half-baked thought at an AI and hope it will shape it into a masterpiece. But that usually leads to messy, disconnected code. A better approach is to move step by step, layering features carefully so that modules fit together naturally. Just like in traditional coding, structure and pacing matter.
The second part is the technology. AI can write React code, for example, but it won’t decide for you whether state should sit inside a component, live in a shared context, or be managed through a dedicated state manager. Understanding those building blocks is what keeps a project performant, secure, and scalable. Without that knowledge, it’s very easy to end up with something fragile.
And then there are best practices. File sizes grow too large if you never pause to split them. APIs can quickly become unmaintainable if you don’t validate authentication properly. Test coverage, error handling, naming conventions — these are the details that separate “something that runs” from “something that lasts.”
There are other pieces too: version control discipline, clear documentation, and thinking about deployment early rather than as an afterthought. All of these add up. AI coding helps us move faster, but it doesn’t replace the craft, it amplifies it. And when we respect both the creativity of the idea and the discipline of the practice, that’s when we start to see real success.
Design Patterns in React
Introduction
I am a software engineer. I love coding, and I know how to code—I’m actually quite good at it. I know how to code and I use most design patterns automatically, but I honestly do not know what they are called (with a few exceptions).
Here are some common design patterns explained with React code:
Singleton Pattern
Ensures a class has only one instance.
Example in React: A global state management instance (e.g., Redux store, Context API provider).
const StoreSingleton = (function () {
let instance;
function createInstance() {
return { user: null, theme: "dark" };
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
},
};
})();
const store = StoreSingleton.getInstance();
Factory Pattern
Creates objects without specifying the class.
Example in React: Dynamic component rendering based on props.
const ButtonFactory = ({ type, label }) => {
const components = {
primary: (label) => <button className="btn btn-primary">{label}</button>,
secondary: (label) => <button className="btn btn-secondary">{label}</button>,
};
return components[type] ? components[type](label) : <button>{label}</button>;
};
// Usage
<ButtonFactory type="primary" label="Click Me" />;
Observer Pattern
Notifies dependent objects when one changes.
Example in React: Event listeners, pub-sub mechanism, React Context API.
import { useState, useEffect } from "react";
const eventListeners = new Set();
const subscribe = (listener) => eventListeners.add(listener);
const unsubscribe = (listener) => eventListeners.delete(listener);
const notifyAll = (data) => eventListeners.forEach((listener) => listener(data));
const useNotification = () => {
const [message, setMessage] = useState(null);
useEffect(() => {
const listener = (data) => setMessage(data);
subscribe(listener);
return () => unsubscribe(listener);
}, []);
return message;
};
// Usage
const NotificationDisplay = () => {
const message = useNotification();
return message ? <p>{message}</p> : null;
};
Decorator Pattern
Dynamically adds features without modifying core code.
Example in React: Higher-Order Components (HOCs) & Custom Hooks.
const withLogging = (WrappedComponent) => {
return (props) => {
console.log("Component Rendered:", WrappedComponent.name);
return <WrappedComponent {...props} />;
};
};
const Button = (props) => <button {...props}>{props.label}</button>;
const LoggedButton = withLogging(Button);
// Usage
<LoggedButton label="Click Me" />;
Adapter Pattern
Converts incompatible interfaces for seamless interaction.
Example in React: Converting an API response to match UI needs.
const legacyAPIResponse = { fname: "John", lname: "Doe" };
const adaptUser = (data) => ({
firstName: data.fname,
lastName: data.lname,
});
const UserProfile = ({ user }) => {
const adaptedUser = adaptUser(user);
return <p>{adaptedUser.firstName} {adaptedUser.lastName}</p>;
};
// Usage
<UserProfile user={legacyAPIResponse} />;
Strategy Pattern
Encapsulates algorithms for flexible swapping.
Example in React: Using different sorting algorithms in a table component.
const strategies = {
ascending: (arr) => [...arr].sort(),
descending: (arr) => [...arr].sort().reverse(),
};
const SortableList = ({ items, strategy }) => {
const sortedItems = strategies[strategy](items);
return <ul>{sortedItems.map((item) => <li key={item}>{item}</li>)}</ul>;
};
// Usage
<SortableList items={["Banana", "Apple", "Cherry"]} strategy="ascending" />;
Command Pattern
Wraps requests as objects to allow undo/redo.
Example in React: Undo/redo for a text editor.
import { useState } from "react";
const useCommand = () => {
const [history, setHistory] = useState([]);
const [index, setIndex] = useState(-1);
const execute = (command) => {
const newHistory = history.slice(0, index + 1);
newHistory.push(command);
setHistory(newHistory);
setIndex(newHistory.length - 1);
return command.execute();
};
const undo = () => {
if (index >= 0) {
const command = history[index];
setIndex(index - 1);
return command.undo();
}
};
return { execute, undo };
};
Composite Pattern
Treats objects and compositions the same way.
Example in React: Recursive component rendering.
const Comment = ({ text, replies }) => (
<div>
<p>{text}</p>
{replies && replies.map((reply, i) => <Comment key={i} {...reply} />)}
</div>
);
Conclusion
I use most of these design patterns daily—but I don’t know what they are called. I know I don’t like a services pattern (oh sorry, the Facade pattern) as I like keeping all my fetching code together in my Context. Though, to be honest, I am starting to wonder why.
Why Are We Still Using CVs in 2025? AI Can Do Better
In a world where AI can write essays, generate code, and even hold conversations, why am I still manually sending my CV to apply for jobs? The traditional recruitment process—where a job is posted, recruiters screen candidates, and job seekers send applications—feels outdated and inefficient.
Let’s be honest: companies already struggle with an overwhelming number of applications, and job seekers waste hours tweaking resumes and searching for roles that match their skills. But what if AI could eliminate this manual back-and-forth entirely?
The AI-Powered Hiring Solution
Imagine a platform where companies upload a job description, and AI automatically extracts key requirements—skills, experience, and qualifications. On the other side, candidates upload their CVs, and AI instantly matches them to relevant job postings. Instead of job seekers manually searching through thousands of ads, AI alerts recruiters when a highly matched candidate appears.
Why This is Better for Everyone
✅ For Job Seekers: No more hours spent on job boards. You simply upload your details, and AI ensures your profile gets seen by the right employers.
✅ For Recruiters: Instead of filtering through endless applications, AI presents only the most relevant candidates, speeding up hiring decisions.
✅ For Companies: A streamlined, data-driven hiring process that reduces hiring costs and ensures better role-fit candidates.
Is This a New SaaS Opportunity?
The more I think about it, the more it feels like AI is ready to disrupt the hiring process entirely. Instead of companies and candidates spending countless hours searching for each other, why not let AI handle the matchmaking?
This could be built as a SaaS platform that integrates with job boards and applicant tracking systems, making hiring faster, smarter, and more efficient.
The question is—who’s already working on this? And if no one has done it right, maybe it’s time to build it.
My frustrations with my AI Buddies

Using AI code generation tools can feel like having a supercharged assistant—they can quickly draft code snippets, suggest solutions, and even build entire components. But as helpful as they are, I’ve found some frustrating limitations that often slow me down rather than speed me up.
One of the biggest issues I run into is that AI tools can’t remember my personal coding style. Every developer has their own way of structuring code, naming variables, and organizing logic. I might prefer concise functions or certain design patterns, but AI generators typically offer generic solutions that don’t align with how I like to write code. This means I often spend extra time rewriting or tweaking the output to match my style, which defeats the purpose of using these tools for efficiency.
Another pain point is that AI tools don’t remember which frameworks or CSS libraries I’m using. If I’ve chosen React with Tailwind CSS for a project, the AI might still suggest solutions using plain CSS or even other frameworks entirely. It’s frustrating to constantly correct the suggestions, reminding the tool that I’ve already made specific technology choices. This disconnect slows down development and forces me to double-check everything for compatibility.
I also like using the Context API in React, particularly putting fetch calls directly in the Provider for better encapsulation and centralized data management. However, AI often suggests creating standalone service files instead, which doesn’t align with my approach. This mismatch forces me to rewrite the AI-generated code to fit my preferred architecture.
Then there’s the issue of file organization. I like to use a feature-based folder structure, keeping related components, hooks, and utilities together. But AI tools have no sense of where files should go. They’ll suggest creating a new file but won’t place it in the right folder or follow my project’s organization pattern. This leads to a messy file structure that I have to clean up manually, making the process more cumbersome.
Overall, while AI code generation has a lot of potential, it lacks the memory and context needed to be truly helpful. Without the ability to learn and adapt to my style, tools, and project structure, it often creates more work than it saves. Until these tools can bridge that gap, they’ll remain more of a novelty than a reliable development partner.
My AI Buddies

Generative AI has completely changed how I approach software development. From writing snippets of code to automating repetitive tasks, these AI tools have become my go-to partners in the coding process. Today, I want to share how three of my favorite AI agents—GitHub CoPilot, Cline, and Bolt—have enhanced my workflow.
My Experience with GitHub CoPilot in VS Code
GitHub CoPilot, developed by GitHub and OpenAI, has been a game-changer for me. Integrated seamlessly into Visual Studio Code, it feels like having a helpful coding buddy suggesting lines of code and even entire functions as I type. Whether I’m working with PHP or React, CoPilot provides intelligent, context-aware recommendations that save me time and help me break through coding blocks. It’s especially handy for automating boilerplate code and exploring new frameworks or libraries without needing to constantly check documentation.
How Cline in VS Code Simplifies My Workflow
Cline is another AI-powered tool that has made coding more intuitive for me. While CoPilot helps by suggesting code, Cline enhances my development workflow by offering smarter interactions directly within VS Code. I can ask Cline to do something in a code file using English, and it can run complex terminal commands, navigate my file system, and automate build processes. This has been a huge help in bridging the gap between coding and command-line tasks, allowing me to stay focused on building instead of getting stuck on syntax-heavy commands.
Why I Love Using Bolt.new and Bolt.diy
Bolt has been a fantastic addition to my toolkit, with its two products: Bolt.new and Bolt.diy. Bolt is all about rapid prototyping. I can have an idea for a web app and turn it into a working prototype in minutes. It generates functional codebases, user interfaces, and basic logic structures, Bolt.diy van even import an existing codebase and I can tell it to add features or make modifications. It strikes the perfect balance between automation and creative control for me.
Bringing It All Together
Each of these AI tools brings something unique to my workflow:
- CoPilot boosts my productivity by suggesting relevant code in real-time.
- Cline streamlines command-line tasks, making my development process smoother.
- Bolt helps me accelerate prototyping and custom development with smart automation.
By integrating these tools into my daily work, I’ve been able to cut down on development time, dive into new technologies more easily, and focus on solving complex problems instead of getting stuck in routine tasks. Whether you’re a seasoned developer or just starting out, these generative AI agents could become your new favorite coding companions.
I truly believe the future of coding is more collaborative, with AI working alongside us to unlock greater creativity and efficiency. It’s an exciting time to be part of the software development world!
Have you tried any of these tools yet? I’d love to hear how they’re working for you!