Consider the following code:
We are trained very early to write code which is easy to maintain. This means that other people should be able to understand it, it means that we should be able to understand it when we look at it a year later, it means that the clever bits should be easy to reuse. All worthy goals, all of them eventually translate into time and money, and all have to do with software development and management.
Many developers continue to explore this aspect of programming, and study class design, and interface design, and design patterns. People will engage in debates on underscores vs. camelcase, or on composition vs. inheritance.
It is not the contention of this post that these discussions are without merit. They are the process-aspect of software development, and processes are important. Standards are important. It is important not to make mistakes, which could have been avoided by standing on the shoulders of those who came before.
But sometimes we forget that we write programs to do things. When I was a younger programmer, I was just so excited that there were so many ways to express my ideas, so many ways to design my functions, and my classes, and my class templates, and oh-look-isn't-this-the-command-pattern.
This post contains my view of how a programmer should develop, heavily biased by my own experience and my own mistakes.
Stage 1
Programs are mysterious and esoteric. Error messages from development tools are frightening and make no sense. But working on the command line feels cool. You hope that people will notice the code on your screen and be in awe of you.
Stage 2
The compiler / interpreter works. You understand that the program has an entry point, does some stuff, and then exits. You understand control structures and you know that your functions and variables should have descriptive names. And you're learning that debugging is a huge pain.
Stage 3
You can use libraries and modules written by other people. You have become comfortable with incomplete or incorrect documentation, and can get your programs to do what you want them to. Debugging is no longer a pain and you see it more as a challenge. But you still spend too much time doing it. You view your programs and a collection of classes and functions, and understand the relationships between them. You read Design Patterns and start looking at your own code to find patterns (patterns!) and update your resume accordingly.
Here's some advice: Don't read Design Patterns. Not as a young programmer anyway, not unless your job demands it. Don't read about class design in general, the meaning of protected inheritance, or about when virtual functions should be private.
Instead, focus on making your programs run better. No bugs, tight execution, compact memory footprint etc. Yes, RAM is cheap nowadays, I'm not trying to encourage cost savings here. But I think it is more useful for a programmer to consider the run-time aspect of their program rather than its static nature.
Stage 4
You have developed a data-centric viewpoint, i.e. you know what the data looks like, where it comes from, how it is modified, where it ends up. You know which data is short-lived and which is going to be around for a while. You can shift your viewpoint of a program back and forth between "procedures passing data to and from one another" and "data being acted upon through its lifecycle".
Let me talk about these two viewpoints for a minute. Viewing a program as being made up of entities passing messages to one another is very useful. We tend to talk of those entities as being "objects", and these objects usually do things i.e. they are actors.
But objects can also be just data (although some people frown upon objects with only state and no behavior), and one can view their programs as being collections of objects in different stages of development. In this viewpoint, the actors are de-emphasized and the focus is on the objects being manipulated. For example, one may talk about how a string field in an object is converted to uppercase - with no mention of the
You may also start looking at data management libraries and services, like caching services, service buses, and message queues. You wonder if you are dealing with Big Data, and put it on your resume anyway. And you can often debug problems in your head because you don't have to look at the code to know what it's doing.
Stage 5
Now that you view your programs primarily as runtime entities, you can come back to the static viewpoint. Now when you think about class design and modularization, you will have the runtime model in mind - first and last. And now you will create beautiful designs, engineered for performance as well as for manageability.
1: int x,y,z;
2: str a,b,c;
3:
4: x=0;
5: a="A0";
6: print(x, a);
7:
8: y=x+1;
9: b="A1";
10: print(y, b);
11:
12: z=y+1;
13: c="A2";
14: print(z,c);
15:
and compare it to:
1: for (int idx=0; idx < 3; ++idx)
2: print(idx, "A" + str(idx))
Both do exactly the same thing, but anyone who has been writing code for more than a few months knows that the second version is vastly better. And if you ask us why it is better, we will tell you that
- It is easier to read
- It is easier to debug
- It is easier to modify
We are trained very early to write code which is easy to maintain. This means that other people should be able to understand it, it means that we should be able to understand it when we look at it a year later, it means that the clever bits should be easy to reuse. All worthy goals, all of them eventually translate into time and money, and all have to do with software development and management.
Many developers continue to explore this aspect of programming, and study class design, and interface design, and design patterns. People will engage in debates on underscores vs. camelcase, or on composition vs. inheritance.
It is not the contention of this post that these discussions are without merit. They are the process-aspect of software development, and processes are important. Standards are important. It is important not to make mistakes, which could have been avoided by standing on the shoulders of those who came before.
But sometimes we forget that we write programs to do things. When I was a younger programmer, I was just so excited that there were so many ways to express my ideas, so many ways to design my functions, and my classes, and my class templates, and oh-look-isn't-this-the-command-pattern.
This post contains my view of how a programmer should develop, heavily biased by my own experience and my own mistakes.
Stage 1
Programs are mysterious and esoteric. Error messages from development tools are frightening and make no sense. But working on the command line feels cool. You hope that people will notice the code on your screen and be in awe of you.
Stage 2
The compiler / interpreter works. You understand that the program has an entry point, does some stuff, and then exits. You understand control structures and you know that your functions and variables should have descriptive names. And you're learning that debugging is a huge pain.
Stage 3
You can use libraries and modules written by other people. You have become comfortable with incomplete or incorrect documentation, and can get your programs to do what you want them to. Debugging is no longer a pain and you see it more as a challenge. But you still spend too much time doing it. You view your programs and a collection of classes and functions, and understand the relationships between them. You read Design Patterns and start looking at your own code to find patterns (patterns!) and update your resume accordingly.
Here's some advice: Don't read Design Patterns. Not as a young programmer anyway, not unless your job demands it. Don't read about class design in general, the meaning of protected inheritance, or about when virtual functions should be private.
Instead, focus on making your programs run better. No bugs, tight execution, compact memory footprint etc. Yes, RAM is cheap nowadays, I'm not trying to encourage cost savings here. But I think it is more useful for a programmer to consider the run-time aspect of their program rather than its static nature.
Stage 4
You have developed a data-centric viewpoint, i.e. you know what the data looks like, where it comes from, how it is modified, where it ends up. You know which data is short-lived and which is going to be around for a while. You can shift your viewpoint of a program back and forth between "procedures passing data to and from one another" and "data being acted upon through its lifecycle".
Let me talk about these two viewpoints for a minute. Viewing a program as being made up of entities passing messages to one another is very useful. We tend to talk of those entities as being "objects", and these objects usually do things i.e. they are actors.
But objects can also be just data (although some people frown upon objects with only state and no behavior), and one can view their programs as being collections of objects in different stages of development. In this viewpoint, the actors are de-emphasized and the focus is on the objects being manipulated. For example, one may talk about how a string field in an object is converted to uppercase - with no mention of the
TextConvertor which derived from a StringManipulator and created by a DataModifierFactory.You may also start looking at data management libraries and services, like caching services, service buses, and message queues. You wonder if you are dealing with Big Data, and put it on your resume anyway. And you can often debug problems in your head because you don't have to look at the code to know what it's doing.
Stage 5
Now that you view your programs primarily as runtime entities, you can come back to the static viewpoint. Now when you think about class design and modularization, you will have the runtime model in mind - first and last. And now you will create beautiful designs, engineered for performance as well as for manageability.