Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Sunday, September 8, 2013

A bit of fun with Zend Framework 2

After writing web applications in Java for about ten years, we recently approached PHP. After a bit of training and experiments on the Zend Framework 1, before starting to actually work on a real product we decided to switch to the Zend Framework 2 (mostly because of a great Zend Framework Day).
But it was only after a few months that my colleagues had started to use the framework that I eventually joined them.

At the beginning it was really frustrating. After ten years of Java, getting "back" to PHP has been somehow weird: I kept using dots instead of arrows, always forgot the dollar sign before variables, yet insisting on declaring their types. Not to mention the syntax to declare and use arrays (which, to tell the truth, I never remember also in Java). But these were not problems, just minor diversions.

My real problem was that I didn't know what happened under the hood, and I mostly proceeded tentatively. In the Zend Framework 2, of which by the way I have quite a good opinion, so many things happen automagically, and some of them are not very well documented. I mean, thanks for a great tutorial for beginners and all, but... why on earth do I have to create an album/album directory for the view? Would it be so terrible to say that there is a folder for the module and one for the controller? Or to explain how camel case turns to dashes and dashes turn to... what do they turn to?

And so, even the simplest tasks seemed daunting. Then, after banging my head on the wall for a while, I slowly started to get the gist of it, up to the point that now I feel quite confident, at least for the basic things.

And then, suddenly (snaps glove), you get a break... all the pieces seem to fit into place

And, hear, I started to enjoy playing with it: controllers, factories, autoloading... and, last but not least, tests. And (and, even if this was the fifth and in such few a lines, I somehow managed to slap in a sixth and a seventh one) I slowly switched from "how the hell do I get this parameter from the route?" back to "where should I put the responsibility of horizontally filtering data"?

Up to the point that I am seriously considering the possibility to REALLY get way out of my comfort zone and submit a proposal for one of the next conferences introducing the framework for beginners like me, trying to smooth the path I have lightly trodden with so many difficulties.

Hey, maybe it's only me, maybe I'm particularly dumb... but then again, somebody could find it useful. As always, I'm wide open for suggestions... but closed for modification :-)

As an end note, I'd like to thank Antonio for being so patient and putting up with my musings, questions and doubts. Looking forward to some more programming fun time together!

Wednesday, March 30, 2011

Duplication is evil, double duplication is worse

Think of an application with a domain model in which a person can have several emails, each of which has a different role (e.g. private, office, preferred, and so on). Persons can choose their preferred email for normal communications, but there are other communications that are normally sent to the email with a given role (e.g. communications about personal health will not be sent to an email which is also read by secretaries); only when an email with this role is missing the system reverts to a default email, which is chosen between the existing ones applying a chain of rules.

In an application like this you could (hypotetically speaking, of course) find a snippet of code that returns the email corresponding to a given role:
public String getEmailForRole(Role role) {
String email = emails.get(role);
return email != null && isValidEmail(email)
? email
: getDefaultEmail();
}

public boolean isValidEmail(String pattern) {
return (...stuff...);
}
The isValidEmail method checks the email against a simple regular expression. This snippet springs at least two different considerations.

Check for correctness

One might think that the check for validity is unnecessary, after all checks are done while inserting and updating, right? Partially. Let's just say all checks should be done there, and let's not forget that data greatly outlive applications, so you could easily have strings with completely different meaning stored where only emails should be. Sounds ugly? Welcome to reality. Sure, you could quite easily find all instances of strings that are not emails, but when the customers asks you to leave stuff as it is you have very little power. Other things I've seen include courses descriptions instead of teachers and documents instead of relatives. To cut a long story short, better safe than sorry.

Be clear on intents

Stick with them and hide mechanics. In particular, here we have a duplicated duplication (pun intended):

  • the check for null values must be duplicated in every snippet that contains emails.get(role)
  • the check duplicates the intent of the isValidEmail method. I think this duplication is worse than the previous one, first of all because the redundancy blatantly hits the eye, but most of all because there is a conceptual duplication: the responsibility for the check should lie in the idValidEmail method itself.

