For the Love of Programming in the Age of AI

Introduction: Learning the Hard Way
I remember my first computer program back in 2010 when I was in high school. It was through lessons we took in computer class about the Logo programming language. I used to look forward to that computer class. It was my favorite class after science and physics.
I still remember the Logo commands: raising the pen, changing colors, moving the turtle forward and backward. Also it was my first introduction to the power of looping, which allowed us to draw geometric art. Squares, triangles, spirals, and intricate patterns that would have been tedious to code line by line without loops. I used to get excited when I was able to draw a unique and somehow symmetric shape that looked good. I’d share the code with my friends like a secret recipe.
Almost a year later, in PAAET, my professor would ask us to first write programs line by line on a piece of paper. We used to debug, trace, and memorize every command, reserved keyword, and import statement. This practice helped us develop strong memory and build standards and discipline that would serve us throughout our careers.
The IDE back then wouldn’t hold your hand that much. My first true programming language was Pascal, and we used Turbo Pascal as our development environment. I remember when everyone was learning ASP.NET with VB, and I asked my professor Mr. Waleed where Pascal was being used in Kuwait. His answer shocked me: “It’s used by Kuwait Flour Mills factories.” My follow-up question was, why should we learn it then? He answered that building strong fundamentals matters more than the language itself. That statement stuck with me and it holds true until today.
Part I: The Human Side of Programming
Learning from People, Not Just Languages
My first language was Pascal, and my first IDE was Turbo Pascal. My professor Mr. Waleed was an amazing person. When I remember this language, I remember him—his patience, his wisdom, his dedication to ensuring we truly understood the fundamentals.
The same goes for C++. When I remember C++, I remember my professor Mr. Mohammed and his methodical approach to teaching object-oriented principles. Our capstone project was to build a banking terminal application that can be used to withdraw and deposit money using a simple text file as a database. When I think of C and C++, I remember my Cambodian friend in PAAET, Rohim, who loved C++ and cryptography with such passion that it was infectious. His enthusiasm really used to inspire me.
When I remember C#, I remember Bob Tabor. So many hours I spent learning C# and OOP through his online tutorials. His teaching style made complex concepts accessible, and he sparked my interest in building desktop and web applications.
When I remember JavaScript, I remember a Gatsby project that I inherited from a senior developer from India. It forced me to learn the MERN stack the hard way. I basically became friends with this person without actually meeting him. I had to read his code, understand the logic behind it, and decipher his architectural decisions, as he was no longer available to help with the project. That experience taught me more about code quality and documentation than any tutorial ever could.
When I remember SQL, I remember Mohd. Ismaeil, a senior database administrator who made me fall in love with SQL and appreciate the value and the role a database plays in every modern system. He showed me that a database is not just a bucket to drop your data in; there are stories to be told, and querying is an art form.
When I remember Python, oddly enough, I remember the first time I saw a colleague use it and talk about it in a presentation about open source tools. Back then, we used to have meetups for GDG in Kuwait. At that time, Python was getting popular for building websites with Django. That presentation opened my eyes to the elegance of Python’s syntax and the power of its ecosystem.
These languages stuck with me the most throughout my life because I learned them from people I spent hours with. People who cared, who mentored, who challenged me. This kind of learning is emotional; it creates connections that transcend mere technical knowledge.
Programming languages are just tools, but the people who teach us how to use them become part of our story. They shape not just what we know, but how we think, how we approach problems, and ultimately, who we become as developers.
Every line of code I write carries echoes of these mentors, friends, and colleagues.
The Parallel Between Writing and Programming
One of the things that still amazes me to this day is how programs, mere 1s and 0s, can create immense value out of thin air. The barrier to entry is remarkably low: a laptop, a compiler, and an open mind. With just these three things, you can build a game that brings joy to thousands, a website that connects communities, a desktop application that solves real-world problems, a banking system that moves billions, a blog that changes perspectives, or a calculator that makes someone’s day a little easier. You are only limited by your imagination and your willingness to create.
This purity of creation is something programming shares with writing. Both demand that you think deeply and logically about what you’re crafting. In programming, you’re solving problems through code; in writing, you’re relaying ideas through narrative and storytelling. Both require clarity of thought, structure, and the ability to communicate complex ideas in ways that others can digest and use.
I remember reaching a point where I started writing more code than English, where I began thinking in functions and loops rather than paragraphs and sentences. Yet, ironically, my foundation in writing prepared me perfectly for this transition.
Back in my high school years, during 11th and 12th grade, I had two amazing English teachers who helped me fall in love with the English language. I feel sad that I can’t recall their names, but I remember their impact vividly. They taught me how to construct arguments, how to organize thoughts, how to revise and refine until something clicked. I used to love reading comprehension questions in exams! It helped me develop critical thinking and the ability to find conclusions out of paragraphs. This made me immerse myself in reading books, listening to podcasts, watching films—anything basically related to this language.
That foundation in English served me tremendously when I transitioned into my IT career. The strong foundation in English, the previous interest in programming and my love for writing taught me how to read documentation, better understand and debug errors, how to write resolutions to support tickets, and how to communicate technical concepts clearly to my colleagues. Programming taught me that creation isn’t magic—it’s a process of iteration, and how to break complex ideas into manageable pieces to drive towards a certain conclusion.
Part II: The State of Flow
What Is Flow?
There is a transcendent state that programmers enter when the world outside the screen begins to fade. A moment where the friction between thought and syntax vanishes. This is “the Zone,” an experience that every developer knows and chases. If you ever used to Google programming music, then you know that feeling.
In this state, complex solutions aren’t something you’re “working on”; they become extensions of your own mind. The joy isn’t just in the final result, but in the sheer momentum of solving one puzzle after another in a continuous, rhythmic stream, almost like playing a musical instrument, where muscle memory and creative thinking merge into something enjoyable. It’s a rare form of cognitive harmony where time distorts, distractions disappear, and for a few hours, you’re not just a person typing at a keyboard, but a conductor orchestrating a pure, logical symphony.
This psychological state is famously explored by Mihaly in his book, Flow: The Psychology of Optimal Experience. He describes it as:
“being so involved in an activity that nothing else seems to matter; the experience itself is so enjoyable that people will do it even at great cost, for the sheer sake of doing it.”
Flow occurs when the challenge perfectly matches your skill level; difficult enough to demand full concentration, but not so hard that it causes anxiety.
For decades, programming has been one of the most reliable pathways for me to this state. A state that I’m addicted to. The struggle of debugging, the satisfaction of refactoring messy code into elegant solutions, taking care of spaces and tabs, naming every function and variable carefully, taking care of small details in the UI here and there that others won’t even notice, the cognitive load of holding an entire system architecture in your mind, it is so wonderful of a feeling.
Why Craftsmanship Matters
You might argue that programming is simply a means to an end. A tool we use to build and solve problems nothing more nothing less. But I dare to disagree, programming is and will remain an art form. A design problem and a way to create a software to help others. A practice of empathy and an extension of one’s ability to solve and understand problems in a systematic way.
With time I came to understand that true value comes from creating a tailored solution. It’s like the difference between buying a dishdasha from a store versus going to a tailor to have one custom-made. Sure, the store-bought one is faster to obtain, cheaper and mover available. But the tailored dishdasha? It fits your exact measurements, accommodates your preferences, reflects your style, and complement your body, it will make you look and feel exceptional. It’s crafted specifically for you, with attention to details that matter to you personally.
That’s what programming should be—the art of crafting solutions that fit the exact contours of a problem, not just picking the closest generic option off the shelf.
Every project I’ve worked on is a story to be told—a narrative of challenges faced, decisions made, trade-offs considered, and problems solved in ways that were unique to that moment and that context. It’s not just a generic solution dropped on the client’s desk. It’s a journey of understanding their specific needs, their constraints, their vision.
Each project carries the fingerprints of the developer who built it: the late nights spent refactoring, the eureka moments that led to elegant solutions, the mistakes that taught valuable lessons. When you build something with your own hands and mind, you can explain every choice, every line of code, every architectural decision. It’s yours in a way that an AI-generated solution never can be. That ownership, that intimate knowledge of what you’ve created—that’s what makes the work meaningful.
Part III: The AI Disruption
How AI Interrupts Flow
But something fundamental is shifting. AI coding assistants—tools like GitHub Copilot (the tool I use the most) are transforming how we write code. On the surface, this seems entirely positive: increased productivity, fewer syntax errors, faster prototyping. And indeed, these benefits are real.
Yet there’s a hidden cost that we’re only beginning to understand: AI is preventing us from entering flow state, which in turn makes programming as a whole less enjoyable.
Here’s the paradox: to craft something truly tailored, you need to enter that deep state of concentration where you understand every seam, every measurement, every detail. You need to be fully present in the work, thinking through each decision with care and intention. The artist can’t create a masterpiece while constantly being interrupted or while someone else is suggesting what should happen next.
And that’s precisely where AI is changing—and potentially diminishing—the programming experience.
Modern AI coding assistance creates constant micro interruptions to that immersion. Instead of thinking deeply about how to solve a problem and actually strategizing about what to do next, we’re constantly evaluating suggestions, accepting or rejecting auto-completions, and offloading our thinking to AI-generated code snippets. Each suggestion, even helpful ones, breaks the continuous stream of thought that flow demands.
I remember recently a friend told me, “Let AI Model X create a plan and AI Model Y implement it and AI Model Z revise it.” I nodded in agreement, but deep inside I felt: “What is the point then?”
Why are we rushing? Who exactly are we racing against? What are we buying time for?
If we outsource all the thinking, the choices, the struggle and the creative problem-solving, the very essence of what makes programming intellectually fulfilling, what’s left for us? Speed without purpose, efficiency without satisfaction, output without growth.
The Loss of Appreciation
It’s the difference between composing original music with struggle and purpose or using pre-made loops and stitching them together in Audacity. Both create songs, but only one builds the deep neural pathways that come from sustained creative effort.
I’m not saying that one approach is bad and one is good. I’m saying that we no longer appreciate things enough. Everything feels cheaper because of AI. When everything becomes effortless, nothing feels earned. When every answer arrives instantly, discovery loses its sweetness. I don’t visit stack overflow that much anymore. I don’t spend time reading documentation like I used to. The satisfaction of solving a hard problem after hours of struggle—that profound sense of accomplishment—is being stolen by the hollow efficiency of prompting and accepting provided by AI.
We’re trading the joy of mastery for the convenience of delegation, and in the process, we’re losing something irreplaceable: the pride of truly understanding what we’ve built.
The Atrophy of Problem-Solving Skills
There’s something more concerning happening beneath the surface on a global scale. When you struggle with a problem for hours—truly struggle, hitting dead ends, refactoring, rethinking your approach—you’re not just solving that specific problem. You’re building robust mental models, strengthening your debugging intuition, and deepening your understanding of the entire system. The struggle is the learning.
AI assistance, by providing instant answers, shortcuts this struggle. It’s like using a calculator for every math problem in school—you get correct answers quickly, but you never develop the mental math intuition that makes you a better mathematician. You’re solving problems, but you’re not necessarily becoming a better problem solver.
I notice this in myself. When I have an AI assistant enabled, I find myself reaching for it reflexively, even for problems I could solve on my own given a few minutes of thought. That reflex—that immediate outsourcing of cognitive effort—is slowly eroding the very skills that make programming satisfying for me. The “Aha!” moments become less frequent because I never give myself the chance to arrive at them naturally.
The Future Generation at Risk
But what worries me even more is the future generation of developers—the junior developers just starting their careers. I had the privilege of learning the hard way: writing code on paper, debugging without powerful IDEs, wrestling with problems until I truly understood them. Those struggles built my foundation.
But junior developers today are entering a world where AI can write entire functions, suggest complete implementations, and solve problems before they’ve had a chance to think deeply about them. They’re being robbed of the struggle that creates mastery. How can they develop strong fundamentals if they never experience the friction that builds understanding? How will they debug complex systems if they’ve never truly had to trace through logic step by step?
We might be creating a generation of developers who can prompt AI effectively but can’t think, who can stitch together solutions but can’t architect them from first principles. That’s a terrifying prospect for the future of software engineering.
Part IV: Finding Balance
Being Intentional with AI
I’m not advocating for abandoning AI tools entirely, that would be as unsensible as refusing to use an IDE or a debugger. These tools, unfortunately, are here to stay. It is a love and hate relationship. Those tools do provide a genuine value anc will help us build much faster with more accuracy. It feels like a privilege that senior senior developers have earned. But we need to be intentional about when and how we use them.
For example, recently I had a project where I needed to use MUI, a UI framework for React. I’ve used ant design before but never MUI. AI helped me actually grasp the ins and outs of that framework much faster. But that’s the catch: because I’ve used React and a similar UI framework extensively before, I was able to grasp those concepts much easier and build on an understanding that I cultivated over years of practice.
For me personally, I turn off autocomplete altogether and use AI mostly to refactor or build UI boilerplate. Whenever there is a CRUD pattern that needs to be implemented, I just let AI do it as there is nothing new to be learned there. I try to use “Ask” first in Copilot before resorting to “Agent” and “Edit.” “Plan” is very good whenever I’m starting a project from scratch.
A Path Forward
The answer is to designate “deep work” sessions where AI assistance is turned off completely, allowing ourselves to struggle and enter flow state. Use AI for the tedious parts—boilerplate code, API documentation lookup, syntax conversion, but preserve the challenging, creative problem-solving for unaugmented human thought.
The programmers who thrive in the coming decades won’t be those who can prompt AI most effectively. They’ll be the ones who know when not to use AI in my opinion. You are still responsible of the code that AI creates after all.. no one will go ask Claude why you repeated the same function in five separate files. Those who can still enter deep flow states, who have built robust mental models through genuine struggle, and who understand their code at a fundamental level because they’ve wrestled with it rather than merely accepting it.
Another important factor that will have an impact on programming is domain expertise. I love the education sector and academia in general (although I hate how commercial research is becoming). This helps me be creative and come up with ideas and patterns that I’ve observed over the years. Whether I am building a student management system or a digital classroom interface, cloud labs, I am applying the same discipline I learned back in those blue Turbo Pascal screens.
When we pair deep domain expertise, the craftsmanship of code and the assistance of AI, we stop being mere “coders” and become architects and philosophical builders.