(퍼옴) http://users.actcom.co.il/~choo/lupg/essays/becoming-a-real-programmer.html

 

v1.0.0

Becoming A Real Programmer (thinking about thinking...)

Table Of Contents
  1. How long will it take?
  2. How critical is self-criticism?
  3. This is too theoretical - how about some examples?
  4. Letting ideas "sink"
  5. Broadening the scope of lessons learned
  6. Short-cuts don't let lessons sink-in
  7. Learning from other people's mistakes
  8. The better programmer you become - the more humble you get
  9. Being lazy the smart way
  10. Conclusions

So you want to become a programmer. an independent programmer, that is not dependent on specific people to hold their hand, that can design a project and lead its development. A real programmer.

Assuming that's what you want to become, and assuming you're not there yet - how do you go about doing that?


How long will it take?

Quite often, it will take you several years to become a real programmer. If you happen to have around you good programmers who are also good teachers, the time could shrink by much. But nothing will make this time shrink more then by you thinking about what you do, trying to develop a plan for your self-advancement, and criticizing your progress, your plan, and your changes to the plan.


How critical is self-criticism?

If you do something, and you think you did well - you limit your ability to do it better next time - because you don't see what wasn't good enough.

If you leave self-criticism to certain occasions (such as after fully completing a given project), you miss the opportunity to learn during this project. Learning means seeing something that wasn't good enough, thinking how to do it better, trying the new way, checking if it improved something, and continuing that until you feel this isn't your worst problem any more. The longer you wait between cycles, the longer the overall process takes to converge.

Of-course, changing things all the time won't work either - cause some methods of operation only justify themselves if used for a long period of time.

Assuming that initially even usage of simple methods of operation will make us work better, we can start with using rather quick cycles, and as we make progress and master the simple methods, we can increase the time between cycles, in order to assess more complicated methods of operation.


This is too theoretical - how about some examples?

Let us take the following example - we were told that documenting code is useful. How useful is it? How much and where to document? we need to write 'according to the book' in our first project. Leave the code for one week, and then come back and try to add a feature. Did we need to read something several times in order to remember what's going on? then lets add a comment there. Some comments were not clear? lets try to make them clear - perhaps write more? perhaps write less? perhaps improve our English grammar?