If there's an isValidEmail(String pattern) method I expect it to check for null values without having to bother myself:
public String getEmailForRole(Role role) {
String email = emails.get(role);
return isValidEmail(email)
? email
: getDefaultEmail();
}

public boolean isValidEmail(String pattern) {
return pattern != null && (...stuff...);
}
A more elegant solution could be the creation of an immutable Email value object and the use of the NullObject pattern, a special case of the more general Special Case pattern (another pun intended); in this case the emails object would return a NullEmail object that implements the same interface of the Email class:
public Email getEmailForRole(Role role) {
Email email = emails.get(role);
return email.isValid
? email
: getDefaultEmail();
}
A simplistic implementation of the NullEmail object could be
class NullEmail {

private Role role;

public NullEmail(Role role) {this.role = role;}

public String getValue() {return "";}

public Role getRole() {return role;}

public boolean isValid() {return false;}
}
If we wanted to explicitly return a String instead of an Email object we could slightly modify the getEmailForRole method:
public String getEmailForRole(Role role) {
Email email = emails.get(role);
return email.isValid
? email.getValue()
: getDefaultEmail();
}
As you might have noticed, nothing changed in our NullEmail class - nor in the Email class, which is not shown here.

Of course in this particular case we still have to check for the validity of the email, but in many other places (e.g. print emails of a person for every possilbe role) we can safely operate on our NullObject just as we would on a valid one.

It could be overkill, but it surely gets rid of one of the worst plagues in software: duplication. But that's the subject for another post :-)

Saturday, March 26, 2011

On "Working Effectively with Legacy Code"

In the last few weeks I have spent most of my time working on a legacy system which is going to be partly replaced by a new one which greatly broadens its scope. But what exactly is legacy code? Michael Feathers says that
To me, legacy code is simply code without tests.

It is as simple as that:
Code without tests is bad code. (...) With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse.

Alas, too often the answer is not the one we'd like to hear.

We started out so well

Almost every system, if you have at least decent programmers working on it, starts out as a wonderful green field: defined architecture, code conventions, solid principles, patterns and practices.

After a while the gardeners get busy with other gardens, and a couple of weeds start to poke out. Then some more, then more. And more. Meanwhile seasons pass and rain falls, so our green field gets muddier and muddier. Actually it looks more like it has rained cats and dogs, day after day after day. Mud becomes quicksand, and nobody dares to even get close to it.

The (in)famous spaghetti incident

Too soon the project reaches the point in which whenever you pull a string you have an undesired and often undetected change in a completely different part of the system. When I want to sound important I refer to this as the butterfly effect, a metaphore used in chaos theory. Yes, I know that your projects are different and you have never seen it happen, so try to use your imagination and stay with me a little more, will you?

That was exactly where I was, all tangled up in obscure dependencies: the perfect spaghetti code.


As I tweeted, I love spaghetti when they are in my dish, not in my code, so I had to do something (even because deadlines are always waiting in ambush). To sharpen my tools I retrieved my copy of "Working Effectively with Legacy Code". The book covers many aspects of what we developers have to face daily: instead of the "write once, run anywhere" mantra, we have to deal with "write once, read it at least ten times", but too often our code is obscure. Yes, our code. And we don't have tests, or at least we don't have enough. Do you have a complete coverage? If you do, you have all my respect, otherwise welcome in the family.

How do we get out of this?

First of all, we have to get our code into a test harness, but it is not as easy as it sounds. The book contains a series of 24 different dependency breaking techniques, each of which presented in several almost-real situations, to minimize the impacts of changes and ensure that we are not breaking anything. It sounds like the classic catch-22 thing:

When we change code, we should have tests in place. To put tests in place, we often have to change code.


