Engineering is a discipline of application of the scientific method to solving real-world problems.
It is about describing aspects of reality in terms of a model and then building (testing and continuously improving) a machine according to this model.
Software engineering is the most flexible and quickest way to build a reliable machinery for solving problems. The cost of changes is low, so embrace changes and change often.
Very naive attempt to describe what is software engineering.
There are few principles, or maxims which *together* forms a foundation of software engineering discipline.
- divide et impera
- take different perspectives
First one is the most fundamental and most important - a has several different meanings. It means decompose a problem into a set of small sub-problems, and attack them independently. It means divide a system into separated layers, and develop them separately. It means establish a set of rules (protocols) for everyone to follow, and then just enforce correctness of these protocols. It means focus on what is relevant in this particular level of abstraction and forget, for this moment, everything else. It means almost everything.
For a software engineer it means separation of concepts - interconnected black-box abstractions, it means modularity - separation of pieces of code. It means careful design of APIs and especially protocols, which are of the first priority. Bad protocols cannot be helped by good software.
The second most important thing is underlying representation - which data structures are you using and how they are represented.
Most of people conditioned to ignore this part of reality and believe that this doesn't matter, that there are some magic tools, such as JVM or V8 which will take care of this annoying details. This is very naive view and the most common cause of suffering.
Software engineer must know how his data are represented, how and where they are stored, how often they are accessed and in which pattern. THIS is the most important part of software engineering. It is not so-called data-driven development, it is this. Know. Your. data.
Knowing how your data are stored and accessed implies knowing your hardware. Software engineer cannot ignore underlying hardware. On the contrary, he must choice appropriate hardware for each task. He must know architecture of CPUs and memory subsystem at least. It doesn't mean he must become an expert, who could design a processor, he must understand the flows of data between CPU, RAM and storage, and be able to see the patterns.
Then comes OS. Ignoring and neglecting an OS is the same stupidity as neglecting and ignoring your physical environment. Software engineer must choice an appropriate OS for each task and avoid what is broken or unusable for specified kinds of tasks. For example, any version of Windows is completely unusable as a server platform. It is never designed for this.
This complete view the ability to take different perspectives, to zoom between layers, to trace in your mind the execution of even a very simple process all the way down to the registers is the the ability that distinguish a software engineer from a mere copy-paster.
This knowledge will help you with reading other people's code, first of the simple systems, then more advanced and complicated, and be able to understand what is going on.
The ability to read the source code of, say, the MIT Scheme, and see its structure and patterns is a sign of some competence. One must be capable of trace in ones mind how those list structures are transformed into a pointers and machine code and then how the resulting compiled code is executing.
It doesn't mean that you should compile code in your head. You must be able to follow all the transformations through all the layers. Then you may say that you know something.