Saturday, November 30, 2013

A Code for Software Professionals

Robert Martin defined "Professionalism" in the context of "professional software engineering" as the "disciplined wielding of power".  You can catch the talk at a ruby conference in 2009 which is called "What killed Smalltalk could still kill Ruby".   You could substitute "Delphi" or "Your Career" in place of the word "Ruby" there, if you think that having Ruby in the title of the talk means that anything in that talk is unapplicable to you, Delphi programmer.  If you think that your use of Delphi makes you immune to the ill fates that befall other developers, other teams, using other languages, then you have the very disease at the heart of Bob's talk, and you are exactly the person who needs to watch the video here.

About 42 minutes into the talk, he switches from a passionate cry to developers to commit to test-driven development practices, to talking about Professionalism and gives the definition about "disciplined wielding of power".  It's excellent, and I agree with everything he says.

I would like to give my definition of what a software professional, a member of a team, large or small, or even a single developer working on his or her own, should be doing, if they wish to be a consummate software Professional.

I would also like to hear your professional credo, if you have one.  All of this presupposes, I think, that we are people motivated not purely by money, by power, by position, by a search for comfort and material things, but rather, motivated equally by a desire to do a job well, to do something that is objectively Good, worthy of the limited time we all have to do what we choose with.  In the long run, we are all dead.  So why are we doing any of what we do?   I would say that to do a thing well, to do it professionally, as your career, your vocation, your job, from 22 when you graduate college, until you retire at 65, or leave this life, means, I hope that writing software is something you do because you love it, and you want to do it well.

Here are my five cardinal rules. Yours may be different. Mine flow from a common core conviction that everything I do has a moral component, and that I will be ultimately happy if and only if I do what is objectively morally good. Why I think that, is off topic for this blog. But the fact that I do think that way is what illuminates and ties together the five points of my personal credo as a software professional:


1.  Do the work you get paid to do. I am a professional. Part of the meaning of that word is that I get paid to write what the people who pay me tell me to write, and I build it according to their rules, conventions, styles, and preferences.  When I'm finished, I got paid, and I got the satisfaction of doing a job well and they own what I built. I respect their intellectual property rights. I don't steal, and I don't dissemble or delay. I also keep my employer's trade secrets and source code private.   I also believe that wasting a day that I got paid to do software by doing nothing is stealing, and so I don't do it.  When I'm out of ideas about what to work on next, I ask what I should do. I try to work on the most important stuff first, so that what I do in a day moves the ball forward as much as I can.

2. Tell the truth, and shine light, even when it's uncomfortable, but be kind to people, when you choose how to speak that truth.  I try to be honest.  I mustn't ever lie.  I also try not to blame people.  I try to take blame, accept responsibility.  If I work in a team, either as leader or senior developer, I try to absorb blame and share praise. If someone praises me I'm likely to mention what another person provided that helped me. This helps me to work with other people, because they know I will accept responsibility for mistakes and will not throw a colleague under the bus. I also won't make up stories and try to lead people on merry chases, when they try to figure out what's going on in a project milestone, a team meeting, a product review, or a coding task or a bug.   Lies can include omissions.  Leaving something out of a commit comment could be a form of lies.  I think that humility and honesty are only possible in tandem. When I become proud, and arrogant, which I sometimes do, because I am only human, it is the desire to be honest that helps me pop the bubble of pride.  When I am able to be humble, I find that my conscience prompts me to mention things that are less than flattering. For example, "I fixed this bug, but I am worried that there might be a side effect and I don't know how to prevent this side effect, but if I tell someone now, I think it might be better to discover the side effect now, rather than try to hide the fact that I may have created a bug with this bug-fix, and I don't want people to blame me".