This is where the techniques come in handy. I was pleasantly surprised when I discovered that, after some years of TDD, almost every problem and solution described in the book sounded familiar, so I skimmed it more than actually reading it. I still remember when I first read it: man it was hard, not the writer's fault, but because of the reader.
One of the most important things is that you have to preserve the behavior of your system when you refactor it (and preserve the rest of the system when you introduce new features or change existing ones), so you should at least know what it does. What is better than some characterisation tests?

Cleaning it up

I love NetBeans. I always have, since it was Forte4Java. Now I love it even more because it has a heap of automated refactorings that make "Refactoring" needless (ehm... that's not true, NetBeans deals with the mechanics, but you should know what you're doing, so stop reading and go buy your copy if you still don't have it. Done? OK, let's get on).

Do you need to create a new test class? nothing simpler, just a simple SHIFT + CTRL + U and a template with all the skeleton methods is ready for you. Just punch in the starting conditions and the expected results and you're done. Feathers describes all refactorings steps by steps, but a few keystrokes are all NetBeans needs to extract superclasses, methods, interfaces, pull up or push down members and methods, delegate, and so on and so forth. Nevertheless, you should know what you're doing.

While working your code could get uglier in some places. It could be temporary, or temporary in the Italian way (which means definitive). Even in the latter case, at least you would have tests in place so that you know you're not breaking anything.

In several places Feathers suggests to reduce incapsulation to put code into a test harness. Somebody might find it strange, extremists might find it insane. Yet...

Encapsulation isn't an end in itself: it is a tool for understanding.


Remember when I wrote that you write code once and read the very same code over and over? What 's the point of an encapsulated design if I spend hours for the most trivial task? Mnd you, I'm not suggesting every field must be public and collections should be directly exposed, but nobody is going die if a private method becomes protected for the sake of testing.

Where have my spaghetti gone?

After a while, one after the other, your pull spaghetti out of your dish, slowly replacing them with neat and tidy sushi.

Before you realize it, you will look at your codebase with different eyes, and chances are that you will enjoy dealing with legacy code. Don't enjoy too much though, even if you have a lot of technical debt to pay: you don't have to pay it for the sake of doing it, but because it allows you to move faster when you need it (and you know you will need it).

Let me stress this again: if I didn't have some hundreds of tests already in place, these weeks would have been months. Baby steps, nip and tuck, red and green bar. But I only introduced tests and refactored legacy code when I needed it, otherwise I would spend too much time on activities that were not a priority. See something rotten? pen it down, fix what you're doing and if you still have time you can deal with it. Look for decisions that could change, but change your code just in time (the YAGNI rule rules).

Friday, January 7, 2011

Where does good code come from?

It is a good question, and apparently several people keep asking it. I found a a visual representation of the problem:


You can find the original here, with many other interesting comics.

The interesting thing is that it seems that coding right and coding fast are like oil and water (or, to quote from the Godfather part three, like money and friendship). But is it true?

At the beginning, it surely is. But, after applying - and applying, and applying, and repeating and repeating all over again - you will actually be able to code right AND fast. That's where katas come in handy. Who knows, you might also be able to exit the "are you done yet" switch before requirements change...

Wednesday, October 27, 2010

InfoQ: Sharpening the Tools

This is a very nice presentation very well led by Dan North. It offers several insights and hints, but I'd like to quote a couple of things.

At a certain point Dan says he doesn't like learning lunches too much, as the fact that you don't commit completely to learning but do it while you're eating somehow implies that education is not important, while it should be part of the job you're (hopefully) being paid for. It is sadly true, yet we have to work with what we've got: it will come as no surprise that I attend all these presentations in my lunchtime, but I found that given the circumstances it's much more effective than trying to reserve a full hour during the rest of the day.

The most important advices are found in the conclusive slide:
  • always assume you're out of date
  • you owe it to yourself to keep current
So... how much do you know what you don't know?

Thursday, September 16, 2010

The FizzBuzz kata

