We were at a meeting with our customers the other day. The meeting was about the new release of our software - we showed them what we are trying to achieve, and requested their comments. One of the users who attended the meeting just couldn't understand why we keep releasing the software, fixing it, releasing it again, adding more features, releasing it again, etc. His exact words were "Why do we need all these meetings, and so many releases? Can't you just think really hard about the software before you work on it, and then release it with all features intact? Why can't it be complete to begin with?". And he asked this very seriously, like he just couldn't understand why our behavior is so weird. All we could do was smile, and tell him that we wish it was as simple as that.
I believe that there is a step that every developer must take. For lack of a better term, I will call it the Plunge into Knowledge. I've seen it happening many times, and it happened to me as well. You start your development life by doing your job. You get a task, you do it. If you hit a snag, you turn to one of your co-workers for advice. If they hadn't yet taken the Plunge themselves, they will give you the best answer they have, an answer they probably received from someone else who used to be in the team. Many accept that and move on. They don't try to search for a better answer, even though for all they know, the answer they got is 10 years old and there might be a much better solution. They don't try to improve as they don't feel there is anything to improve. So they keep at it, never going forward, always with their head in the ground.
If you're lucky, you'll either wake up from this illusion yourself, or someone will be there to wake you up. And so you dive into a world of knowledge: books, web-sites and blogs full of information. And you find out there is a huge amount of people out there doing the exact same things you're doing. And some of them have found better ways of doing these things. And you realize that what you've been doing for so long and taken for granted, shouldn't have been done this way at all. You see how blind you were when you weren't learning new methods, new technologies, when you weren't improving.
If you're reading this blog, that means you've taken the Plunge, so feel good about yourself. I know many developers who don't read any blogs at all, that have never read a single software-related book. They're happy in their ignorant little spot, oblivious to the storms raging outside. I used to be like that as well. While I was at college, and up until the end of my first year at work, I was doing my thing, developing ASP.NET 1.1 and feeling good about it. Can you imagine that I never even bothered to read about .NET 2.0 until my team was about to transition to it? That I haven't downloaded any of the early versions of Visual Studio 2005? It seems ludicrous to me now. A new technology, which offers to change a lot of the way I work, was on its way, and I hardly paid it any attention. I finally opened my eyes, thanks to some of my team-mates, and was overwhelmed by the amount of things I don't know. Overwhelmed by all the technologies that were either here for a long time or about to come out soon. It seemed that it would take me years to catch up. But you can't swallow an entire ocean, so you take small sips. On the way, you become a much better developer than you've ever been.
I think that it is your duty to make sure people around you take the Plunge. You'll produce much better software this way, and you'll have more fun as well. When you're constantly learning and trying new things, even difficult times seem a lot brighter.
Have a great holiday, and don't forget to breathe.
I've finally finished reading the excellent Peopleware book, and would like to share with you some of the notes I wrote to myself while I was reading it. Here we go (erm, spoilers up ahead, I guess...).
- Projects fail because of people (politics, communication, etc.), not because of technology. And yet we spend so much of our time worrying about this software or that tool instead of dedicating our time to the most important thing: taking care of our people.
- Working overtime for long periods of time is bad, and you'll pay for it in terms of employees' satisfaction and recuperation time. In the short run it might seem like it pays off, but in the long run you'll get sad developers and low quality products.
- Developing high quality software is more important for the pride of the developers than to your customers. That is, it is important for your team's morale that you develop high quality stuff, instead of rushed, buggy and unmaintainable solutions.
- "Parkinson's law almost certainly doesn't apply to your people". This sentence took me by surprise, I must admit. Parkinson's law says that work expands to fill the time allocated for it. If you assign a task two months to complete, that's how long it will take (at least). I always believed this to be true, as I thought that people tend to let themselves "wonder about" if they feel they have the time to do so. The authors claim it is simply not true, and they show a research that backs up their case. On projects in which there was no time pressure at all (no deadline, we're done when we're done kind of thing), the productivity was a lot higher than in projects that did. And yes, it does make me wonder.
- The reason "you can't get anything around here between 9:00 and 17:00" is crappy work environments. Most workplaces suck in this regard. They are noisy, full of interruptions and they just don't allow you a moment to think. I could certainly relate to that, as I'm really a guy that needs his thinking time, and on some days it is just impossible to find 5 quiet minutes to yourself. Usually it means I will stay at the office a bit later than everyone else, so I can finally get something done. The authors go about how to build the best work environments, but I won't get in to that.
The important thing to remember is that you must allow your people to work during the standard working hours, by providing a maximum number of uninterrupted hours each day. That is, hours in which you just work, no one calls you, no one talks to you, you can get in the "zone" (or "flow" as the authors call it) and just work. Since each interruption takes you out of your zone ("Hm, where I was I before that phonecall...?") uninterrupted hours are the time in the day you make the most work progress. In my current workplace, it saddens me to say, I think that you get maybe 1/2 of uninterrupted hours during the normal work hours. The culture of our organization was not created, apparently, by managers who read Peopleware. It's too often that I hear my team complaining about not getting to code at all in certain days. It is my goal to give each of the members of my team 2 whole uninterrupted hours between 8:00 and 17:00. Ambitious, yes, but I believe this will improve our productivity more than anything else.
- The best organizations are consciously trying to be the best. This is a part of what turns a workplace to a community.
- The concept of a jelled team. The jelled team is a team of people that complete each other, that create a whole that is greater than the sum of its parts. Being in a jelled team is what will make you enjoy your work, and there's nothing better than working in a job you enjoy. It is the best thing for the organization as well, as a jelled team will perform a lot better than a one that isn't.
The authors don't tell you how to jell a team, they can't - it either happens or not. But they do tell you what will definitely ensure that your team is not jelled. Things such as defensive management (not trusting your people, trying to control their every action), bureaucracy, and phony deadlines (trying to set an early deadline just for the team to work harder) among others. I think that this chapter, called "Teamicide", is the most important in the book. I would recommend everyone to read at least it, if not the whole book, and take a good look at yourself and at your organization. Are you killing your teams?
I would like to believe that my own team is in the process of jelling. We've been together for about 9 months already, and I feel that the members do complete each other. And we're having fun, which is the most important thing. What worries me is a current organizational move into "matrix" development. That is, instead of a team of people that stay with each other, assign a specific group of people for a specific task. It might look like the most productive thing to do (make better use of people's skills), but I believe it will prevent teams from jelling, and hence will kill productivity.
- People hate change. They really really do. And yet you have to change in order to improve. There will be chaos at first, and that's OK, since that's the nature of change. Soon things will converge again, and you'll be at a better place. This really relates to my current attempt at implementing TDD at my team. Most of them are now in the stage that they hate writing unit-tests. They understand the importance of it, I think, but the change for them is really hard. It is a new skill to learn, a new way to do things, and therefore we are now at a stage of chaos. But that's an integral part of every change, says Peopleware. Expect it.
- A manager's greatest sin is wasting his people's time. Your job is to maximize their work time, so don't consume it without a good reason.
If anything, I hope I motivated you to give this book a read. I think it is a must for anyone in a management position.
And last but not least, Shana Tova everyone! May you have a year full of good surprises, wonderful, bugless code, and of course, dancing chickens. (oh, come on, who doesn't like a dancing chicken?)
The .NET 2.0 framework has been here a while, but if you're like my team, you're still using a lot of code that you wrote back at the .NET 1.1 days. It's likely that many of these methods are using non-generic collections. This poses an annoying issue. Check out this method:
public IList GetAllUsers(IList userCodes)
IList list = new ArrayList();
//Add the users here...
On the one hand, you don't want to touch the older code. It is working, it doesn't have unit-tests, and anyway - It is just not feasible to go and change all your older code to use generics. The method might be even in a closed DLLs that you can't change.
Still, you are now writing new code, and you want to use the old methods. Now, you don't intend to write new .NET 2.0 code with non-generic collections, are you? So what are you going to do? Well, this:
private void PrintSomeUsers()
List<int> userCodes = new List<int>();
IList<User> users = Algorithms.TypedAs<User>(GetAllUsers(userCodes));
OK, so what do we have here? First, we are instantiating our generic list, and adding some numbers to it. Next, we are calling the GetAllUsers method. We can just past it the userCodes list, as List<T> thankfully implements the non-generic IList. Now, the magic happens when we call Algorithms.TypedAs<User>. This method belongs to the very useful PowerCollections library. It wraps our non generic collection, that was returned from GetAllUsers, with a generic coat. This prevents the need to copy the IList into an IList<T>, as some people might do, and therefore it is a lot more efficient, and elegant. Our next use of the Algorithms class is the ToString method, which simply creates a string representation of a collection. Note that overloads of Algorithms.TypedAs exist for ICollection<T>,IEnumerable<T> as well (they return ICollection and IEnumerable, respectively);
This is all nice and dandy, but in our case, GetAllUsers would have looked like this:
public ArrayList GetAllUsers(ArrayList userCodes)
ArrayList list = new ArrayList();
//Add the users here...
The idea of using Interfaces in method signatures seemed to escape us back than, and now the bad practice came back to bite us. List<T> does not have a cast to ArrayList, and in this case, we would have to change the userCodes parameter to use IList instead of ArrayList. Thankfully, it is usually trivial to do, since they are rather similar in nature.
Another complication might be if the PrintSomeUsers method accepted the userCodes as an IList<T> parameter.
private void PrintSomeUsers(IList<int> userCodes)
In this case, passing userCodes to GetAllUsers would fail, as IList<T> does not "inherit" from IList. And we already learned that it would be bad practice to accept the concrete List<T> as a parameter. In this case, we could use the Algorithms.Untyped method, like this:
private void PrintSomeUsers(IList<int> userCodes)
IList<User> users = Algorithms.TypedAs<User>(
Algorithms.Untyped does the exact opposite of TypedAs, by converting an IList<T> to an IList by means of a wrapper. Indeed, this is not the prettiest code in the world. In many cases, you should consider changing old methods to use generics entirely, but sometimes it is not a penalty you can afford. In these cases, Algorithms.TypedAs and Algorithms.Untyped can be very good friends to have around. Just remember to remove the wrappings once you do get around to refactoring the legacy code.