Logic and Process – the Fundamental Principles of Computer Science

Posted on Posted in Computer Science 101, PHP Dev

As a philosophy major at Vassar, and as a philosopher and author of philosophy books later in my life, I have always tried to get to the root of whatever subject I study, and to see the fundamental principles upon which a foundation of thought or practice is built. This is true of me, too, as a software engineer. So, let us ask: what is the fundamental principle of software engineering? To answer this question, I think we must ask, and answer, another question: what is a computer?
I am not talking about “computer” in contrast to terms like “mobile device” or “smartphone.” There is, of course, a taxonomy according to which “computer” means desktop or laptop, in contrast to “mobile device” which means smartphone or tablet. Here I say “computer” in a deeper and more significant sense, really in its classical sense. What is a computer? A computer is a machine that computes. In its modern sense, a computer is an electrical machine that computes via a CPU, although in the early days a computer was a mechanical analog system that computes by analog representations of reality (e.g. the device that Lovelace, the first computer programmer [who was a woman, by the way] programmed).
I had a basic realization as to what a computer is, when I understood what a CPU does, and read about the theory of the Turing Machine, and realized that a CPU is a Turing Machine. Once you understand that a CPU is a Turing Machine, the way to think about software engineering becomes clear. To reveal this, first I will explain Turing Machines, and then I will touch upon CPUs.
So, what is a Turing Machine? Alan Turing, the great computer scientist of the 20th century, who developed the computer that broke the Nazi encryption during World War II, and who was then driven to suicide by British persecution due to the fact that Turing was gay, also found the time to be the father of the theory of computer science while fighting the Nazis. Turing’s theory was a theoretical machine called a “Turing Machine.” A Turing Machine is a machine that takes an input (originally theorizes as a symbol on a piece of paper or tape), reads the input, performs some operation based upon the input, outputs the input, and then reads the next symbol in the tape. The Turing Machine is a machine that has been programmed with a set of rules, such as “if the symbol is a red X, subtract 2 from the number in memory.” Armed with this set of rules, baked into the machine’s gears as it were, the Turing Machine can then take input that consists of instructions, and can then obey those instructions according to the rules it has been given. The input symbols, then, can consist of discreet instructions for the Turing Machine to obey, or of data for the Turing Machine to process according to its rules and the instructions also in the input.
That, basically, is how a CPU actually works, and a CPU is the centerpiece of how any computer (desktop, tablet, smartphone, IoT device, etc.) actually works. I am a software guy, not a hardware guy, not an electrical engineering guy, so don’t ask me about how the electrical engineering part of a CPU operates, but, to the extent that a software engineer must understand CPUs, I can say that a CPU has components that take input (binary code/machine code), this input contains op codes that give instructions to the CPU, and the input also contains data, in various forms such as numbers in binary notation or text stored in binary number format according to the ASCII table or UTF etc., and the CPU is wired to read the instructions, take the data, and operate upon or analyze the data according to the instructions–with all processing ultimately reducing to either mathematical operations upon numeric data, or logical computations and logical comparisons of values. The machine code is stores as bits in bytes in RAM which the CPU reads and processes in different parts of the CPU, but the actual hardware aspects are all Greek to me. What is relevant, then, is that a CPU is a Turing Machine. Why does this matter? Because the theory, the basic idea, that Alan Turing was trying to get at, as a computer scientist, is that a computer is a machine that obeys instructions in a specified way. The instructions are the input–a series of symbols on a piece of tape, for a Turing Machine, or gigs of machine code stories in SSD, in modern times, it’s all fundamentally the same–and the CPU, according to the logical and mathematical rules baked into it, obeys the instructions to process the data input. The key, for me, is that a computer cannot just do whatever it feels like, instead, it for a given input comprised of a given instruction and a given data, the result that the computer processes is specified, and is, therefore, fully predictable. If the input is “3, 7, add”, then the CPU will output “10,” and, assuming that the electrical hardware is in good working order, it will do this 100% of the time, and the result is predictable 100 times out of 100 opportunities.
In this sense, a computer is a logic machine. This, then, leads me to final deep, probing, philosophical question that I will propose in this blog post: what is logic? As a philosophy major, I am aware that, of course, there are many different answers to this question, posed by philosophers throughout the history of philosophy, and debates about this can become quite heated (one thinks of Wittgenstein attacking Popper with a fireplace poker, for example). Aristotle had his syllogisms, Frege and Russell and Wittgenstein had their vast edifices of math and premises, and modern philosophical logic has become quite convoluted. Then there is Boolean logic, the logic that most computer programmers are familiar with as a matter of practical necessity: a value can be true or false, if X and Y then both X and Y must be true or else the result is false, if X or Y then if either X or Y are true then the result is true, if not X then the truth value of X is opposite to the result, etc. But here I have just said, over and over again, the key, although many readers may have missed it: “if something, then something else.” This, for me, is the key to logic, and to the understand of coding as an expression of logic. If there is a process, and it is based on rules, then the result of that process, applied to a given input, is fully determined, fully specified by the rules, and is therefore fully predictable. The inputs change, but, if the rules are consistent, if there is a specification that says what the rules are, then the result of the process applying those rules to that input is determined by those rules. If you have the principle of Boolean logical “and,” then the inputs can change: X and Y might be based on some data in economics, or a text string on a web page, or a user input, and could be true or false in a billion different CPU computations, but, because the rule “AND requires both values to be true, or else the result is false” has been specified, the result is always the same, that if both X and Y are true, the result is true, otherwise, it is false. Of course, in computer programming, there is the “if, else” syntax, but what I am getting at here is the basic idea behind that syntax, that, for a process, if the rules of the process are specified, then the output is merely the result of the input processed by means of those rules.
(In logic, there are those who think that logic is not about process, but that logic is about truth and falsity, and the building blocks to analyze true and false statements, such as and, or, not, etc. Truth and falsity, in this sense, go far beyond the Boolean logic of the coder, and are more a matter for debate by philosophers, not computer scientists. I personally subscribe to, and have written extensively in defense of, the correspondence theory of language, which holds that a sentence “The apple is red” is true if the sentence refers to an apple in physical reality and that apple is, in fact, red, so that the truth and falsity of words and sentences correspond to the existence and non-existence of objects in reality. But there are many logicians and philosophers who disagree, and it shows how tangential this aspect of philosophical logic is to coding, that the logic in your source code is pretty much the same for you regardless of whatever you believe about the theory of truth and meaning as such. Indeed, for a variable to be “true” or “false” in source code is merely an aspect of the instructions you are telling to the CPU, and rarely, if ever, correspond to the truth of objects in reality, unless the variable is the property of some object that is actually based on something real in the application’s business logic, such, for example, a property of a fruit class that holds a Boolean value that is true if an apple is red, or false if it is not–but even here, this truth and falsity goes above the language Boolean syntax and reaches business logic semantics.)
In this way, a CPU, like a Turing Machine, is simply a machine that takes a process that applies a set of rules to input and then produces the output of applying those rules to that input. What, then, is software engineering? Software engineering is the art of understanding the rules that the CPU obeys, in order to draft a set of instructions (source code) which, when fed into the CPU and obeyed by the CPU, will be applied to the data input (user input, numerical content, etc.) to produce the desired output. Ultimately, a computer program is, essentially, a process–it is a process, specified by the client (whatever business or project owner owns the software development account) that is designed to take a certain input and produce a certain output. For example, a store wants software that will serve as ERP and POS. The input, then, is the customers and their transactions, and the output is an organized computerized analysis of the bank accounts of the store as a result of the transactions. The job of the computer programmer, fundamentally, is to take the inputs and outputs that the client wants, and translate them into the inputs and outputs that a CPU could provide mechanically, and then draft the set of instructions, to be obeyed and executed by the CPU, which will produce the client-desired output given the variable inputs in the client’s plan. Thus, a software engineer translates a business process, or business logic, into a computer process and computer logic, to computerize the client’s desired process into a process that can be executed by the CPU.
Some computer science teachers encapsulate the principle I have been articulating as O = P(I) (some also say “O = P(I) + E”)(pronounced like the name “Opie”). This means simply “output equals process of input (plus error)”. O is the output that results from applying process P to input I, with errors E added in. This, I think, is the correct way to think about software engineering, and about process, and logic, as such. The output is nothing more than the input processed by the process. (The E indicates that error may introduce variations in the output that are not a result of the input, but, from the point of view of the end result of the output, I prefer to think of human errors as a part of the process that produces the output, albeit an unintentional part, and so prefer to say “O = P(I)” as such.)
Thus, if you know the input, and you know the process, you can predict the output–and, even with various input, if you control the process you can get the output that you want by designing a process which will turn all the possible inputs into whatever output you are trying to get. The key skill, here, is logical thinking: the ability to think in terms of a process as a set of instructions that are obeyed, so that, in the context of the rules that a CPU is wired to obey, you can tell the CPU what to do in order to get it to do what you want it to do. Computer programming is nothing more than this–identifying the client’s desired process and translating it into a computerized process that works, by means of knowing what the rules wired into the CPU (and, in practice, your programming language which will translate your code into the machine code binary executed by the CPU) are so that you can draft the instructions which will tell the CPU to perform the process that turns the client’s potential input into the client’s desired output. It is nothing more than this. If this is true, the skills needed for software engineering are: logical thinking, the ability to understand what the client wants, the ability to design a process that reflects the client’s desires, the ability to code a software that encapsulates that process, then, for that goal, knowledge of the syntax and semantics of the language in which you code, and, also for that goal, knowledge of the substantive area of the client’s business logic so that you know what the program must do well enough to be able to know how to make it do that.
(Note the skill I have not mentioned: math. Unless you are engaged in actual electrical engineering, or work in a business area where advanced math skills are essential to the business logic, such as data encryption or AI, I don’t believe that math is a core skill of the software engineer, although it is a matter of contingent coincidence that most people who are good as logical thinking are also computer geeks who know math.)
Armed with this, we can ask: what is a computer language? It is a set of symbols on a tape that the Turing Machine obeys as instructions. Really, it is a series of text inputs, translated into machine code by the compiler (and, yes, the assembly language) according to the language’s rules, and the CPU then executes that machine code. Thus, it is a language that translates human-readable CPU instructions into machine-readable CPU instructions. The syntax of the language is the actual set of symbols and the rules of what CPU instructions they will be translated into, whereas the semantics is, as I see it, the map that maps the syntax onto the business logic of what process the CPU will perform. Thus, a unit of semantics is “if X and Y, then A,” which is the meaning of the software in the context of the actual business logic of what the program does for the client and for real human beings in reality, whereas the syntax of
if ($X && $Y){
$A = true;
return $A;
}
maps that semantics into the instructions for the CPU.
Since we are speaking about processes, let us then say that software design often uses flowcharts because they are the best visual map for detailing necessary specified processes. We can then even draft a simple flowchart of the process of software engineering, according to my analysis:
Reality -> problem/data to manage -> Client who pays software engineer and proposes wishes ->Software engineer -> Software design -> Semantics -> Syntax -> Compiled to machine code -> CPU execution -> data is processed according to the computer software -> CPU outputs output -> client’s problem is solved (if the output of the process of the input works as the coder intended and that process is actually the right one to solve the client’s business logic problem).
In conclusion, the process of computer programming and can be summarizes by the following flowchart:
User/API -> input (data and instructions) -> process (CPU, machine code) -> output ->user/API ->input (process iterates progressively).
This concludes Part I of my Computer Science 101 with Russell Hasan blog post. In Part II and Part III, I will discuss OPIE and debugging, and then apply the O = P(I) + E model to my favorite computer programming language, PHP, and use it to analyze some of the most popular frameworks in that language, WordPress and Laravel. Look forward to it, and stay tuned!

Leave a Reply

Your email address will not be published. Required fields are marked *