The first time I came over this kata was thanks to a post in which Matteo was looking for design problems. I reckon everyone has played FizzBuzz at school, so I already knew what it was about; I had in mind to try it sooner or later, and it looks like somehow I finally did.

Once I wrote my own solution, I was a little curious to compare it with others, so while googling around I landed on this page which states that

Michael Feathers and Emily Bache performed it at agile2008 when competing in "Programming with the stars" in python, in 4 minutes.

That made me feel a little inadequate, since my solution took a little more to emerge, and I guess it's not because I used Java. But, after all, I'm not Michael Feathers nor Emily Bache, so I guess it's all right.

The solution proposed follows the classic filter paradigm: you register some filters in a list (after all you want the program to say "FizzBuzz" and not "BuzzFizz") each of which processes the output of the previous one. The nice thing is that you can inject filters as you like, which is good: the main class itself has the only responsibility to iterate through the filters, whatever they might do.

My solution is somewhat different, as it is based on the decorator pattern, yet it is similar because you can still inject the decorator, which is built wrapping each rule in the outer one, and the main class has the only responsibility to ask its decorator to decorate the input. If no decorators are provided, a no-op default one is used: this is a small complication compared to the previous solution. Another complication is that the decorator actually knows it's wrapping another decorator, no-op decorator excluded, while a filter has no knowledge of whatsoever other object might operate on the input.

Anyway, the most important thing is that my design satisfies Matteo's (evolving) requirements and supports the Anti-If Campaign :-)

Of course, TDD was used :-)

Don't touch my code

There is not such thing as "my code". If there is, there should not be. This is the basis of collective code ownership: everybody can touch anything. Of course, we MUST make sure that our changes do not alter the existing behaviour (unless we're fixing bugs, or altering behaviour is exactly what we're after, of course).

Sentences like "if you touch my code I'll have to spend a lot of my time to correct your errors" are based on the (hopefully wrong) assumption that your fellow developers commit carelessly modified software. Collective code ownership also means collective responsibility, that should go hand in hand with the "leave your campfire better than you found it" habit.

If I touch "your" code (with which I actually mean "the code of which you were the first author") I magically become responsible for it. But be warned: this is a responsability I share with everybody else in the team. Actually I don't even have to touch "your" code to be responsible for it, as I already am. That's it. Do I see something unclear? I'll try to clarify it. Do I see obsolete comments? I delete them. Do I see comments? I'll probably delete them too, provided that the code speaks enough. If it doesn't, I'll try to make it speak. And delete the comments :-)

Friday, April 9, 2010

A better programmer?

After writing about it a couple of years ago recently I took the BetterProgrammer test.

It turned out I am not so bad, even if I'm sure there's plenty of room to improve my skills, mostly because the tests also track the time it takes you to submit the solutions; I'm pretty sure my answers were correct, as for each task I produced almost all the unit tests I could think of (before I actually produced my code, that's obvious).