3.  Model and reflect moral Goodness, and presume good will in other people. I try to expect the same virtues from other people, that I expect of myself, and if I do not see that happening I try to privately, and positively, encourage the behaviours in others that I expect in myself. I find it is possible to encourage fellow developers by modelling my willingness to accept blame, but not attacking people ever.  If I see someone attack a person, instead of attacking a problem, or doing something that is making an issue personal instead of professional (we should fix this issue, versus, you are bad, and should feel bad, because you made a mistake or didn't realize that this is bad) I try to encourage a return to objective, practical solution of the actual problem. I try to preserve good will because it's very hard to get it back when it's gone. I  think teams need good-will and goodness to each other even more than they need technical competence, and by gum, they need technical competence too.

4. Achieve technical mastery the only way it is ever achieved, by lifelong learning.  You don't know everything, and neither do I, and even what you do know today, you will forget tomorrow.  I don't know jquery. I  don't know Big Data. I don't remember very much X86 machine language anymore.    And you know what? I don't have to.  The most important technical skills I have are how to learn something new, and how to bisect problems until I find their root causes. With the ability to learn new things, learning is a joy instead of a burden. If you don't like learning, and you don't like bisecting technical problems until you find the root cause, you chose the wrong career,  my brother or my sister, I suggest you find another.

5.  Follow the Boy Scout rule, even if you're a girl. Be sure at the end of the day that you leave the world you lived in, the job you worked at and the codebases you contributed to  better after you worked on them, than before you worked on them.  Bob Martin calls this the "Boy Scout Rule", referring to that "leave the campground cleaner than you found it", but pointing out that the "campground" Baden Powell was referring to was actually the whole world we live in.    I think that the real Professional looks at the ends and the means, the goals, and the values involved in all the work he or she does, and asks "am I comfortable with this, is this the best we could be doing, and are we doing this the right way?".    If I got paid to make a mess, and to contribute to a project or a company failing completely, I do not obtain any sense of wellbeing or personal pride of a "job well done" from that. I wish to do good, to be part of a team that does good, and which builds not only economic value for my employer, but also contributes to the complete wellbeing of the team, the company, its customers, and the wider world around me.  This is all part of being a good human being.

Why do I share this with you? Because I want to do something with my life that is good. I want to be worthy of what I get paid, and more. I want to be the kind of person who anyone would hire, and hire again.  Don't you?  What do you think? I welcome your thoughts.  Do you ever reflect on the meaning, and purpose of your life as a software developer? Because I do.  Am I crazy for doing that? I think it's crazy not to do that.

Software development is not a profession in the sense that Medicine, Law, and Engineering are professions.  Not yet anyways. But if we can learn how to become professionals, it will be good for everyone in the world. Even if the software you write doesn't cause airplanes to fall out of the sky, or accidental acceleration of your Toyota Corolla when it fails due to a lack of tests and testing, there are still many other good reasons to be a Professional who cares about the whole quality of the enterprise we are engaged in. That means caring about TDD,  or any other thing, if and only if, it leads to the desired goal;  To do good things, to do them well, and to be responsible in the use of the tools and the time we are given.







Saturday, November 9, 2013

When all you have is a hammer, everything looks like a nail.

I frequently run across questions like this one on Stackoverflow.  The person is asking how they might avoid hand-coding complex INSERT statements, using TADOQuery.   My comment in this question reads:

You might find it easier to use a dataset (TADODataset or TADOTable) to do a dataset-like-job, and use a TADOQuery to do a query-like-job. Oh, and there is TADOCommand to run a Command. So if you're writing SQL "insert" strings, you might want to look at running those with TADOCommand. And you might want to avoid writing them at all, and just set field values and insert into a TADODataset.
 This is a common coding anti-pattern:

The "All I Have Is A Hammer, So That Must Be a Nail" Anti-Pattern:

  1. Try something, it works on Tuesday July 1st, 2001 to solve the problem you had on Tuesday July 1st, 2001. 
  2. This is now the Standard Way You Do Everything Until the Day You Retire Forever from Coding.
  3. Do not reflect on whether you are forcing round pegs into square holes, but simply continue to develop a large body of "cargo cult" programming practices that were functional once, and are optimal almost never.

Why do we developers do this?  Because we know how to build one solution to a problem, we often stop looking for more ways to do this.    Learning about using the IDE (especially the debugger), and learning about using (and writing) components, understanding the entire Pascal language, these are all dimensions of learning to be a Delphi developer.   As a single developer learning, the pitfall is to stop too soon.

As a team, this pitfall morphs into a collective trap.  Developers working on a team must communicate "rules" and "best practices" to each other, and must agree and work together.  Working together is a whole other topic that I wish to brush past, but let's just do that, and ask, "how do teams create and modify the set of established rules and conventions they use, and do they ever fall into trap B while they try to avoid falling into trap A?".   Do rules that teams make, ever become "dogma"?  Are they written without qualifiers, or exceptions?  If so, then your team practices can force developers into the "Everything is a Nail", so "Hit it with the Hammer" trap.
 
I can list about 20 common "Hammer/Nail traps" that I have seen developers fall into, and they usually involve the word "always" or "never", and seldom involve the words "think about it", or "use when appropriate":

  1. Never use EXIT
  2. Always use EXIT
  3. Never use GOTO
  4. Always use GOTO
  5. Always put begin and end and never use single statements.
  6. Never put begin and end around single statements.
  7. Always use Data-Aware-Controls.
  8. Never use Data-Aware-Controls. (See Footnote)
  9. Always use Test Driven Development.
  10. Never use Test Driven Development.
  11. Always use Objects, Generics, and Gang-of-Four Patterns, and write your Pascal code like it was Java.
  12. Never use Objects, Generics, or Patterns, and write your Pascal code like it was Turbo Pascal and it's 1989.
Why do developers get stuck in the "always do X" and "never do X" patterns? Why do we argue and fuss about these rules?  I would like to suggest a constructive idea about why:

Solving problems is hard.  When the solution space (the number of things you have to try) gets large, your brain shuts down.  By closing down the "Go Left, Go Right, and Go South" rules in your brain, and leaving only the "Go North" rule, as the One Rule you always follow, until you hit a wall, at which point, your "Rotate Counterclockwise 90 degrees" rule kicks in, developers find it easier to navigate the complex maze of decisions that we make every day when we seek for solutions to our coding problems.   When a solution has worked many times in the past, we sometimes promote our solutions into dogma, like this:

1.  Once, I found it confusing that someone put an exit statement in the code, and I didn't notice it when reading the code, and so the flow of the program was confusing to me as a human being even though it was not confusing to the compiler.
2.  Due to my inability to read and see Exit statements, they are similar to Goto statements, and since they are similar to Goto Statements, and Goto Statements are "Considered Harmful", as everybody knows, they go on the no fly list.

Now let's look at code written without exit statements:

procedure  TMyForm.MyButtonClick(Sender:TObject);
begin
  if ValidationFunction1(param1,param2,param3) then
  begin
     if ValidationFunction2(param4,param5,param6) then
    begin
        if ValidationFunction3(param1,param2,param3) then
        begin
        if ConfigurationStateDetection(param1,param2,param3) then
        begin
           DoSomething;      
        end
        else
        begin
           DoSomethingElse;
        end;
    end;
  end;
end;

This could code be written better as:

procedure  TMyForm.MyButtonClick(Sender:TObject);
begin
  if not ValidationFunction1(param1,param2,param3) then
    exit;
 
  if not ValidationFunction2(param4,param5,param6) then
    exit;

  if not ValidationFunction1(param1,param2,param3) then
    exit;
  
  if ConfigurationStateDetection(param1,param2,param3) then
  begin
      DoSomething;      
  end
  else
  begin
      DoSomethingElse;
  end;
end;

The above is intended to be a sample that is an order of magnitude less complex than the worst "nesting of begins and ends" that I have seen in the field, at places where "exit" is discouraged or banned.   Practice 1 (which has some merits, I understand about exit being confusing to developers), causes Problem 2.

If you're going to make the rule "no exits", then you should have a better solution for a flow chart like this, that is better than nesting 30 blocks deep with begin and end:



There are exit-free solutions but most of them are far more baroque than just using exit, and if you are comitted to your rule "no exits" you should choose one, and make sure people know how to construct something that is less of a mess than a block of 30-nested begins and ends.  But then, when you're done, ask whether that finite state machine engine you invented isn't just your brain hiding an Exit-like and Goto-like language statement underneath some new layer of bafflement.

Let me suggest a better set of rules, either with the always/never removed, or at least, weakened with an appeal to developer rationality.



  1. Never use EXIT, when something better exists.
  2. Always use EXIT, when no better solution exists.
  3. Never use GOTO, when something better exists.
  4. Always use GOTO, when no better solution exists.
...  I think I can leave the rest of the list as an exercise for the reader.

So here is my Rule about Coding Rules:

A.  When you think of a coding rule or best-practice, keep your mind engaged while using that practice, and look for places where that practice creates as much or more trouble than it solves.
B.   When you share your ideas about coding rules within your team,  add conditions like the ones I added above in blue, that make it clear to team members that these are not Cargo Cult practices, but active thought processes that the team uses to develop software.

As a single developer in a team, it's your job not to create endless waves of complaints, but when you see something that is not working, or which is causing problems, it's important to find ways to discuss these issues.  At all times, you should avoid insults or personal comments.  If the team's best practice is to indent or format or organize code in some unusual way you've never seen before, and which you find yourself unable to understand and deal with (something I experienced personally at one place I worked),  you may find yourself tested to the very limits of your ability to cope with the zeitgeist at that team. I know I did.  If you're like me, and you like there to be a "why" or a reason for things being the way they are it may frustrate you to no end that people are in fact, not automatons whose behaviour can be predicted or explained by mere rational analysis, and often do the same things over and over for reasons that may be inscrutable to you, not knowing or caring why they do them this way. I'd like to reiterate why teams are like this:

People do things the same way over and over because that's how the human brain works.

Becoming aware of this, and trying to point out that people are hammering screws into plywood with a hammer, because all they've ever used before is a nail, is a bit of an extreme metaphor, and seems insulting, really, at some level.  But we have to remember that "nails" may have been 99.9% effective in all the places where developers have tried to use them.  Your team might think "TADOQuery is good, and TADOCommand and TADODataset and TADOTable are bad", for instance, because that got you out of some bad situation once, and now that is your rule.  But ask yourself, are you being introspective and is your team able to discuss this, or do you just "put your head down" and not ask questions, not think outside the box.

Going back to the StackOverflow question that inspired this post, I would like to point out that I am not trying to pick on a new Delphi user who is just learning.   But I do find that I myself sometimes fail to learn all that could be learned about a tool or an environment, and I tend to repeat using the same pattern or solution myself, and that I notice this problem in myself, and that I humbly offer this reflection to you, if it is of value:

Ask yourself, every day: "Are there ways to do this that I have not thought of?", and "If I don't know a better way but I sense something is off here, can I ask a colleague for suggestions, and could we find some more efficient or more optimal way to do this?".    So, in the end, the StackOverflow person who asked this question is more right, and more of a good example, because he or she asked a question, and got a lot of feedback from the big crowd of Delphi Geeks on the Internet.

That might be the smartest development best-practice of all.



Friday, November 8, 2013

Surface RT takes a diRT nap

Windows is an operating system for desktop computers. It runs fine on Laptops, but the move to a closed hardware platform (like RT) with a codebase like Windows has lead to the modern anomaly known as Windows RT.

I bought a Surface RT with the intention of learning WinRT development (in Oxygene or C#) with it, in September.    I upgraded without incident to WinRT 8.1.  Then, some time yesterday, the Remote Update gods at Microsoft sent an update to my machine, which bricked it completely.

I have initiated an in-warranty exchange online with Microsoft.  I decided to try to buy an extended warranty on my WinRT surface device.  No offers are available from Microsoft at this time for the first generation Surface RT.

Is that not a tacit admission by Microsoft that the first generation Surface RT is a ticking time bomb, of uninsurable proportions?   Let's see.  Secure boot. Remote update.  Battery rundown.  Let's let it update when it's not plugged into the wall.  Can  anyone guess the unavoidable end results?  It should take about 30 seconds to figure it out. Microsoft's engineers obviously couldn't.

Update: A new surface arrived, and the old one was shipped back.  I'm quite happy with Microsoft's exchange program. However now my Surface RT locks up randomly during use.   Perhaps I have received a "refurb" unit that has a problem?  Lovely.  I may try to contact support again and ask them about it.