The World Inside Out, or How to Be a Programmer and Not Write Code
Konstantin Khait
2025
Misunderstood interlocutor
To tell the truth, I did not want to write these chapters. In a world where, in just a few years, communication with robots has supplanted interaction with the closest people to such an extent that it is frightening to imagine, teaching anyone to use text neural network tools is a monkey’s job. Worse than that, bad taste bordering on ethical suicide. Indeed, if not so long ago all sorts of coaches, mentors, advisors, and consultants were rightly considered charlatans and expelled from decent society, now the “great art of prompting” is taught almost in universities. Often by the same people who previously taught us to become rich and successful, often lacking any technical education or even personal experience with neural networks. Their sudden “expertise” is based on the eternal triad: the triviality of the subject taught, incredible aplomb, and the learned helplessness of the audience. An audience that could quite possibly master this very “prompting” without any mediation from high-minded teachers who have watched videos and, I cannot guarantee, perhaps even read a thick book about large linguistic models and picked up a few smart terms from there. Voluntarily joining the long line of exploiters of human indecision, selling what is available to everyone for free — is tantamount to an admission of fraud. And I would never have gone for it if not for a few of my friends who persistently recommended “starting from the very beginning”.
Actually, this book is not written to explain how to use ChatGPT, Google Gemini, or whatever might replace them by the time you, if you’re lucky, finish reading it. Its goal is to show how tools based on LLM can challenge traditional “algorithmic” (as well as “functional” and other deterministic) programming, and how those of you who do not have coding experience, mathematical and algorithmic training, but possess common sense and systematic thinking, can become programmers, or rather, software product engineers, using this approach, which is significantly underestimated at the present time.
Teaching the use of ChatGPT, in my deep conviction, is as pointless as my grandmother’s attempts to teach me how to use a telephone. This remarkable elderly woman diligently showed her grandson how to turn the rotary dial (yes, I am old enough that the phones of my childhood didn’t have buttons), and the child wondered why spend time on something that is elementary from the very start. It is just as inappropriate to teach my children the art of using a mobile phone when my three-year-old daughter, born, you could say, with a screen in front of her eyes, launches any applications perfectly without any training. And my sons, not yet fully literate, use neural networks for any and all reasons, without the need for any courses or training. Modern tools are such that not only housewives but even infants can handle them just as well as any “professionals”… If we are talking about the everyday tasks of housewives and infants. However, when it comes to solving more complex problems, simplicity turns into confusion and bewilderment. And that is precisely why I will have to start from the very beginning.
Devil machine
The famous Soviet comedian Mikhail Zhvanetsky loved to tell a joke about an American sawmill bought for a Siberian lumber mill. Delighted by the capabilities of the overseas machine, the Soviet workers fed it everything from thin branches to enormous logs, and the miracle of technology successfully handled every task. But the persistent and proud lumberjacks didn’t stop and eventually shoved a rail into the sawmill. The machine broke down, and the workers returned to their usual tools, noting the pathological imperfection of Western technology.
I won’t hide it, my first acquaintance with LLM followed roughly the same pattern. With the persistence of a savage, I loaded the devil-machine with “human” tasks, drawing far-reaching conclusions from its apparent inability to solve them the way I wanted. And only after many months, having worked my brain considerably and experimented with software APIs, did I come to the generally obvious understanding that any thing must be used for its intended purpose.
Alas, many of my acquaintances have not come to this understanding. They laugh when the neural network draws a sixth finger, two tails, writes a recipe for cooking pork wings, or makes mistakes in simple calculations. Although this is about the same as laughing at an orangutan who forgot to tighten a nut when assembling a jet engine, or, even more precisely, at a genius violinist unable to take a double integral. It would be much more appropriate to be impressed that the neural network can, in principle, draw or give coherent answers to complex questions. Especially since the majority of critics themselves are not capable of drawing anything similar, whether with six fingers or with four.
Here we have another example of the paradox of the human psyche: when interacting with something through a simple interface, we tend to forget how complex the thing we are actually operating is. Just like when driving a car, we automatically turn the steering wheel and press the pedals without thinking about the intricate technical solutions embedded in the engine, transmission, and suspension design. And we remember them only at the moment when a failure, malfunction, or complex situation occurs where our skills cease to be sufficient. And then the ability to operate is not enough, and we have to understand the machine.
This is exactly what happens when interacting with ChatGPT. The “messenger” interface is so simple, and the illusion of communicating with a live interlocutor is so evident, that we almost forget who we are dealing with. And we demand reactions and responses from the interlocutor that we would expect from a living person. Moreover, from a person with sky-high intelligence, having access to all the knowledge in the world and capable of processing it at the speed characteristic of computers.
In most cases, our expectations are justified: these tools were created for this very purpose. But expectations are expectations, and in reality, a chat-bot based on a large linguistic model is a tool with its own properties, characteristics, and limitations. And when the task set for it goes beyond acceptable boundaries, we get amusing, idiotic, or simply incorrect answers. This does not mean that the tool itself is bad, but rather that it is not good for someone who stubbornly tries to shove a rail into a sawmill instead of understanding how this sawmill works.
In my observations, the most adequate users of neural networks are managers. I mean managers, good managers: they professionally view subordinates as certain resources, tools, understand the limitations of their capabilities, their responsibility for correctly setting tasks, and know how to not just expect results, but achieve them. For them, communication with LLM — this is a fairly familiar process, and they are less likely than representatives of most other professions to make meaningless complaints and fall victim to unfounded expectations. However, they are also less prone to ridiculous enthusiasm or, conversely, dramatic horror at the future takeover of the world, than impressionable individuals from other industries. After all, any manager has had to deal with people who far surpass them in intelligence, and they know that besides intellectual abilities, there are many other strong points that allow one to control, subordinate, and utilize.
But let’s return to the infernal machine. Here and further, we will talk about text tools based on LLM — large linguistic models. We will not delve into the details of their structure, as there are plenty of thick monographs, lengthy educational videos, and university courses for that. We are quite content with the most basic understanding.
A large linguistic model should not be imagined as a horned devil, a huge brain with an incredible number of convolutions, or a complex mechanism with billions of gears. Personally, I recommend not imagining it at all, even if you are an expert in this field: simply because it is distracting. When driving a car, we do not think about how the flywheel rotates, the pistons move back and forth, and the connecting rods swing. Similarly, there is no point in delving too deeply here. It is enough to imagine a box, IT specialists in such cases say “black box.” Through this box, billions of texts in different languages have been passed. You did not witness the process of “passing,” it is called “training” and was carried out by OpenAI, Google, or someone else who kindly provided you with this model. Millions of dollars, megawatts of electricity, and tens of thousands of hours of work by powerful GPUs, which we still call graphics cards, were spent on it. And we have practically nothing to do with this process.
It is important to us that the neural network, that is, what sits inside the box, does not remember all these texts, but is able to determine the probability, with which a certain set of words will be followed by one or another next word. If you are not sure you understand this phrase, reread it until you do — without it, everything that follows will be empty page-turning. So, the trained neural network knows nothing, understands nothing, makes no conclusions, and has no idea about causes and effects. It is only able to provide the most probable sequences of words following those you submit as your queries. All its “knowledge” and “understanding” are embedded in these very probabilities, nothing more. The main detail, the “engine” of any neural network tool, is extremely simple in its logic. Its intelligence is given by the vast number of accounted connections between words, allowing it to provide relevant answers to most real queries.
However, from this basic structure of LLM also follow limitations.
First of all, the neural network is trained on a specific dataset, and the connections built within it are based on this training sample. This sample for general-purpose networks is taken from the commonly used information environment: the internet and books, and it reflects the knowledge and information available in this environment. The Earth is round, America was discovered by Columbus, killing people is bad, the Sun — is a yellow dwarf, and Plato is a Greek philosopher. Whether you agree with this or not, the connections between words are formed in this way, and without applying special efforts, corresponding questions will yield corresponding answers.
From the nature of neural networks follows their most famous, unpleasant, and often ridiculed property of hallucinating. In response to our queries, LLM provides the most probable, “best” sequence of words — it cannot not provide it — but there are no guarantees of the adequacy of this sequence to what actually exists. If the text array used in training does not allow considering the answer irrelevant, then the neural network has no other ways of such evaluation: it simply has no sensory organs, no “life experience,” “pork wings” mean nothing to it, it has not seen a pig, does not know what it is, and does not even realize the reality in which pigs exist. LLM operates with words, and this phrase turns out to be the most relevant of all possible, that’s all. We will talk about how to deal with this later, but for now, we have to accept the inevitability of hallucinations as such.
For this same reason, neural networks themselves do not know how to count, or more precisely, to calculate. There are quite a few texts that say twice two is four, so to the question “what is twice two” the answer “four” is the most likely. But there are negligibly few texts that would say what the square root of six hundred eighty-five multiplied by one and a half is, and therefore the chances of getting the correct result are also low. There are methods to teach — no, not neural networks, but tools based on them — to count, but initially by their nature, LLMs do not know how to calculate.
It is not a universal knowledge base either, although this is exactly how it is very often attempted to be applied, sometimes successfully, sometimes not. If it concerns some commonly used facts, then with a high probability the connections between the words describing them will be sufficiently “strong” and the answer will be semantically correct. But it is quite possible that there were some similar, “distracting” fragments in the training texts that will pull along inappropriate, inadequate, irrelevant word sequences, and the meaning of the result will be distorted. That’s how I once tormented ChatGPT with questions about Cardinal Richelieu’s brothers.
Using linguistic models to manage knowledge bases and search through them is not only quite possible but also necessary, however, the neural network itself is not such a base. And expecting universal erudition from it is very reckless.
About the Size That Matters
Well, the most well-known and most unpleasant limitation of neural networks — this is, of course, the size of the context. The number of coefficients that account for the probabilities of connections between words in modern LLMs is enormous, which is why they are called “large models,” but still limited. As is the size of the text they can accept as input and generate as output. A chunk of meat, simultaneously shoved into the neural network meat grinder, has a limited size, and it is impossible to pass through it entirely not only a voluminous tome but even a small chapter as of today.
The worst part is that technically this is not a strict limitation. You can feed the model as much data as you want, but the relevance of its responses will rapidly decrease.
Here it is appropriate to mention, finally, that “neural network” in the sense of “large language model” and “tool based on it” — are far from synonyms, although the use of these terms is not always distinguished in practice. LLM is that very box, into which text is input, and from which, roughly speaking, the most likely continuation according to the training data emerges. However, the training data, as we have already discussed, has long been forgotten, we cannot influence it, so the text, in addition to the actual request, must contain additional information necessary to obtain a relevant response in terms of meaning. In dialogue-type tools, this is at least the history: previous user questions and system answers. Besides them, additional data and instructions, hidden from our attention, may be added, the entire array of which is input into the neural network. They can be substantial, or they can concern, for example, issues traditionally related to safety. For instance: “Answer the following question if it does not touch on topics of sex, violence, and child labor exploitation, otherwise write that you cannot help with this request. User question:…”.
The end user does not observe this note, like many others, knows nothing about it, but the result of its interpretation, naturally, dramatically affects the model’s response. Well, the formation of such additional instructions and explanations is essentially the only non-trivial subject of “prompting.” And it makes sense to refer to it as the process of “fine-tuning” the neural network: it is not directly training in the strict sense, since neither the network’s structure nor the weights of its nodes change, but from the perspective of obtaining relevant answers, it is precisely an enrichment of the knowledge possessed not by the LLM itself, but by the tool based on it.
From the inherent limitation of the neural network’s context size, it follows that endlessly increasing instructions to make them more detailed and specific is a dead-end path. Sooner or later, the volume of such text will exceed what the model can “digest” at once, and instead of providing more accurate and adequate output, it will start to hallucinate, ignoring or underinterpreting some instructions. At the same time (and here is its difference from a human), an arbitrary part will be discarded, not the least important one. However, natural intelligence also experiences similar “information overload,” so the main principles and methods of “neural network pedagogy” are generally similar to the principles and methods of traditional pedagogy.
Precise, specific, and unambiguous instructions to some extent save the situation. But only until the volume of data that needs to be processed begins to exceed the capabilities of the neural network itself. After this, the moment comes, for which this book was written, the moment when it is necessary to use the symbiosis of LLM and familiar algorithmic solutions.
On the Accuracy of the Magic Kick
The most practically useful property of neural networks is not their ability to coherently answer questions, provide information on a given topic, or generate memes about cats. It is the ability to produce structured text suitable for further processing.
One of the most in-demand types of such text is program code, especially since popular neural networks have been trained on huge datasets of such code and therefore impressively handle the task of coding in popular programming languages. That is why millions of programmers, as well as people who consider themselves programmers, strive to be programmers, or dream of becoming them, have rushed to code using ChatGPT, Copilot, Codeium, and so on.
They also quickly discovered that the problem of limited context when writing code with neural networks manifests very clearly: as long as the solution is limited to a short fragment, and the task is more or less typical, the LLM provides an ideally correct and high-quality solution. But as the complexity increases, or rather the amount of code required for implementation increases, and the request moves away from the standard set of frequently encountered problems, the results deteriorate, glitches, failures, and “sabotage” begin, similar to how a student behaves who desperately needs to pass an exam, while their knowledge is limited to the read manual.
In fact, that’s exactly how it is: the neural network is obliged by its nature to produce a result, and the context it can operate with is limited by the training dataset and the maximum volume of input data. Therefore, writing truly complex and lengthy programs “head-on” using artificial intelligence turns out to be impossible.
How to actually do this using techniques different from “write me an operating system” is the subject of further discussion. For now, I have to say a few words on the cursed topic of prompting.
Since people are involved in artificial intelligence not so that machines will one day take over the world, not out of pure vanity, and not for fun, but to solve their human tasks, they are interested in ensuring that these solutions are correct and practically applicable. And so, as with any other tools, it is extremely important that it is used correctly. How exactly — naturally depends on the task we are solving. However, any tool has areas in which it is most effective, large language models are most effective in generating structured text. For this reason, legal documents, not to mention technical ones, are better produced with their help than stories and essays, and resumes are better than journalistic pamphlets. And even artistic works will be of higher quality if created based on a well-organized framework, gradually adding details. For example, first request a story plan, then a description of the characters, then, using them as context, the introduction… and so on.
In other respects, the principles of prompting more or less align with the techniques of effective management: clear task setting, clear unambiguous description of input data and expected results, and, what is often neglected, assistance and support for the model at every step.
With the first two topics, everything is clear, “tips from the experienced” have become clichéd, so they can be repeated as briefly as possible: artistic style and convoluted politically correct formulations generate, respectively, ambiguous and hardly applicable responses. The neural network is not a negotiation partner but a diligent performer; for its effective use, it is necessary to employ an imperative style and categorical constraints. Not “can you,” but “must,” not “would like,” but “should,” any “given” and “ought to.” As structured as possible, clearly, point by point. There is this and that, do this and that under such and such constraints. Avoid this, apply that. “Thank you” and “please” are discarded at the data filtering stage; it’s foolish to fill the already limited context with them.
Even better, give the input data some structure, tabular or list-like, ideally using formatting in the style of XML or JSON. What is this — I recommend reading about it on Wikipedia, or asking ChatGPT: if you intend to read further, this will be necessary in any case.
But, perhaps, the main thing to remember is that the neural network has neither eyes nor ears, it (unless it is a very advanced tool, of which there are currently very few) cannot substantively verify its answers. You are its senses. Yes, you. Only you can ultimately assess the relevance of the results obtained and provide feedback to the system. This feedback will become part of the context of subsequent requests and lead to the improvement of their results. It is important to remember here that “improvement,” i.e. becoming more relevant, is not the neural network itself, but the instructions that supplement your data, so your hints should not exceed the acceptable volume of context. In particular, if you are communicating with an LLM in dialogue mode, sooner or later old messages will stop being considered and… you will have to remind the neural network of something you have already “discussed” earlier. Sometimes this may seem like communicating with someone with memory loss, however, from a practical applicability standpoint, this is the only correct path, far better than complaining about the imperfection of a hammer unable to drive a nail without external help.
How to write code without knowing how to program
Oh, how hard it is for me to write this chapter. I can already see hordes of programmers ostracizing me for heresy and apostasy, and most importantly, for betraying the sacred mystery of the profession. And legions of humanities graduates hoping to become engineers without even understanding the terminology, cursing me for their shattered hopes and unfulfilled expectations. Therefore, I have to start with an explanation (which, of course, will not satisfy either side): modern LLM tools allow you to write code without programming skills, but… you won’t be able to create a meaningful program without any understanding of the subject. Moreover, the higher your own qualifications, the better results you can achieve. This is, in fact, how it works with any tool: in the hands of a master, it allows for the creation of masterpieces, while a monkey equipped with the same will merely spoil the material.
And yet, there is one nuance that contradicts everything said above: thanks to neural networks, it is much easier for an interested non-professional to quickly achieve significant and practically applicable results. Since there is no longer a need to memorize function names, parameter orders, and much more that constitutes the routine of the coding process. You need to set the task correctly, accept the completed work, give assignments for adjustments, and check what has been done. And roughly understand what is being provided to you. In other words, manage the development.
Fortunately for us, “robots will replace” not everyone, but only the laziest and most foolish. The profession of a coder indeed, most likely, will die out, but programmers will live on.
However, if you want or need to master the process of coding using neural networks as an assistant tool, you must firmly accept from the very beginning the thesis that you cannot fully trust this assistant. As with a human assistant, you will have to understand what is being done, how it is being done, give corrective nudges in time, and ensure that they are accepted and understood. Artificial intelligence is at times dull and stubborn, but blaming it for this is completely useless. Moreover, it requires precise and competent task setting in the language, that is, in the terms used in the data on which the neural network was trained. Accordingly, you will have to master programming terminology, way of thinking, and basic concepts: variable, list, function, class — in any case. If you already know them — wonderful, if not — you won’t get far without this. You will have to learn.
Also, I can’t stand examples and recipes. It’s important for me that the essence is explained and I’m given the opportunity to try it myself. It takes a lot of time, but that’s how I understand the subject and feel it “at my fingertips.” Most people love examples and adore ready-made recipes. Explanations “from dinosaurs” and theorem proofs seem to them a waste of time. And, I must say, in many cases, that’s how it is. Therefore, I will provide as many examples as possible and explain why they are the way they are. And those who, like me, need to generalize will surely do it themselves.
So, before proceeding to the main topic, on how not to write programs in the conventional sense of the word, but to use neural networks to solve tasks that were previously difficult and painful to solve algorithmically, let’s spend some time examining how to actually write programs using linguistic models as a tool. At the very least because many of the relevant techniques will be employed later in a more advanced and automated version.
The main thing that ChatGPT or its analog replaces for you — is a textbook. Classic programming books (and probably most other educational materials) are something that will exhaust themselves in the coming years, if they haven’t already. Everything you would like to get from a book, you can easily get from a neural network. However, since LLMs are currently used in the mode of chatbot responders (a familiar, but not at all necessary application), you’ll need to ask questions. This is more difficult because people usually have a fear of novelty and learned helplessness. But the main thing is to start.
For example, like this:
— “Write the simplest program in Python.”
To start like this, you only need to know the name of the programming language and that programs are written in it. It seems such knowledge is available to everyone.
Since the time of Ritchie and Kernighan, the simplest programs in all languages look the same. They output to the text console “Hello, World!”.
# This is a simple Python program that prints a message
print (“Hello, world!”)
Even if you don’t know anything about program code in general, you can already extract a lot of information from these two lines:
— Comments in Python start with the # sign and do not affect execution
— Function print displays on the screen what is enclosed in parentheses
— Strings should be written in quotation marks
A few more independent experiments with prompts, like “print the number 10,” “calculate the sum of two numbers and display it on the screen,” etc. — and the first ice will be broken. At each stage, you will receive a fully functional and operational program: a neural network writes code of this complexity without errors.
And then the second barrier arises. A barrier that thousands and thousands of coaches, advisors, and online trainers earn from the inability to overcome. “What to ask next?”
If I were to start listing these questions now, we would end up with yet another programming course. For some, unnecessary, for others, long completed, for some irrelevant, and in any case, bringing nothing new compared to the multitude of existing courses. But I will do it differently.
Having at hand LLM-tool, you don’t need a Python programming course. Even in the absence of the most basic knowledge and theoretical preparation, you don’t need trainers and coaches. After all, next to you is a genie fulfilling any, well, almost any wishes. So let’s wish for… a Python programming training program. On any example convenient for you. Let ChatGPT, or whatever you prefer to use, suggest task options, lesson sequences, provide examples, and check assignments. Ask it in simple human language, no prompting secrets are required here.
Neural Network Pedagogy in Action
You can get a basic understanding of programming code, sufficient for writing minimally viable programs, without any “high art of prompting,” by asking the neural network questions as you would ask a person. But then, of course, the nuances begin.
My 11-year-old son, having started learning Python with the assistance of LLM, received a task from me to write a program that sums a list of numbers. If he had formulated it to the neural network in this way, the result would have been something like this:
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Calculate the sum
total = sum (numbers)
# Print the result
print (“Total sum is:”, total)
No special knowledge is needed here, Python has a built-in function sum, which does everything for us.
A programmer, an ordinary person who studied their craft through a normal human program, but unaware of the existence of a ready-made solution, would write something like this in 99% of cases:
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Initialize the accumulator
total = 0
# Loop through each number and add it to the accumulator
for number in numbers:
total += number
# Print the result
print (“Сумма чисел равна:”, total)
Numbers are added one by one to the already accumulated sum, like pressing the M+ button on old calculators. This procedure of “accumulating the result” is so natural that it’s hard to imagine anyone inventing something else.
But my son communicates with the neural network in English, does not have a technical education, expresses his thoughts in a convoluted way, and as a result, his prompt turned out to be so intricate that even the author himself had doubts about its interpretation. The final result was absolutely correct and even elegant. But it would be difficult to find a human coder who would suggest this solution as the first, second, or even third option.
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Convert the list into a string expression like “3+7+1+9+4”
expression = "+".join (str (number) for number in numbers)
# Evaluar la expresión
total = eval (expression)
# Print the result
print (Total sum is:”, total)
If you suddenly did not understand, the list of numbers is converted into a string-formula “3 +7 +1 +9 +4”, which is then evaluated by the function eval, designed for evaluating expressions.
For developers of embedded systems, such solutions make their eyes twitch. We instinctively imagine how many processor cycles are required to convert numbers to text, reverse convert text to numbers, and what overhead parsing an expression string during execution carries. But in interpreted Python, all these conversions, as well as eval, are part of the execution process, so in many cases, this option will be not much slower than accumulating the result. Not to mention that the powerful processors of today’s computers mostly idle, and the memory volumes allow us to forget about doubling, if not tripling, the required number of cells.
For us, it is important to learn two lessons from this example:
— Prompts matter, and the terms in which they are formulated can change the solution beyond recognition. Speaking with artificial intelligence requires at least using the correct language,
— “The soulless machine” does not have our human life experience, does not think about the problems we may subconsciously keep in mind, and does not have the stereotypes and limitations inherent to us. It was trained on texts describing final outcomes, and therefore, the solutions it proposes may, on one hand, not meet human expectations, and on the other hand, be more optimal than what even a good, competent professional might produce.
And the main moral here: formulate the task clearly, explicitly, and completely. And, upon receiving a result that doesn’t fit at all, change the formulation of the question instead of being horrified by the answer. And, most importantly, help!
Help him, scoundrels!
If you persistently make your way through the thickets, forcing the neural network to generate more and more complex programs, sooner or later you will encounter one of its two limitations. Most likely, the first to catch up with you will be the context size limitation. The first encounter with it is usually unexpected and unpleasant: you suddenly discover that functionality has started to disappear from the program being created. Moreover, not the one you are currently working on, asking your clarifying questions and specifying the task, but rather those parts that are considered long finished, ready, and not requiring changes. When the capacity of the electronic brains becomes insufficient, it is they that are discarded, and since your attention at this moment is not focused on them, this treachery becomes obvious not immediately. Therefore, if you are doing some useful project and not just trying this and that, a version control system and the habit of constantly saving, “checking in” new versions into it, will be far from unnecessary for you.
Unfortunately, you will not find a radical remedy for machine sclerosis. More precisely, it lies outside the plane of code generation using LLM and requires, on the contrary, the use of LLM from and instead of code. However, senility can be significantly delayed with the help of a few fairly simple procedures.
Firstly, help the patient remember what they forgot. Requests like “I had it like this before, add it back” with the inclusion of the lost parts of the code, refill the model’s context, allowing it to recover what was missed. A similar, but less effective way is imperative prioritization: “Add such functionality back and don’t you dare discard it again!” However, it should be remembered that no matter how categorical your phrasing is, it won’t increase the “memory” capacity of artificial intelligence, and as the task expands, it will still begin to lose details more and more.
At this point, you will have to put aside the whip and help the electronic brain with action. Since it, the troublesome non-human, is unable to keep a large task in mind but handles small ones well, you will need to break down your program into a thousand little bear cubs. You can do this with the help of the same neural network by asking it to decompose the original task. After that, assemble the target application from individual functions, classes, and modules, check and adjust it. You can adjust it using the previous method: “I have such and such code, I need to improve it in the following way.”
This work is usually done by a software architect, and it is still very difficult to replace them with a robot. And, if previously they had a certain number of programmers of varying levels of ineptitude under their direction, now their biological brains can largely be replaced with silicon ones. However, whether philologists, historians, and film critics can massively retrain as software managers and what additional qualifications they will need to acquire for this is a question that remains unanswered for now.
The second thing you will definitely have to worry about is hallucinations, or, in slang terms, glitches. They are expressed in the model’s obsessive desire to make mistakes. Sometimes they are gross, in which case they are usually visible to the naked eye, but more often they are minor, like constantly renaming functions, changing the order and value of parameters, rewriting already approved and verified code fragments. Sometimes these errors are not fundamental if the task can be solved in different ways, and all of them are quite suitable. But more often such glitches destroy the integrity of the written code. Worst of all, if not quickly detected, they remain in the program for a long time: subsequently, after the volume grows, cleaning them out using the same method of communicating with the neural network (“this is wrong here, change it like this”) becomes impossible due to context overflow. And either time and qualification allow you to redo the work manually with curses, or you have to start it over, often from scratch, because the LLM context is already filled with incorrect assumptions from the previous dialogue.
The only more or less effective method of reducing the impact of “machine sclerosis” and “machine Alzheimer’s” is to break the task into limited fragments, unit test them, and provide hints to the artificial intelligence with frequent citation of previously written code.
Here I will once again condescend to an example. In this case, an example of what can be achieved using neural network code generation with reasonable general computer literacy, but, in principle, without special programming knowledge.
Once I needed to make a screen video: a small script, incidentally written by a neural network, was drawing pictures with a “turtle,” and I needed to show the whole process to a boy on the other side of the ocean. Actually, in Windows there is a built-in function for this, but it captures one window, while I needed the whole screen with the program code and the picture being drawn. I could have installed OBS Studio or one of dozens of similar programs, but you have to find them first, then uninstall them, and all this creates hassle and fuss. FFMpeg is already installed, but it runs from the command line and is inconvenient to quickly turn on and off.
In general, the quickest way to solve the problem turned out to be to call ChatGPT and write a complete application in ten minutes, including the installation of everything necessary, launching from the menu in the tray, and generating video files with time and date. No special prompting skills are required for this, just a clear description of “I need to capture the screen to a mp4 file” with an indication of the operating system, programming language, and a few additional corrective instructions. Again-simply in human language.
import subprocess
import sys
import threading
import datetime
import shutil
import os
import time
from pathlib import Path
# Installing dependencies if missing
def ensure_modules ():
import importlib. util
def install (package):
subprocess.check_call ([sys. executable, "-m”, “pip”, “install”, package])
for module, package in [(“pystray”, “pystray”), (“PIL”, “pillow”)]:
if importlib.util.find_spec (module) is None:
install (package)
ensure_modules ()
from pystray import Icon, Menu, MenuItem
from PIL import Image, ImageDraw
ffmpeg_process = None
tray_icon = None
blinker_thread = None
blinker_stop = threading. Event ()
def find_ffmpeg ():
ffmpeg_path = shutil. which (“ffmpeg”)
if ffmpeg_path:
return ffmpeg_path
fallback = r"C:\ffmpeg\bin\ffmpeg. exe”
if os.path.isfile (fallback):
return fallback
raise FileNotFoundError (“FFmpeg not found”)
def get_video_output_path ():
videos_dir = Path. home () / “Videos”
videos_dir.mkdir (parents=True, exist_ok= True)
timestamp = datetime.datetime.now().strftime (”%Y%m%d-%H_%M_%S”)
return str (videos_dir / f"Screen_Capture_{timestamp}.mp4”)
def create_icon (color):
img = Image.new (“RGB”, (64, 64), “black”)
draw = ImageDraw. Draw (img)
draw.rectangle ((20, 20, 44, 44), fill=color)
return img
ICON_IDLE = create_icon (“green”)
ICON_RED = create_icon (“red”)
ICON_BLACK = create_icon (“black”)
def blinker ():
while not blinker_stop.is_set ():
tray_icon. icon = ICON_BLACK
time.sleep (0.4)
tray_icon. icon = ICON_RED
time.sleep (0.4)
def start_recording (icon=None, item=None):
global ffmpeg_process, blinker_thread, blinker_stop
if ffmpeg_process:
return
output_file = get_video_output_path ()
ffmpeg = find_ffmpeg ()
comando = [
ffmpeg,
«-f”, “gdigrab”, "-framerate”, “30”, "-i”, “desktop”,
«-f”, “lavfi”, "-i”, “anullsrc=channel_layout=stereo: sample_rate=44100”,
«-pix_fmt”, “yuv420p”, "-c:v”, “libx264”, "-c:a”, “aac”,
«-crf”, “23”, "-preset”, “ultrafast”,
output_file]
ffmpeg_process = subprocess. Popen (
comando,
stdin=subprocess. PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
blinker_stop.clear ()
blinker_thread = threading.Thread (target=blinker, daemon=True)
blinker_thread.start ()
update_menu ()
def stop_recording (icon=None, item=None):
global ffmpeg_process, blinker_stop
if ffmpeg_process:
try:
ffmpeg_process.stdin. write (b’q\n’)
ffmpeg_process.stdin. flush ()
ffmpeg_process. wait (timeout=5)
except Exception:
ffmpeg_process. terminate ()
ffmpeg_process = None
blinker_stop.set ()
tray_icon. icon = ICON_IDLE
update_menu ()
def toggle_recording (icon=None, item=None):
if ffmpeg_process:
stop_recording ()
else:
start_recording ()
def exit_app (icon, item):
stop_recording ()
icon.stop ()
def update_menu ():
tray_icon.menu = Menu (
MenuItem (“Stop Recording” if ffmpeg_process else “Start Recording”, toggle_recording),
MenuItem (“Exit”, exit_app)
)
def main ():
global tray_icon
tray_icon = Icon (“Screen Recorder”, icon=ICON_IDLE, title=“Screen Recorder”)
update_menu ()
tray_icon.run ()
if __name__ == "__main__”:
main ()
For those who doubt their abilities and suspect that only thirty years of practical programming allow me to write such utilities in ten minutes, I hasten to assure you that I haven’t even read this code. Which, by the way, is significant in the context of future chapters: is it even necessary to generate text that no one intends to read? Maybe it’s better to immediately move on to execution?
Rules of Engagement
You would surely judge me if I withheld a few specific tips from you, limiting myself to general chatter. Therefore, I will be brief, like Longstreet at Appomattox, and instructive, like Baloo the bear.
— When faced with hallucinations of a neural network, first clearly and thoroughly explain to it the problems caused by the generated code. It will not see them on its own. Ignore statements that “this is the final, complete, and tested version” — we have already discussed above that LLM does not take responsibility for its words and why.
— Do not try to solve many problems at once, it will overload the context. The expression “chase two hares” is exactly about fine-tuning neural networks. Move step by step.
— If you have error messages, simply pass them back into the dialogue. As a debugger and exception diagnostician, neural networks are particularly effective.
— Throw back the code that has problems and the code that didn’t have this problem (if you have it). “This worked correctly, but this works incorrectly.” Such hints help the electronic amnesiac remember what was being discussed two minutes ago.
— When the program becomes large enough, more than one hundred and fifty lines of code, request not the full version, but a list of changes in relation to the previous or, better yet, the version you provided. This will save context, reduce “laziness,” and hallucinations.
— Break down complex things into modules. Request a specific function, specifying the required parameters and output format, rather than the entire program. Yes, you will have to assemble the code from pieces manually, but it is still dramatically more efficient than writing it from scratch.
Actually, we will have time to discuss more complex and general advice below, but I intend to be a bit pedantic for a while longer.
— Many experts, both in quotes and without, recommend describing the task to the neural network as thoroughly and structurally as possible. This is a good and practical approach, but by following it literally, you risk spending more effort than if you were solving the task without the help of AI. Instead, start by explaining what you want as you would to a professional human. If the result is unsatisfactory, clarify the details that were misunderstood, and move on to a detailed description of the minutiae only when you get directly to their implementation.
— After encountering an unsatisfactory response several times in a row, especially if each subsequent one is worse than the previous, and the above tips don’t help, start the dialogue anew. Upload the most suitable of the previous versions and describe the modifications that need to be made. Otherwise, the “cluttered” context may become an insurmountable obstacle for further coding.
— Compare the amount of code obtained in the new iteration with the previous size. If you ask the model to add functions, and the number of lines significantly decreases, this is a good sign that functions are starting to be discarded. If this syndrome is not caught in time, a significant part of the effort will be wasted.
— Don’t be lazy to understand version control at least at the very basic level. Git — the best protection against disappointments, searching for “the last version where it still worked properly” in a multi-page dialogue with a chatbot is a futile task.
I’ll stop with the didactics here, as such advice is usually not read by anyone, and everyone will learn their lessons on their own. Still, keep them in mind, if only so that in a few years, you can slap your forehead and exclaim “I’ve heard this somewhere before.”
Neural Network Tools and Labor Productivity
No matter if you are an experienced programmer, a beginner, or not planning to master this specialty at all and are just having fun, when you first write something tangible in collaboration with a neural network, it will seem to you that now your productivity will skyrocket. At least because you no longer need to type tens, hundreds, or sometimes even thousands of lines of code, which in itself takes a hell of a lot of time. And that now, finally, you will be sitting on the beach with a long-deserved cocktail, while obedient and tireless AI-agents churn out module after module at your command. I’m not exaggerating much, the first impression is exactly that, and I was also under its influence for some time.
However, I haven’t been writing code manually for a long time, and my productivity has increased at most threefold. At the same time, I am terribly tired, my head is splitting, and I nostalgically recall the times when I could spend a day or two mechanically filling in methods of library classes or populating error handlers.
All because the work doesn’t do itself, “AI-agents,” or rather primitive code generation, really do an excellent job with routine tasks, and if before active thinking took up at best 20 percent of the total programming time, now it requires all one hundred and then some.
And the human brain is not limitless, consumes a hellish amount of energy, and has quite finite multitasking capabilities. And where previously you could let it rest with a clear conscience without feeling like a lousy procrastinator, now you have to strain to the fullest. Remaining a bottleneck, albeit shifted to a different point on the productivity scale.
Naturally, with the improvement of tools, the productivity of programming work will increase. Currently, the context of the models known to me allows writing about 200—300 lines in Python without the need for intensive “manual” intervention, depending on the complexity of the problem being solved. When this figure grows at least threefold, entire classes of tasks will no longer require human involvement. And yet, full automation of coding based on the principle “I give you a task, you give me an answer,” or as the military say, “fire and forget,” is unlikely to be possible on this path. Practically useful software consists of millions of lines, and generating them even after one or two levels of decomposition will not be possible for a very long time, possibly never, unless a fundamentally new way of parallelizing processor power is found.
Which, however, does not mean that it is impossible to fully or almost fully automate the coding process. However, it is very likely that this requires an approach different from replacing a human programmer with a machine programmer. After all, isn’t it strange that we make a computer write a program that it will execute itself, and on our, human, or at least human-understandable language? Why not do everything necessary immediately without writing this very human-readable program?
Here we have almost reached the most important point. But before moving on to this main point, we need to discuss a few myths that currently hinder the use of LLM not as a code generator, but as a replacement for it. So don’t be surprised by the “introduction” in the middle of the text. Only now are we ready to get to the essence.
The Myth of Determinism
Since its inception, the computer was primarily intended for performing calculations according to a given algorithm. In addition to its design features and architecture, this largely predetermined the attitude towards this device: even now, when most tasks solved by electronics are not related, or only indirectly related, to performing calculations, many people, including professionals, continue to consider determinism of execution and repeatability of results as one of the main properties of computing technology.
The overwhelming majority of programming languages, development methodologies tools are largely, if not entirely, based on the idea of execution determinism. When referring to an instruction, function, or API, the programmer assumes quite specific behavior and known predictable results. Essentially, this means complete controllability of the computing system, which does what a human could do, only in a completely different range of speeds. When performing step-by-step debugging, the code author aligns the execution speeds of the algorithm by the human and the machine, performing the same operations that are expected to be done programmatically and controlling the correspondence of their implementation to his expectations, that is, the results he would achieve himself by performing similar actions according to a similar recipe.
At this point, you must have become bored. Mainly due to the obvious pointlessness of discussing the principle of program execution determinism: for most people, especially professional programmers, it is so obvious that it is beyond question. With a very limited set of assumptions, a computer with its memory cells and processor, which serves as a means of changing the values in these cells, is naturally modeled as a multidimensional state space, where each computational cycle corresponds to a transition from one state to another, and the program defines the function of dependency of each subsequent state on the previous one and external influences. This model is equivalent to a very large finite automaton, and anyone who has studied computer architecture or the basics of electronic technology does not require these explanations.
This model is obvious, practical, and has many practical applications. At the same time, from the perspective of software development, it is deceptive, and except for very early theoretical works, it was almost never used to describe real algorithms and programs. The reason for this is also well-known: the dimensionality of the state space, not just of modern computers with gigabytes of RAM and terabytes of storage, but even of microcalculators with thousands of memory cells, is so large that describing each of them is practically impossible. And the real work of a programmer always implies isolating a certain manageable subset of this space, small enough so that its value can be predicted at every moment of code execution. However, even this limited subset of states in practice turns out to be too large. Therefore, the real expectations of a developer generally concern certain execution points where only a certain number of variables or, more often, output data are controlled, while for the rest, it is postulated to be within some “acceptable” range of values.
Here, a pause should be made. I intentionally minimized all previous discussions, did not delve into lengthy explanations, and avoided formal explanations of the concepts of “state space” and discussions of the limitations of finite automata models in relation to modern computing technology. Even if all these terms are unknown to you, not to mention if you know them better than I do — it’s not a big deal. All I wanted to convey to you is: we, programmers, have been perceiving a computer system as some absolutely controllable object, expected to respond predictably to what is written in our programs for almost a century. We consider the concept of “predictable” equivalent to the concept of “correct,” and behavior deviating from our expectations, respectively, erroneous, faulty.
But, attention, we think about the computer in this way, but we interact with it quite differently. No one, except for developers of very low-level high-reliability systems, where the program is more of an extension over electronics rather than an intermediary between it and the user, ever tries to determine the practical behavior of software with absolute precision. Programmers have long not known, nor do they wish to know the exact or even approximate set of processor commands into which their code is transformed, the state of external processes relative to it, and even most of the internal ones, the side effects of the invoked APIs and libraries, and much more. We are content with the constraints imposed on the behavior of these processes and objects, assumptions about what is “normal” and what is “erroneous” from the perspective of the program or system we are developing.
This applies even more to users. When pressing Ctrl+S, a person naturally expects that the document they are currently editing will be saved somewhere with the possibility of reopening it later. This is the limitation that separates normal behavior — the document is saved, from faulty behavior — the document is not saved. But how exactly the file with the document will be formed, what bytes are written into it, how it is processed by the operating system, cached, replicated, and so on — all of this, of course, does not interest the user. They are not particularly interested even in whether this file is a file in the sense of “a named array of machine words with a predetermined content structure, possessing the property of portability between different programs and long-term storage,” or if it is saved in some other form, for example, as a set of records in a database.
In other words, the determinism of computer operations expected by us has long and universally implied not the mandatory knowledge of the behavior of the computational system at every moment, but the compliance with certain conditions, criteria of acceptability and correctness of results. In other words, we habitually deceive ourselves, assuming that there is someone or something that, if necessary, can accurately say how a computer program will react to this or that action, however, this assumption, with negligibly rare exceptions, is never realized. Moreover, no one even attempts to realize it. If the browser does not display the desired web page, we press F5, if the application closes spontaneously — we restart it. In the modern world, the user never knows which specific version of the program they are using, as software often updates itself, not only without participation but even without warning the operator.
This happens not only for low-responsibility applications, such as surfing the web. The driver has no idea how many times any of the numerous microcontrollers in his car will reboot during a trip, and software products like Unreal Engine, which are not at all adapted for work in conditions requiring high reliability, use virtualization.
In other words, we do not expect determinism from the computer and computer programs, we do not need it and do not receive it. The determinism of computing systems, its necessity and possibility is nothing more than a myth, inherited from ballistic calculators and mechanical arithmometers, which gave rise to computer technology a good hundred years ago. A religion that has very little to do with reality.
About Neural Networks and Even Faster Horses
Since the successes of neural network technologies became obvious to the layperson, and many people from various computer-related and even completely unrelated fields rushed to find ways to apply them in their work, the use of the part of them intended for text processing (NLP) has been predominantly reduced to three main directions.
— Communication with the user. The largest segment targeted by most efforts. Dazzled by the semi-fantastic possibility of communicating with a machine in natural language, excited by the availability of tools like ChatGPT and DeepSeek, and most importantly, with almost no entry barriers in the form of any preliminary knowledge and skills, the public rushed to communicate, and businesses began to organize this communication. A mass of various useful and useless services, from “virtual friends” to banking and hotel chatbots, translators, and advisors, allows both solving some practical tasks and satisfying the human need for communication, which is an objective problem in modern society of disconnected digital introverts.
— Processing and, to a lesser extent, generation of documents. As well as other sources of unstructured and semi-structured data. With the advent of truly powerful meaning extraction mechanisms, the dream from my student days of turning databases into knowledge bases has largely become achievable. However, considering the gigantic array of sources that need to be processed and are being processed, there is currently a lack of tools here. As well as skills — unlike interface tasks, almost any activity in practical data mining requires at least basic programming knowledge, and preferably quite serious professional training, which immediately reduces the mass interest in it.
— Code generation. Here, of course, the demand arises mainly from people “in IT,” professionally connected with software development, or aspiring to such a connection. The possibility of avoiding lengthy learning of programming languages, as well as, more challenging, the principles of algorithmization, techniques, and methods while there is still demand for software development and, accordingly, developers, fuels interest in coding with the help of neural networks. Moreover, the developers of LLM and related tools themselves, being programmers, encourage and promote this method of their application. Finally, since source code by nature is text, and even formalized, in the field of its generation, NLP allows achieving quick and impressive results.
We will periodically return to the first two tasks later, but we will predominantly focus on the third one. After all, alongside the obvious advantages of the mainstream approach to it, there is also a fundamental contradiction expressed in the question: why should a computer write a program that it will then execute itself, and on a language specifically designed for human convenience? Why not skip the code generation stage and proceed directly to execution.
This question, which seems to be given insufficient attention, is the one I intend to focus on.
Twenty-five years ago, when I was a very young graduate student and had just started working for the not-yet-dying company “Motorola,” I was greatly and unpleasantly surprised by several corporate initiatives. At that time, I did not yet know that every self-respecting corporation must periodically generate meaningless and pompous activities that distract employees from work but create the illusion of vigorous and intense management activity. As well as serving as a cover and feeding ground for numerous incompetents and freeloaders, who are always a significant majority in any old reputable company.
One of these initiatives was the requirement to relentlessly and significantly increase the percentage of automatically generated code. According to the plans of the high management, which in a few years led the prosperous company to collapse and bankruptcy, employee productivity was determined by the number of lines they created per unit of time. These lines were strictly accounted for in reporting, and this reporting largely determined the career prospects of a particular programmer. Naturally, it occurred to someone in management, not directly responsible for financial results but appointed to grow and nurture the efficiency of personnel use, that if lines of code were created not manually, but by some magical means, then the numerator in the simple formula of labor productivity would soar to the skies. The word “magical” was absent in corporate jargon, so it had to be replaced with “automated.”
Бесплатный фрагмент закончился.
Купите книгу, чтобы продолжить чтение.