"Truce is concrete, philosophy is fruitless"
So this page is about fruitlessness.
Majority of people don't understand what the mathematics is all about and what is the power of this science. I will try to explain this. Let's consider a simple example. You known, that for any natural numbers a,b,c the following is true: (a+b)+c == a+(b+c). But how do we known this is true? This is, in fact, an infinite set of propositions, one for each triple (a,b,c)! It is not possible to verify all of these identities by checking them per each triple! In the arithmetic foundations this property is proved using the induction principle. Using the logical deduction we are able to prove this infinite set of propositions. In other words, we are able to comprehend the infinity. Even if you are dealing with not infinity, but with a finite, but a large set, the logical deduction is the only way to state some properties of this set. Mathematics has the power to control the infinity and to bring an ultimate truce in many real cases.
Programming is about building some logical machines. It is, in fact, the engineering of some virtual entities. Historically, the computing arose from the mathematical logic and the algorithm theory. The Turing machine is a kind of prototype for all real computers. The developing of a good software is impossible without a good mathematical thinking. It is especially important in the modern multi-threaded or event-driven software, where it is not feasible to trace all execution scenarios. In a single-threaded program you can follow a program execution step-by-step, but once you have several threads of execution, the number of possible execution states becomes incomprehensible (combinatorial explosion). You must use logical statements and the logical deduction to understand how such programs are working.
Yes, that is the major difference between programming and manufacture. The purpose of manufacture is the reproduction of the same thing again and again. Reproduction of a program can be done instantly by the command copy. The purpose of the programming is to create something new, unique.
So developing a program we create a new quality to make the word better, safer, friendly etc. Or non-quality to make the work worse, risky, hostile etc. You think it does not concern you, because you get your money and leave? To where, to another globe, perhaps? To ruin it too? There is no escape. Humanity will learn how to control the power of the software of will be crashed by it. The power which comes from the command copy. When you program a quantity, you program a bug quantity.
What is the difference between a good programmer and a bad one? Good writes a small, bugless code, bad writes a large, fat and bugful. Good spends most time to learn, understand and design a good, structured, mathematically correct code and a short time to make it running. Bad is not capable to learn much, deeply understand a subject and tools, he writes whole novels of poor literature code and then spends most of the working time to make it running. Somehow. Good automates its work. It creates software components and tools for repeated tasks. Bad is destined to do and hate a manual job.
In the software development quality becomes quantity. That is the key point. There is no such thing as a deadline. There is a goodline. Deadline is a badline. Don't go towards it. Well developed code grows faster, it incorporates new features smoothly, it can be well tested, defect fixes are much simpler. The proper strategy in a large-scale development is to maintain a high code quality from the start to the finish. Prototype and redesign! Test comprehensively! Make a reliable software from a reliable software components!
In the soft history there were several examples, how a premature generalization led to a bad software. The first example is the UNIX paradigm: everything is a file. And that is totally wrongful. Socket is not a file. Keyboard and mouse are not a file. UNIX paradigm simplifies the system interface, but makes hard or impossible to work correctly with non-files in nature objects. Recall socket option functions, for example. This is an excellent illustration how an inadequate control interface forces to implement handmade serialization/deserialization through opaque control bottleneck.
Another good example is the STL approach to work with containers and algorithms. The natural way to work with data in a tree is the usage of recursive algorithms and that does not fit to the concept of iterators.
Simply like that. Ugly code is a bad code. The sense of beauty may seem irrelevant, but, in fact, it is important both in science and engineering. Good product is not just useful, it is also aesthetic. So use the sense of beauty as a guide.
There is no such thing as "good for everybody". "Good for everybody" means "good for nobody". Design you software components like a good tailor. To make a good suit make it suit. It means don't develop a universal components, good for an abstract everybody. Know how do you suppose to use it and make it good for a particular purpose. And a thing good for somebody has a chance to be good for manybody (but not for everybody). You will find many such things in CCore, so don't be surprised.
Efficiency is the most important guide in the programming. Programming itself can be considered as the efficient mathematics. It not only leads to fast code, but also to well-developed code.
The first step to the code efficiency is to make it well-structured. You cannot optimize a spaghetti code. If the code is well-organized, then you can identify parts, critical to improve performance, and work on them.
The second — no fat. Use efficient algorithms, use appropriate data structures, use simple means to solve simple tasks.
Third — leave to the compiler the most of optimization job. Compilers can solve many (but not all) optimization tasks much better, than humans. Modern compilers are good in the "local" optimization. So focus on making the code "optimizable" and leave the routine optimization work to the compiler. You should learn, what the compiler can do and what cannot and why.
I like the metaphor of the basket with apples. Peoples can put an apple to the basket or can get an apple from it. If the basket is empty you have to wait until somebody else put an apple. This is a metaphor of semaphore. Why metaphors are important? Because if you know a metaphor you can easily derive a precise definition of the software entity from it. You can specify a set of methods and its meaning, you can understand how to use an object without the reading tons of manuals. Metaphor is a seed. It can grow to a mature software component. Good software is metaphoric.
Metaphor is the most powerful weapon of the human mind to struggle with complexity. Using them you turn on the most deep and powerful human mind ability.
Filthy programmers make a lot of errors. There is no problem to find them, usually you can read the code and find a lot. But what's about a good one? When you write a good code, how about errors? How to catch a black cat in a dark room? Despite the common misunderstanding, it is not too much difficult actually. The REAL problem is: how to prove there is no cat? It is possible to create a defectless software, even a complex one, both theoretically and practically. But if you have one, how to prove it?
There is only one reliable way. Prove to prove. The same way as we prove mathematical theorems. In the pure mathematics we are able to build very complicated mathematical constructions and prove their properties by the logical deduction. The same way is good for the software development. Good programmer does not just write code. He formulates and proves different code properties. Therefore, good programmer must have a well developed mathematical mind. Unfortunately, modern development tools does not record this part of job.
There is a difference between the pure mathematics and the software development though. In the software development to cover all significant code properties you must prove a huge number of simple statements. So to make it feasible it is necessary to build the code in such a way, that this number will not be insane. And here we come to different software development techniques, like functional, object and abstract decompositions.
Functional decomposition arose from an observation, that some action sequences are repeated again and again. Object decomposition arose from an observation, that some data combinations and methods of manipulations on them are repeated again and again. Abstract decomposition arose from an observation, that software entities can be "parametrized" by another software entities. Each time we repeat some build again and again, we can repeat its property proofs too. So a good software decomposition not only allows us to build a complex software, but it allows to make it correct too.