Learning to program is a lot like learning a foreign language. To be any good in it, you need to read a lot of other people’s code and write a lot of new code. Getting fluent in programming takes time, but like any practice reading somebody else’s code becomes easier the more you do it, and the more you write the faster you are able to produce working functionality and less mistakes you will make while writing. Young developers joining the industry often start their careers by maintaining existing software and end up writing fairly little new code, which is a real shame as that means it takes them awfully long to get productive and confident enough to trust their own thinking.
Like writers, many programmers suffer from writer’s block. Only solution I know to procrastination is to just start producing something and forget for a moment any quality requirements you might mentally have that prohibit you from proceeding. Contrary to popular belief writing new code isn’t dangerous. Shipping new code that hasn’t been thoroughly reviewed and tested is dangerous. In publishing, on average fairly few pages ever written end up being published and pages that are lucky enough to get published often go trough multiple revisions before being accepted by the publisher. Publishers appoint editors to review even the most accomplished authors. In software projects code reviews are rarely practiced in the required depth, even though it is one of the best empirically-proven methods of improving the code quality and catching bugs.
Words are powerful. Every word is an abstraction, for example when you say a word dog people think of an idea of a dog, not necessarily any particular dog. Like words in a book, each program is described using abstractions. Natural language writer often assumes that the reader is already familiar with the used vocabulary or can infer the meaning through the context, where as in programming the author needs to explicitly define the meaning behind each words. The program code does not give the author much artistic freedom for interpretations or ambiguities, the system crashes if it is unable to follow the plot or track the involved subjects correctly. Dynamically typed and interpreted programming languages are often closer to natural languages and offer more expressive freedom for the authors than computationally faster, statistically typed and compiled languages.
Defining an abstraction is like writing a poem. Each abstraction tries to capture one concept or behavior similarly as a poem tries capture the essence of one feeling or a thought. Like in poems, a good abstraction is as concise as possible without making compromises to the original idea. An abstraction that tries to capture multiple responsibilities is hard to follow and maintain, similarly as words with ambiguous and hidden meanings are easily misunderstood by the participants. Like in writing, the more familiar metaphors you find for representing your abstractions, the more readable and self-explanatory your code will be.
Right abstractions are highly dependent on the problem domain. Good writing skills do not get you very far without solid understanding of the subject area you should be writing about. Big software companies often underestimate the importance of domain knowledge and end up hiring and subcontracting developers who lack understanding of the functionality they have been hired to improve. In addition to experience, finding right abstractions for the job requires active thinking. Every new abstraction adds to the overall complexity of the program, so it’s important that you understand what abstractions are really critical for implementing the program.
A program is a very special kind of book. Traditional books can be read linearly from cover to cover, whereas code execution jumps between lines and chapters circularly based on the user input and changes in the environment the program is being run. In a way program is a book that is being read over and over again in a varying order. Writing new software is even more challenging than writing a book, because most software is simultaneously co-written by multiple authors, making it harder to achieve good cohesion and to make sure the common story and all the side plots won’t end up skewed and misrepresented when the changes are applied. This makes writing software largely a communication game between the authors. When the communication fails, manual and automatic verification tests are needed for shielding the program correctness from human mistakes.
Variations in the program behavior are called side effects. Side effects are a major cause of headache and quality problems in software development. Getting a program swarming with side effects to behave correctly is really difficult job. It is like living with an alcoholic dad suffering from mental problems, you never know what kind of mess he gets the whole family in. You should try to keep the number of program states at minimum and make the states you absolutely can’t live without explicit so they are easier to track and validate.
A programmer can utilize programs written by other authors. Programs used by other programs are normally referred to as libraries. Each library provides a set of ready-made abstractions that can be used for writing solutions in a particular problem domain. Including a new library is like going to a school and learning a new skill that you can apply from now on. Using existing software libraries can speed up the development time considerably, but it also makes you dependent on the work and services of others. When problems arise it’s far more difficult to fix flaws in external libraries than in your own code.
A programmer includes libraries to the program similarly how a researcher makes citations to existing publications and uses the abstractions defined in the publications as words to define her own theories. Like researchers, professional programmers should be aware of the important software libraries in their field and be able to apply them flexibly when solving problems. Releasing your program under open source license contributes the program to the knowledge base of the whole industry similarly to how scientific publications contribute to the knowledge base of the entire field.
Powerful and accurate abstractions are critical tools for obtaining correct program behavior. With the right abstractions you can describe the program behavior more simply and concisely. A simple and concise program is easier to change and maintain, which is important as the ability to make rapid changes to a product gives any team a serious competitive advantage.