After we played with documentation for a few month we want to get to work on a larger document - something that explains the general design of a software module, for example. This takes longer to write, and it is hard to assess its quality without fully writing it, leaving that software project for a month, and then getting back to it. Our cycles slowed, because we already learned the simple things (documentation of single functions), and the more complicated methods take longer to complete, and require waiting longer in order to assess their usefulness (you don't forget the design of a module after 1 week, but you easily forget the internals of a specific function after a few days).


Letting ideas "sink"

The method of leaving something and getting back to it later is based on two principles:

  • we need to wait a while in order to be able to look at something in a new perspective - we might have got locked in one manner of thinking, and simply leaving the material for a while often helps us to unlock - because we forgot what it was that kept us locked in.

  • when we need to deal with something new, we often don't fully understand it. If we leave it for a while and then come back to it, we suddenly see things we didn't see before - understand little nuances we overlooked when we were busy grasping the major principles. It could also be that we worked on a different project meanwhile, and when we got back to the original project, we saw how something we learned during the second project, could have been applied to the first project. We correlate.


Broadening the scope of lessons learned

When we find a mistake we made, we can simply find a fix for it and use this fix next time, or we can instead try to check if there is a more general class of mistakes, to which this specific mistake belongs. In the later case, we can find a solution to a whole class of mistakes, and thus not have to learn from different mistakes in the same class - we will avoid doing those other mistakes in the first place.

For example, suppose that we made an error of forgetting to allocate the extra null character when allocating a string in a "C" program. We coul just fix this bug and check the program again. We could think "oh, we didn't think about it", and go over all string allocations in our program to check they don't contain the same bug. We might decide that memory allocation is error-prone in general, and instead of doing the allocation and calculation of required space all over the code - we should write a function that allocates strings. We can broaden this to other types of allocations - and write functions that allocate objects of other types. If we had this problem with allocation, perhaps we have a similar problem with objects initialization - lets write functions that initialize objects, and use them, instead of writing the same initialization code all over the place. We start to see that even very small code re-use reduces the number of bugs in our code. We move from "ah, this initialization only requires 2 lines of code - why write it in a function?", to "repeating these 2 lines of code again and again will mean that if we make a mistake in 1 out of 4 locations in the code - then with 20 such code locations, we will have 5 bugs - all because we were too lazy to write a 2-line function".

See how we got from a specific memory-allocation error, to learning something about avoiding code repetition, which we would have dismissed as "a waste of time" if we were directly asked to do this in the first place.


Short-cuts don't let lessons sink-in

We can argue that an experienced programmer could have shown us all of this immediately, and with enough patience, show us why something that looks trivial can save us a lot of time in the total development process. However, using such a short-cut prevents from the lesson to sink-in. We will still be tempted to choose the quicker path over using the slower path, that makes the overall journey shorter. We have to make our own mistakes in order to learn. Or we have to see how our friends made mistakes and learn from them...


Learning from other people's mistakes

When we learn of a mistake that someone else made, it is easy to think "this won't happen to me, I'm smarter" and dismiss it. But if we already invested time in seeing this mistake, why not stop, reminding ourselves we are only human and in certain situations we might do a similar (stupid) mistake? After we admit this to ourselves, we can go about learning from this mistake, as if it was our own mistake.

One possible conclusion that follows is that helping other programmers fix their own bugs can help us learn, and thus is a useful activity - not just an annoying burden.


The better programmer you become - the more humble you get

Pride is a major obstacle for learning. "I am smart, i won't make this mistake again" is an error that will lead us to do a very similar mistake soon after. "I write good code, so i don't need to check it" will mean our simple local bugs will be hidden, and get exposed later when our module is used by other modules, which make it behave differently then our feeble tests did. By then, the bugs will be harder to track down, because the test-case is more complicated. Thus, we should reverse the cause and the result - "I check my code, and thus i write good code".

Pride will also make us think we can learn everything on our own. Given infinite time this might be true - but life is short. We want to learn faster. Let us, then, learn how to listen to other people's criticism, and weed out the useful parts in their criticism, even if we think the majority of this criticism is wrong or pointless. For example, if someone keeps telling us that we did not test our code properly, while we spent a lot of time on testing, instead of dismissing the criticism - let us listen to it. Several examples that we will be given will be wrong - we did test those parts of the code properly. But once in a while some claim for lack of testing will be correct - aha, we indeed forgot to check that input option. Now that we see it, we can start our generalization process - how do we find all possible inputs and test all of them? if there are too many possible inputs - how do we choose selected test-cases that will help identify most of the probable bugs? How do we choose test-cases in general, not just for testing inputs - what about testing timing problems?


Being lazy the smart way

"I will find the bugs when i debug the code" is the claim of the sloppy lazy programmer, who refuses to read their own code again after they wrote it. The smart lazy programmer will claim "if i put more time re-reading my code now when it is fresh, I will probably spend less time over-all on writing and testing this code module - if I consider the time I spend on it now, as well as during system integration and system testing later on".

The smart ultra-lazy programmer will think even further then this - "if I spend time now on learning lessons, in the long run i will be able to finish programming tasks in a shorter duration, and the time saved in the future will be much more then the extra time i spend now on my lessons learning".


Conclusions

In order to become real programmers, we need to think of what we plan to do. We need to think of what we just did, and of what we did a short while ago, of what we did a long while ago... Then we need to learn lessons. And then we need to broaden the lessons to more generalized classes of mistakes.

We also need to listen to other people - they might see now something that we will only see next year - even if they are not smarter then us. They are simply not locked-in by things locking us in, that we did not identify yet. Or they had the chance to learn a lesson due to a mistake they made in the past, that we didn't come across yet. Perhaps they come from a completely different background, and have completely different methodologies of thinking, that make some bug easier to spot. So we humble ourselves, and listen.

And we must avoid letting our short-term laziness hurt our much-more-useful long-term laziness.

Posted by '김용환'
,