The tests were very interesting and can be used as katas; some of them could also be resolved by brute force, but some knowledge of maths and combinatorics surely helped me a lot in writing faster and more elegant solutions (it hasn't given me a penny yet, but it turns out that getting a University degree with full marks has yielded some results after all).

You can check your results against mine here.

Thursday, September 3, 2009

How to fold code in NetBeans

NetBeans editor has always had several nice features, one of which is the possibility to fold code thus eliminating unnecessary noise when working. Normally you can collapse methods, comments, imports, javadocs, and so on just clicking the + sign on the left (or using the CTRL + KeyPad- combination). To expand the collapsed section you can obviously click on the - or use the CTRL + KeyPad+ combination.

NetBeans also offers you the possibility to arbitrarily collapse contiguous lines of code: all you have to do is select the lines you want to collapse and press ALT + Enter, thus showing available suggestions given the context (in our case
Surround with //<editor-fold defaultstate="collapsed" desc="comment">...)


I also found an interesting post on code folding, so I'd like to add my two cents on the subject.

I personally think that all imports in Java classes should be explicit, as I want to precisely know what I'm importing. If I only see a couple of lines with asterisks I might think everything is fine, but that could be hiding the fact that I'm importing a thousand classes, which is definitely a smell. That said, I think this can be slightly different, say, when using Java persistence (or in similar situations): I surely want to see all "important" imports (nice alliteration, huh?), but I might want to hide persistence related imports. This would lead me to a hybrid hiding strategy, which can be confusing, but would hide unnecessary noise in the code, which is good.

About method collapsing I pretty much agree with Dustin, but every now and then I happen to collapse method when I work, e.g. if I want to see different portions of code at the same time on a narrow screen - otherwise NetBeans has the Clone Document feature that lets you reposition a copy of the code you're working on pretty much anywhere on the screen(s) - and I cannot/don't want to move methods around. Of course there should not be too many methods between the portions of code that I want to inspect. Anyway, I always use this kind of folding as a temporary solution except for "non-important" or standard code, e.g. plain setters and getters in simple beans, unlike Dustin who likes to keep all executable code shown - even if I can see his point.

Monday, June 22, 2009

Don't comment bad code

Don't comment bad code - rewrite it.

The quote belongs to Brian W. Kernigham and P.J. Plaugher (and I'm sure to many others). It might sound simple... yet I perceive it as so powerful! It puts your back to the wall with the choice to devote yourself to leave your campfire slightly better than you found it... or to simply turn your head.

Uncle Bob has a similar opinion on the subject:

"Ooh, I'd better comment that!" No! You'd better clean it!

Commenting bad code derives from the fear to actually modify it. But beware:

Fear is the path to the Dark Side.

Get rid of modifiers

When you are performing queries you sometimes want to treat modified letters like their corresponding unmodified ones, e.g. รจ should be treated just like a plain e.

The first algorithm that comes into your mind is probably a long switch of modified characters, which is horribly ugly. The second one could be a map, slightly better but still ugly. Both approaches require quite an amount of work, and I didn't (I still don't) like them.

After investigating a little and asking some friends I was more or less resigned, until Gabriele pointed me to what I was actually looking for: the java.text.Normalizer, that lets you transform an ugly string into a neat one with just a single line of code:

result = Normalizer.normalize(myString, Normalizer.Form.NFD);
return result.replaceAll("\\W", "").toUpperCase();

Now, that's what I call quite good...

Wednesday, May 13, 2009

Become fluent with fluent interfaces

It's been a while since I first read about fluent interfaces, and of course it's been a while I've been using them too, like every test infected guy.

Yesterday I finally decided to give them a try and implement one for a Builder: implementing a fluent interface is embarassingly easy, as basically all you have to do is create setters that return the builder itself and a method that returns the object you're creating.

To give the simplest example that comes to my mind, if you wanted to create an order you could write someting like
OrderBuilder.createOrder()
.forCustomer(customer)
.with(STEAK, 1)
.with(FRIES, 1)
.with(BEER, 3)
.build();
The builder actual code might look something like this:
public class OrderBuilder {

private final Order order;

private OrderBuilder() {
this.order = new Order();
}

public static OrderBuilder createOrder() {
return new OrderBuilder();
}

public OrderBuilder forCustomer(Customer customer) {
order.setCustomer(customer);
return this;
}

// ...similar setters ...

public Order build() {
// ...maybe perform some validation
return order;
}
}
After playing with my code for a while I discovered that implementing a good fluent interface is not as easy as it might seem at first: you have to carefully think about what you really want to do (program by intention), how to clearly express it, and have your APIs reflect it. Nevertheless I think I'll experiment with them a little, they could be another nice trick in my toolbox.

Friday, January 30, 2009

Singletons?

...any global data is guilty until proven innocent
(Martin Fowler)

If you want to be a good software designer, don't optimize code prematurely. [...] If you use the Singleton pattern out of habit, because it "makes your code more efficient", you're prematurely optimizing. You suffer from Singletonitis
(Joshua Kerievsky)

I'm not afraid of a few globals. They provide the global context that everyone must understand. There shouldn't be many though. Too many would scare me.
(Ward Cunningham)

The real problem with Singletons is that they give you such a good excuse not to think carefully about the appropriate visibility of an object.
(Kent Beck)

I mean, it looks like we're not lacking literature on the subject, are we? I wonder why so many people are just too busy with their Singletonitis to consult it (Kent Beck gave a hint on this).

Monday, January 12, 2009

FTP in Java

This one is a reminder as well; the example is not complete but I'm sure that it will be enough to get to the point.

FTP is not directly supported in Java, rather it is disguised behind a URLConnection. Once you've opened the connection you just access the appropriate stream and normally use it:

URL url = new URL("ftp://username:password@your.host/complete/path/to/remote/file");
URLConnection connection = url.openConnection();

To "get" a file you use the input stream:

InputStream is = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(is);

then you create a writer...

FileWriter writer = new FileWriter(new File("complete/path/to/local/file"));

and flush what you read:

int tmp;
while ((tmp = reader.read()) != -1) {
writer.write(tmp);
}

aren't we forgetting anything? oh yes, clean up the room:

reader.close();
writer.close();

The dual "put" operation requires an output stream:

OutputStream os = connection.getOutputStream();

and the core of the transfer loop would simply be

os.write(tmp);

Ok, the read-and-flush code is quite ugly, one would problably wrap the reader in a BufferedReader, append and flush instead of directly writing and stuff, but for version 0.1 it will suffice.

For most advanced needs it is always possible to use the Commons Net.

Thursday, December 11, 2008

Agile and procedural

Today I partecipated in a discussion started by Dennis Morton who asked if anyone had succesfully adopted Scrum, XP or RUP on non-OO procedural based applications. A little rephrased, these are my thoughts.

Scrum is relatively easy. Implementing Scrum could not be that easy because you have to face several impediments: one of the biggest ones is that it clashes with the existing culture, but that does not depend on the particular language you use.

As Keith and Charlie pointed out, life is easier for OO programmers, as there's plenty of relatively inexpensive tools and technologies (if not inexpensive at all) that can help them: Junit, Cobertura, JMock, EasyMock, Hudson, CruiseControl, Eclipse, NetBeans, and so on and so forth in a sparse order, just to talk about Java.

I don't know of similar tools to be used in RPGLE ("inexpensive" and "IBM" cannot share the same sentence) but that might just be my ignorance, so it is up to the team to find a suitable solution (that could also be an expensive but affordable tool).

Anyway, I have to point out that Scrum is just (?) a very good set of techniques for project management, but it is not enough, as you must have in place the proper engineering practices to benefit from the advantages that Scrum offers.

It is useless to give a product owner the possibility to steer the project at every sprint planning meeting if a simple change requires tons of programming hours, as she always has to weight benefits against cost. You can be agile because you have test harnesses supporting your changes. You can be agile because you continuously refactor. You can be agile because all the team members own all the code. You can NOT be agile just because you use Scrum, as you're just exposing problems - problems that most of the times existed well before Scrum was implemented, so don't shoot the messenger. You also have to master the tools to resolve problems. And the first and most important tool is people, so I'm completely with Keith and Charlie who put them in the heart of the process.

We have to undergo a similar challenge as we'll embark on a very big project next year, almost completely based on IBM technologies. As we're starting from about 650 pages of detailed requirements, aged about one year, a remote customer, a distributed team with several new members (not to mention the rest), we'll surely have to cope with changing requirements (no, not the band in which Craig Larman plays in his free time) and lots of other variables and issues.

It is likely we'll have some answers within the next few months; up to now, as it is well understood that we'll have an application layer exposing services, the only thing that I could think of is the use JMeter as an acceptance testing tool. As always, inspect and adapt, rinse and repeat :-)

We're open to suggestions!

Tuesday, December 2, 2008

Collective Code Ownership Part 2

When I write "everyone is responsible for all the code" I also mean that everyone is responsible for all the tests, so if you only have unit tests and you need an integration test... write it! It does not matter if you didn't write the original code or the original unit tests, it does not matter even if you didn't talk to the original developer. It is your responsibility to write it: navigating through an application just to click a link is (almost) completely pointless, and it sure is a waste of time. That does not mean that end user testing must not take place (how could you assert that "a normal user should be able to foobar the barfoo without previous training" otherwise?), but we should strive to automate as much as possible.

This is even harder to assimilate, because not only you have to touch code written by others, but (heresy!) write tests for code you didn't write. It's already hard to persuade people of how much TDD pays off the initial investment and the mental shift, but it's even harder to push them to use tests as a primary way to discover how a particular piece of code works (I often write tests for third part libraries or also for checking the behaviour of java.lang or java.util classes I'm not sure about). I can understand that people fear changes, and that one could be unwilling to change the way he's always worked, but here we're talking about being afraid of one's own shadow. Try it, and try it seriously, and after you did if you still think it won't work (and you won't) you'll still be able to give it up. And... no, "I have no time" is not a valid answer, because not having tests only leads to wasting more time.

Alas, too often I perfectly agree with Gabriele...

Monday, December 1, 2008

Collective Code Ownership

To quote from Wikipedia:

Collective code ownership means that everyone is responsible for all the code; this, in turn, means that everybody is allowed to change any part of the code.

That also means that everyone has to change any part of the code when it is required. Developers cannot shield themselvs behind a "he did it". Even if you didn't partecipate in the writing, the code should be clear enough to allow you to understand it and change it confidently.

By giving every programmer the right to change the code, there is risk of errors being introduced by programmers who think they know what they are doing, but do not foresee certain dependencies. Sufficiently well defined unit tests address this problem: if unforeseen dependencies create errors, then when unit tests are run, they will show failures.

That's true, but... who controls the controller? Just today, after other colleagues were trying to integrate two systems without writing tests (boo!) we wrote a (supposed to be) failing unit test and... it didn't break as it should, as we were testing for equality objects that we clearly knew were different. That was because we forgot to change the equals and hash code methods after adding an attribute to the result class of which our tested method returned an instance, and we didn't have a test on equality on the result class because all the code was generated by the IDE. Nevertheless having a bunch of tests sped the process of finding and fixing the error: if we didn't write a failing test before proceeding we would have spent a lot of time before we managed to find our (not too subtle) bug - time our colleagues actually did spend.

So... always write your tests! That's another supporting example for the "we tried baseball and it didn't work" post: Collective Code Ownership also works because of other practices, such as coding standards, pair programming and unit testing. I'm still convinced of what I wrote, but I certainly agree on the fact that you cannot simply pick random XP practices and hope everything will go well.

Thursday, September 4, 2008

Teach Yourself Programming in Ten Years part II

Ok, back to the comments on the recipe for programming success.

Know how long it takes your computer to execute an instruction, fetch a word from memory (with and without a cache miss), read consecutive words from disk, and seek to a new location on disk.

Unlunckily the great amount of resources brought us to forget the art of good programming. I know I might sound old fashioned, but I can remember more than a hell of a program running on a C64, on which only 38k were actually available, the remaining 26 being occupied by the operating system itself. Nowadays too many resources are wasted, nothing is optimized and a lot of programs are lousy. A word of caution: optimization should not be the first thing you look at, as you should first try to have an understandable and maintenable codebase, and you should really measure and optimize only when it's needed, but there's a limit for everything... Anyway, back to the subject of university, one of the exams I've seated (computer and network architecture) represents a good example of something I've really never used in a direct way but dramatically changed the way I look at software, as now I know how the underlying hardware works, and I know many programmers for which this statement doesn't hold true: e.g. you can see it from the way they write inner loops: if you know how words are stored in memory and in cache you'll chose the order which best fits the underlying physical system.

Get involved in a language standardization effort

mrghmr....

Have the good sense to get off the language standardization effort as quickly as possible.

Now this is more like it!

With all that in mind, its questionable how far you can get just by book learning.

Book learning is not enough. You must try, and try, and try. Well, better yet... Try not. Do, or do not, there is no try. And this comes from the wisdom of Master Yoda, so it should not be questioned :-) Nevertheless, IMHO books play a very important part, because they can start you up and serve as a reference, but there must be a "deliberate effort to improve", so you must bang your head on that wall: that's where my look comes from, it has nothing to do with my 15 years of rugby. And it is fundamental to share your experience with others: you have something to learn from them, they have something to learn from you.

