Preamble, History, Mindset
Instead of a Preamble; A Present History of Backend Thought and Practice
What is code? How we fundamentally operate
When first learning to program, possibly the first code ever shown to any student, any future prospective programmer or engineer is something of this form:
x = 2
y = 5
x = x + y
While the expansion of notation usually introduces an effort of abstraction - the student thus introduced to the idea of assignment has likely seen the symbol 'equals' chiefly as a marker of an equation - in the context of which x = x + y
makes no sense - that effort of abstraction is very quickly blunted by a more aggressive move in the opposite direction, of simplicity and concreteness.
After the student "reassigns" his understanding of the "equals" sign as variable assignment, he gets a reassuring feeling that something somewhere keeps tally of changes, of updates; if the student has any propensity of craft or character to software, they might get even an overwhelming sense of power, the power to use words to dictate, plan and execute through the means of machine.
It is beyond the scope of this small non-preamble, but most everything the student does for a number of years through high school and university is a form of "take this there from here, and back". At this period in one's "programming" life, excitement and enchantment proceed from the observed reality that by simply "moving things around", one can solve enormously complex and difficult problems - from swapping the value of two variables X and Y to solving the 8 Queens Problem, and much more.
Manipulation of memory and state, then, is just a tool in the hand of the programmer to arrive to the solutions of mathematical problems. Manipulation of state is the sine qua non of programming.
It is the author's conviction that neither the exposure to forms of complexity management (any form of modules) or programming paradigm (be it functional or object-oriented) is sufficient to wean one's mind off a fundamental x = x + y
mode of thought. What do we do when we program, when we compute? We take the pitcher or bucket from the well to the kitchen and back.
From problem-solving of one kind to problem-solving of another; there are no easy "jobs"
Many software engineers would concur that they never needed to implement a linked list, to rotate a binary tree or to "invent" a sophisticated algorithm by themselves; there must be a generic sense of relief when moving from an algorithmic Computer Science background to many of the real-life jobs that have existed in the past 15 years. There must be a sense of relief in writing/processing a login form (we no longer do that as often, but we used to do it in the 2010's), or in writing a neat React component, a control in a mobile app and so on (either on a Web/Mobile dev course, or on a real job) after any form of "leetcode" type of coursework.
Any person doing a good job in any field of activity will know, however, that every job and, indeed, every type of job has a "central problem" on which one's mind's eye must always remain intent and fixed. For John Carmack, this "central problem" was the one doing the staring - how do you make a game of a never-before-seen level of visual fidelity run on any hardware? This was the central problem of Doom, and he solved it well.
What is the central problem of Backend development? Truly, having a service at all and making sure the service is available, reliable and performant is a problem. But for most of us, is it our real problem? I think for many if not most of us, our greatest problem is the problem of state. John Carmack might have struggled with state as well - but a video game's state is transient; the data a savegame needs, and the data a game running in real time has can be modeled (at least in the case of Doom) with just a few data structures.
We have a state problem in backend applications. We must reliably replicate across time, across the life of an application the same concepts, across millions of permanent state-altering interactions with the real world. A Counter-Strike game's state can be stowed away in a textfile somewhere; it, the game state, as "past" never matters. A Counter-Strike server's main concern, or problem, is indeed the first two above - availability and speed. It must spawn, process, end games, find and match users.
For the simplest E-Commerce web store, however, maintaining the reconstructable "user" and "order" across versions, across time, across iterations of what "user" and "order" even mean is The problem. Our job is to culturally and technologically re-create the past as present - to find the correct Holy Tradition. Our job, our main problem is re-constructing the Ship of Theseus in perpetuity.
The Back-end Problem as philosophical problem; the personal-ontologic disconnect
We've established that no problem is easy, especially when we don't know what the problem we're dealing with is. The "Backend problem" is elusive and difficult on more levels than one, unfortunately. We cannot "name" it and get rid of it simply by budgeting for it.
Some software systems (games, rendering, aerospace, telephony software) grace their developers with real-time feedback (the blasted thing is too slow, or incorrect, renders incorrectly, etc.) with respect to what's going wrong. These outward measurements (speed, availability, error states) are things that go wrong in Backend systems as well, and developers will naturally rush to fix them in their usual clever ways.
But whereas a tensor or vector calculation, or a memory overflow can be fixed with analytic solutions, the Backend Problem is, as we implied, a problem of meaning. A piece of code such as:
//@route('/users/{user}/{subscription_id}')
public function add_subscription(Request $request) {
$user->add_subscription($request->post('subscription_id');
}
Might fail for any number of reasons, and a developer might patch it up in a few minutes, or hours (add form validation, perform an additional DB check, etc.). The developer might even "refactor" it (Why does a user "have" subscriptions? Maybe "subscriptions" have users!), moving it into a Controller or a Service Layer, but the central Problem of Backend remains unresolved. The User is more than an ID/a row in a table, and the Subscription is more than an ID/a row in a table. Moreover, both of these are more than a properly-designed Model class in the Models directory.
The Backend Problem is a problem that bites at the root of the verb "is" - it "is" a problem of language, meaning that affects how we write and think about "things" in our internal and external language before we write our first line of code. The reason a certain business rule (User of group X managed to buy subscription Y, even though group X affords the benefits of it and it should have been impossible) is not (only) because somebody forgot to write the method that enforces that business rule, not only because the User or Subscription classes already have methods/business logic in place for similar business rules that haven't been properly updated for this particular application, but chiefly because nobody has talked about what it means that a user has access to a resource.
We (the developers) in such an instance begin "sensing" that something is wrong only when enforcement of certain business rules, or writing new ones becomes a difficult task (and we ask for budget for a refactor!) but the Backend Problem is such a problem both because is "is" a different kind of problem, and because our natural, analytic senses are rather dull to it.
The Back-end Problem as a hardware problem; the hardware disconnect
Possibly this section should be above the previous one, but it might be good to take a break from "meaning-world" and get back into "tech-world". The source of the "personal disconnect" has some more pragmatic causes as well. The reader might have intuited that all the examples of "non-backend" problems are in one way or another the kind of systems where the end, observable result of the code running is a real-life, tangible output - a game running, a phone correctly linked to its destination, a match of Counter-Strike found.
We might sometimes forget about this, but there is a hardware-level disconnect between what a user "sees" on a website and the code-and-data-representation thereof. Of course, one only needs to look at a compilation of comments from video game developers to "debunk" the non-existence of this code-reality disconnect in their field of work. Nonetheless, to a far better degree, a spawned police car is a spawned police car in GTA than the equivalent relationship in a backend system.
That is because we not only have a code-disconnect but a code-and-data disconnect; a user and their subscriptions can be "modeled" any number of ways; a spawned police car lives somewhere on the heap or stack. The User-with-subscriptions combined entity doesn't even "live" on the same server - even if the Application and Database servers are on the same machine.
This is part of the reason so many "frontend looks impeccable, backend is a total mess" memes exist. The Backend developer will attempt to model the business-reality of his application as a collection of SQL tables, or a collection of JSON Documents. Most of us were taught either by decree or example that this is what proper Application modeling is!
After the developer's beautiful data schema is done, after (possibly) the ORM Models are written, there is a feeling of wholesomeness and completeness the Backend engineer might experience, but it is unfortunately short-lived; business requirement after business requirement, due to the hardware disconnect between the user's screen, the frontend model, the application code and the database model itself, the illusion of a coherent model of reality usually shatters into a hundred, a thousand Model, Service, and Route methods. The Database is not, the database cannot be the ontological source of truth what the User is, for what the Subscriptions are. The constraints of technology choice will encumber the business model, and, vice versa, the increasing complexity of an ever-growing "business logic layer" will hide the true intent of the system.
The Back-end Problem as a cultural and human problem; the psychological disconnect
We return back to us staring at the computer screen, trying to understand the source of a bug, possibly burning through 2x billable company time by starting at our screen with a fellow colleague. More often that not, our language is purely algorithmic and mechanical - is this a race condition? Is this a type of cache poisoning? Is service X or Y timing out?
All of these are necessary and useful questions that define us as engineers; but we must have the wisdom of asking if the dwelling for which the pitcher of water is being fetched for multiple times a day is really fit to be a kitchen; to ask whether anyone really likes it; whether the person fetching the water is not better suited for another job. Data are not being simply retrieved, chopped up, and sent somewhere else. If we are to write good, beautiful software, our very language must describe a real-life "story".
Is that not the grand-promise of Object-Oriented programming? In reality however, too few objects "feel" like entities that have answers to questions, or are themselves answers to questions.
Indeed, we will attempt in this documentation to build an understanding of Software as vector of human needs, and make it as beautiful and alive as our native tongues that we so much love. If this endeavour accomplishes its ends, it will exceed paradigm and satisfy both the Object- and Function- oriented camps.
Tangible Cred is Tangible's contribution to exploring the depth of one of the most overlooked questions of software engineering, namely "what is this?". A second, similarly powerful one would be "who says that/according to whom?"
May it be the object of our inner man to understand the horizontality, verticality and depth of these questions as they apply to code.