About the three-part plan proposed by Fred Brooks: see the "Work on projects with other programmeres" part. When you work in a small firm with a small IT department it is very unlikely that there exist the conditions to follow the plan, at least inside the firm itself.

Wednesday, September 3, 2008

Teach Yourself Programming in Ten Years

Peter Norvig, Director of Research at Google, has published a very interesting article about the huge amount of IT-related books titled something like "Teach yourself XXX in Y days". Having read my share when I was younger, so much younger than today, I really agree with him, today more than ever.

"Day" is not the correct unit of measure when you talk about mastering something - as the article quotes, researches talk about ten years of effort: that's why you must (should) have fun with programming, because it will take you a huge amount of time. To get along with Mr. Sang Shin, you need passion.

Peter proposes a recipe for programming success, and I'd like to comment about it (I'll skip the parts on which I completely agree and I don't have anything else to add).

Program. The best kind of learning is learning by doing.

I'd like to stress the "deliberate efforts to improve" part: spending ten years programming does not necessarily mean you have ten years of experience, because you could as well count each day as the first one. I know many so-called experienced professionals who are in this situation, some of them because I caught them in the act. 

About the education: it is true that with a lot of work you could skip it, but university exposes you to a wide series of subjects, many of which might not look appealing at first glance (some of them not even after many glances), but it really pays off, as many things will come out useful later or help you to lay the foudations of your future professional growth. Moreover, you get exposed to the judgment of many experts on the field, talented people who can counsel and guide you. It's not that easy when you get to your workplace, where many people only look after their own interests (hey it just so happens that not everybody works at Google!). Unluckily (or luckily, it depends...), there's no direct relation between academic achievements and salary (sigh!). 

Work on projects with other programmers.

That sounds easy. Unluckily, sometimes you just have to rely on yourself, or on a very few other people: many customers of ours have just one to three developers, one of which is tipically a "legacy programmer". But it is a great advice, and this is where external groups (e.g. JUGs or XPUGs) come in use.

Work on projects after other programmers.

Far too easy not to follow this one. Browncode represents a huge percentage of a programmer's job, so everybody should know what we're talking about. But crap is not always the best source for knowledge, so it is also important to study and try good code - there's plenty of good open source projects out there, and if you have the time getting involved in one of them you get a very good opportunity to learn a lot.

Learn at least a half dozen programming languages.

IMHO that's hardly feasible or doesn't have the right ROI, particularly in small realities such as ours. My idea is based on the fact that a language that does not need a shift of paradigm is not worth studying (as quoted in the article) and on the necessity to optimize costs and resources. How much does it take to really understand and correctly use a functional language? is it worth the effort? In my particular case it is not, at least for the time being. Should there arise a different need, things would obviously be different. So, I would translate into "have a look at not less than half a dozen programming languages, so that you can select the one that best fits your needs on a case by case basis".

Sorry really have to go... to be continued!

Monday, August 11, 2008

Growing Object-Oriented Software

Steve Freeman and Nat Pryce are posting online parts of a book they're working on, called Growing Object-Oriented Software, Guided by Tests. Should anyone be interested in giving feedback, they provide a Yahoo discussion group.