Tuesday, 17 May 2011

Re-drawing my own map: A new milestone

For every step you take towards mastery, your destination moves two steps further away. Embrace mastery as a lifelong endeavour. Learn to love the journey.
--George Leonard, Mastery
It is with a mixture of sadness and excitement that I would like to announce that, after over five years, I'm leaving Valtech on the 18th of May. The decision was not an easy one and took me months to figure out what the next step in my long road would be. As I said in a recent interview, I love working for consultancy companies and that's the main reason I spent over ten years (two-thirds of my career) working as a consultant.  

Working for Valtech

Valtech is a fantastic company to work for and had a huge impact in my personal and professional life. During my time there I had the opportunity to work on a great variety of projects, different companies, different industries and different technologies. Most importantly, I had the opportunity to meet and work with a lot of great people that helped me to become a much better professional.

If there is one thing that I will never complain about Valtech is that I did not have recognition for the work I've done. I have started at a Valtech in a relatively junior role, according to Valtech's grade scheme, and bit by bit, with a lot of support and trust from my colleagues I was given more and more responsibility and gradually climbed my way up to one of the most senior positions.

There is no such a thing as a perfect company but if I had to point out the best thing about Valtech, I would say that, beyond the shadow of a doubt, it is its people. People that I learnt a lot from, that helped me to feel at home in the UK, that helped me with personal issues, people that challenged me, that pushed me to my limits, that gave me constructive criticism, that trusted me and empowered me to do my job, people that helped me to be better.

I may not be in the office or in a client site full time any more but I will always be around. As it happened before (I took a year off to work on a startup idea and came back) I'll always be around for drinks and events.

Special thanks

I would like to thank you everyone at Valtech that had to put up with me for all this time. I know I can be a pain in the neck quite often sometimes. :-)

It's always tricky to mention names since there is always the risk of people left out feeling a bit upset but I feel that I need to thank some people in a more personal level, so apologies for the ones I did not mention. In no particular order: Toby Mckenzie for caring about me and every single consultant during tough times, all his herculean effort to keep every one happy, finding us good projects; David Draper for challenging many of my beliefs and opinions, for the many advices, for supporting my involvement with user groups and events and for the effort in making Valtech a place of excellence; Mashooq Badar for the fantastic time we had together in many projects, for all the things I learnt from him and for making me open my mind about so many things. Ah, and for all the Blazing hot! moments; Phil Hall for the support and keeping the doors open to me and LSCC; Kevin Harkin (I can't believe he does not use twitter) for the fun we had together, for his friendship, advices, ranting sessions and memorable nights at the pub; Andrew Rendell for his professionalism, trust and for being a great role model for every Valtech consultant; And last but not least, Akbar Zamir, for pushing me and challenging me to be better, for all the advice, trust, knowledge and help, for being a great career manager and most important of all, for being a great friend.

Thanks for the great five years that I spent there. It was an absolute pleasure to work with all of you and be part of this great company.

The future

It’s not just a question of conquering a summit previously unknown, but of tracing, step by step, a new pathway to it.
--Gustav Mahler, musician and composer
I'm joining UBS as a senior developer at a director level, starting on the 23rd of May. Due to my involvement with the software craftsmanship movement, this came as a surprise to many people, including myself, mainly because investment banks tend to be almost a hostile environment for agile and software craftsmanship initiatives. When I started re-drawing my own map, investment banks were an avenue that I was not considering to explore.

As I said before, choosing my next step was not easy. I had a few things in mind that were non-negotiable: I wanted different challenges, that means, things that I haven't done before, keep having fun and loving my job, a potential long term commitment where I would have time enough to put into practice many ideas and beliefs and most importantly, have a long term career as a software developer but with a lot of space to keep growing as a professional.

I was fortunate to have had many opportunities during this time but the majority of them could not satisfy all the items above. I was determined to keep doing what I had been doing throughout my entire professional life that is just to work for companies that I really want to work for, I mean, companies that would be able to offer me what I was looking for at that point in time. For me, that's the best way to keep fuelling the passion that I have for what I do. Joining a company just because of money is and always has been totally out of question.

UBS came along with a very interesting proposition. They want to improve the quality of their software and recognise that agile and software craftsmanship are a great way to get there. They were interested in people with no previous investment bank experience, what is very unusual for an investment bank. They want people that can think different, that are passionate and can help them drive this transformation. I had five interviews and was very pleased to see so many people striving to be and do better.

As far as I understand, my main role will be to work as a hands-on developer, embedded in a team, helping to improve quality, leading by example and mentoring other developers. They also expect me to give internal talks, training, promote events, disseminate passion and promote the craftsmanship values and techniques. In the future I'll be working with other teams in the UK and in other offices around the world. But make no mistake. I'll have a hell of interesting and tough challenges ahead of me and I hope to live up to all their expectations.    

Besides that, I'll keep running the London Software Craftsmanship Community (LSCC) alongside my friend David Green and try my best to give something back to the wider and great community of software developers out there that some many times I benefited from.

Thanks everyone for being part of long road journey.

Thursday, 5 May 2011

Open-source developers deserve respect

I was recently reading Gojko Adzic's blog post called How is it even possible for code to be this bad? I must admit that I was very sad to see tremendous lack of respect towards the Hudson/Jenkins community and towards open source software developers in general.

Firstly I would like to say that any person out there that is working on an open source project deserves a lot of respect, mainly the ones working on projects that bring so many benefits to so many companies and developers around the world. The velocity that our industry moves forward and evolves is, in general, because of many open source initiatives. It's because of thousands of developers that work on the their spare time, for free, to create software that will make the lives of many other developers, companies and users much easier. These people are kind enough to offer their work to all of us and are humble enough to ask and accept help from many other developers around the globe.

One thing we need to understand is that every project has a history and many things, throughout the lifespan of a project, can be responsible for the success or failure of a project. It's always easier to criticise something instead of trying to help and make it better. As far as I'm aware, I don't think that anyone in the Hudson/Jenkins community ever claimed that their code base is the best example of quality software ever written and we all should learn from them. If that was the case, probably it would justify such harsh words written in the original blog post

The only acceptable form of criticism towards any open source project or developer is constructive criticism. 

If we think that a open source project is below standard and/or not good enough, we should either not use it or we should contribute to make it better.

However, I do understand the point Gojko is trying to make. Yes, I agree that good code is not the only thing that makes a project be successful. I think we all could name a few projects that we delivered where clients and/or users were relatively happy but the code base was a bit messy. There are always exceptions to the rules. Trying to get our code as perfect and as clean as possible does not guarantee that our projects will be successful and having a messy code does not always mean that our project will fail either. We all know that. Even my 5 month-old baby girl knows that.

However, I totally disagree with Gojko's statement that "[Hudson's success with "bad" code] is close to the final proof that God doesn't exist for the whole craftsmanship debate". It is almost like saying that Agile is rubbish and everyone should forget about it just because some waterfall projects succeeded. It is like saying that we all should forget about good principles of software development just because some projects succeeded with messy code. In summary, is like trying to get some exceptions and transform them into rules. There are many ways and many things that can contribute to the success of a project. Software craftsmanship is one of them and a very important one. In a software project, the most important thing is the software itself and looking after its quality is an obligation of every developer involved in it.

Although software craftsmanship on its own may not be enough to guarantee the success of a project, the lack of it can be reason for its failure. Single-handed.

Another important point we should ask is the definition of a "successful project" and in which context or environment but I'll leave that for another post.

If exceptions invalidate rules and that is the way we should look at things, does God exist for anything in software development?

Sunday, 17 April 2011

Working for consultancy companies

Recently I was approached by the guys from the Graduate Developer Community (GDC) where they asked me for an interview about life in a consultancy company. Their idea, that came out from an email I sent to the London Java Community (LJC) ages ago about different career paths, was to interview professionals that followed different career paths and publish these interviews on a website called GDC Careers so that graduates and people starting in our industry could have an idea about what is available out there in terms of jobs and career paths.

The interview was originally published on the GDC Careers but I'll also be publishing it here in full. I hope it helps any professional that would like to know more about life on consultancy companies.

NOTE: Throughout my career I've worked for three consultancy companies and this is just my general view of all of them. Each project is a different project and different consultants, working for the same consultancy company but in different projects, can have a completely different view of their employers.

Sandro Mancuso has been working as a software developer since 1996 but started writing code for pure enjoyment way before that. Although he has worked for software houses and startups, he spent the majority of his career working for international consultancy companies where he had the opportunity to work on a great variety of projects and across many different industries. He has a BSc in Computer Science and a MSc in Distributed Objects. He is a Co-founder of the London Software Craftsmanship Community (LSCC).

Title – What is your job title?

Senior Consultant.

What is your role about?

My role is to work with clients, helping them to identify what they really need, advise them, provide options, and help them to achieve whatever they want to achieve in the most efficient way.

OK, I know. That was not very specific or helpful. This is because the role of a consultant can vary quite a lot. Different consultants may choose different career paths. Some follow a more business oriented career, advising clients on strategy, marketing, investment, finance, etc. Some follow a more process oriented career, emphasising project management, Agile Coaching, training, business analysis, requirements, etc. Others prefer a more technical career path, working more often as developers, technical architects and team leaders, mentoring, etc. In my case, I took the more technical path so normally I do what I like doing, that is writing code, regardless of my position in the project. Although I was a hands-on developer on all my assignments, many of them had elements of mentoring. Some times I also got involved in customised training courses for clients, like TDD, Agile, etc.

I work mainly in Agile Java projects. Technologies vary quite a lot since every now and again we are working for different clients, different industries and completely different systems. Sometimes clients already have something in place and the technology stack is already defined. In this case, we often use whatever they are using to start with but we always try to make suggestions if we see that other technologies or frameworks should be used instead. Some other projects, mainly greenfield ones, we generally have freedom to choose the technology stack we judge is the best for the problem. 

What are the best/most positive parts of the job/industry?

In my view, the best thing about being a consultant is the amount of technologies and business domains that you are exposed to during your career. Because of the frequency that we change projects, we end up being exposed to a lot of interesting problems quite early in our careers, giving us a great understanding of many different software projects.

Networking is definitely another very positive aspect of being a consultant. As we move from project to project, client to client, we end up meeting a lot of people, in different organisations, what can be very useful as you progress in your career. The more people you work with or for, the more options you will have in the future.

Another important point is that, as a consultant, you need to be sellable. This may sound a bit negative, but if fact, what it means is that you need to be at the top of your game, knowing the latest technologies, methodologies and trends. The more you know, the easier it will be for a consultancy to place you in a project (sell you to a client). As the consultancy companies recognise that, in general they have different mechanisms (training, conferences, internal talks, events, etc) that you can take advantage of to improve your skills.

Because your peers are also moving from project to project and using different technologies in each project, it is amazing what you can learn from them. The variety of information shared among consultants about projects, businesses, methodologies, technologies, etc, is absolutely priceless. There is always someone doing something different somewhere.

What are the negative parts to the job/industry?

The main complain that consultants have is that in general you don’t have much saying on where you are going to be sent to. Once you decide you want to work for a consultancy company, you need to be aware that travelling is always a possibility. A few lucky consultants get to stay for a long time on projects close to their homes but in general this is not the case. If travelling or long commute is not an option for you, you really need to think hard before becoming a consultant. For those living in big cities, like London for example, in general this is not a big problem since the majority of the clients will be there anyway.

According to your level of seniority, years in the company and history of projects you delivered, you can refuse to go to some projects, in case you don’t like the project (less often) or if the commute is bad (more often). However, this is a card that needs to be played very wisely since you don’t get to play it more than once in a short period of time.

In some projects, you may be seen as an outsider by a few permanent employees. Some feel threatened by the presence of a “consultant”, since you may be “exposing” problems in the current process and software. It’s part of our job to deal with that and do whatever we can to be seen as another team member, a person that shares the same goals, and not an outsider.

Career Path

What is the standard career path/qualifications?

This varies quite a lot since consultancies may offer different type of services and they will need people that are more specialised in some areas than in others. Services offered may include software development, project management, training, coaching, business advice (strategy, finance, investment, etc), auditing, etc. Some consultancies tend to work more on the “consulting” side of things and tend to engage with clients at a more senior level (CEOs, CTOs, Directors, etc). Other consultancies are more focused on software delivery and tend to engage with clients at lower levels (directors, project managers, head of departments, etc). And, of course, some consultancies do a bit of both.

I’ll just talk about consultancies that focus more on software delivery since that’s my background.

My title is Senior Consultant but this is a reasonably vague title. Many consultancies, internally, distinguish their consultants by grades. Each grade has different ranges of salaries and responsibilities and we take on responsibilities on projects, in general, according to our grade.

For people aspiring a more technical career, in the entry levels you are expected to have a good knowledge of a programming language (in our case Java or .Net), most common frameworks, good understanding of Object-Oriented Programming and you would be working as a team member (developer). As you move up through the grades, you may take roles where you will be leading teams, be the technical architect, enterprise architect, Agile coach, etc. At the higher grades, besides all the technical knowledge you will also have some extra responsibilities like writing technical proposals, pre-sales, project inceptions, project management, manage clients expectation, etc. However, some consultants manage to reach the higher grades and remain totally hands on. That’s the path I’m following.

To be successful as a consultant, you need to be a well-rounded professional. Just knowing a programming language well is far from being enough to be a good consultant. You are expected to have knowledge in many different areas since you never know in which project you will end up and which position in the project you will have. And regardless what the project is, you need to be ready. Of course that we all know that is simply impossible to know everything that is out there but at least you need to show that you have the motivation and drive to learn whatever is thrown at you.

Besides the technical skills, another thing that is very important for a good consultant is soft skills, due to the amount of iteration with clients. I’m still working to improve mine. :)

What are the prospects?

Over the years, after many different projects, a consultant will have a good understanding of different types of software projects, technologies and also will have met a lot of people working for many different companies. This gives the consultant a good variety of options for the future. 

In your experience are you aware of any differences your role has between industries/sectors?

In terms of clients we work for, yes, there are huge differences. Working for clients where software is not their core business (a big supermarket chain, a media company, etc) is totally different from working for clients where software is their core business or is an extremely important part of it (software products, internet companies, telcos, etc). There’s also the investment banks, financial companies, government, gambling, etc. Each client will demand a different type of service and a different type of expertise. Some clients will ask a consultancy to help creating the process, roles and responsibilities, requirements, definite the technology stack, etc. Full freedom. Other clients, which have a more mature software capability, may ask a consultancy to provide help with a very specific problem. Sometimes they just need some good developers for a limited period of time. They may want someone in there to coach and mentor their own developers. That means, the role can vary quite a lot, depending on the client.

Reflection and The Future

What was it like coming into the industry?

Before joining my first consultancy company, I had worked for two small software houses and I didn’t know much about it. Job was announced in one of the main Brazilian newspapers. 800+ developers applied and just 34 were hired after a month long selection process, 4 phases, including a two week training and group dynamics. My two previous companies combined had in total 10 people. This consultancy company had more than one thousand employees just in Sao Paulo. Many thousands around the world. I was completely lost and a bit scared by the size of the projects. Before I was writing software for local shops and businesses and there I was working in projects for multinational companies and governments. Complete shock. New technologies, new people, massive projects, multiple teams involved, clients speaking different languages, etc. After a few months, I was quite comfortable there and knew that I had made the right choice. I guess that I was very lucky there, firstly because I was assigned to work on a very technical and capable team and secondly because for two and a half years I had the best mentor (my boss) that I could ever have asked for.

However, joining a modern and more agile consultancy company today is totally different, much easier and less traumatic, even when working on big projects for big clients. In general you will be working in smaller teams (even on long term projects) and following agile methodologies. The technologies used are accessible to every one. When I started, back in the 90ies, we couldn’t just go to a website, download certain technologies and install on our PCs. Many of the technologies were proprietary. There’s absolutely nothing to fear about joining a consultancy company today and the world is a much better place now. :-)

Do you have any thoughts on the future of your role/industry?

I think that while there is a need for software development, consultancies and consultants will always have a place. However, the time where consultants were the only or the best specialists in the market are over. Due to the internet, open source projects, social networking, user groups, conferences, shared videos, podcasts, etc, any one, anywhere in the world, has access to the latest technology at the minute it is released. Consultants now, more than ever, need to be at the top of their game. Consultancy companies will need to do their best to get the best professionals in the market in order to survive. They will need, more than ever, to show to clients that they have the best people to work on their projects.

What advice would you give someone entering your industry?

The following advices are valid for any developer starting his or her career, regardless if he wants to be a consultant, the industry or career path he will choose:

- Firstly and most importantly, enjoy and be proud of what you do. Software development is a very cool profession. During your career, there will be many people out there that will be using and benefiting from stuff you created. And this is definitely really cool.

- If you think you studied hard during university, think again. You haven’t even started studying hard yet. Software development IS NOT a 9 to 5 profession. Be prepared to study hard, outside working hours, for the rest of your life.

- Always aim for jobs where you are going to learn more and not earn more. Preferably a place where you could have a good mentor. Be patient because money will come. If you are good and keep learning, you will have a very decent life throughout your career. If you just aim for the money instead of learning, you may get a good money now and be unemployable and out of the market in a few years time.

- Put a lot of effort on learning the fundamentals of software development instead of just learning the latest framework. If you have a good foundation, you will be able to learn any new technology much faster.

- Contribute to open source projects, learn from their code base and take the opportunity to communicate with other contributors.

- Always have a pet project (you may be excused if you are actively contributing to an open source project). Pet projects are great for you to try different technologies, techniques and methodologies. The cool thing about a pet project is that you have the power to do whatever you want, whenever you want, making it quite fun to work on. You don’t need to finish a pet project, in fact, you never will.

- Join you local user groups. The amount of stuff you learn and people you meet is just priceless.

Have you come across anything or anyone that has helped you move forward in the industry?

Definitely the mentor I had early on in my career. He was an exceptional developer and like a father for all of us in the team. He could hit us as hard as he wanted but no one else was allowed to do it. He shielded his team (us) from all the external heat and pressure. Quality was non-negotiable. He was a true believer that “how it’s done is as important as having it done“, phrase that I use as my blog’s subtitle. He believed in the apprenticeship model, although we’ve never used the term. It was there and then that I learned the true values of what today is called software craftsmanship. I worked for him and on that team for two and a half years and by far it was, if not the best, one of the best teams that I've been part of. My mentor gave me everything I needed to become the professional I am today.

Twitter: @sandromancuso
blog: http://craftedsw.blogspot.com
LSCC: http://www.londonswcraft.com

Saturday, 2 April 2011

Frustrations and aspirations of a software craftsman

For a while I've been thinking about what makes me like or dislike a project. Having spent a very big part of my career working for consultancy companies, I was exposed to many different environments, industries, team sizes, processes and technologies. There were projects that I absolutely loved, some projects were OK and some were a real pain.
 
There were even a couple of times in my career where I questioned myself if the choice of being a software craftsman and keep walking the long road would be the best thing for my sanity.

What makes me dislike a project?

Well, there are many factors. Here are just a few but is far from being a complete list:

  • Bureaucracy is something that can be really frustrating. That includes process for the sake of process, innumerable cycles of approvals, tortuous and long test and deployment cycles, pointless documentation, and all that anti-agile stuff. 
  • Old technologies or the "wrong" technology for the job is always demotivating. We love new toys. There is nothing more annoying when the technology stack is imposed on the team. "You must use these tools from Oracle or IBM. But, hey, don't look like that. You have support if you need it."
  • Lack of autonomy and credibility. "You are just the developers here. You don't make decisions. You do what you are told to do. There are much smarter people here to worry about the _real_ problems. And by the way, you don't have admin rights to your PC and you can't access a few websites either."
  • Uninteresting domain. It's always difficult to find motivation to build a great software if you don't like what the software does or don't really believe in the business idea. 
  • Demotivated people. How can we find motivation and have team spirit when your colleagues attitude is: "Oh, I just turn up to work, keep my head down and do what I'm told. If something goes wrong, it's not my fault.
  • Finger pointing and highly competitive environment, where no one plays as a team. This is an environment where everyone wants to be the boss, they are always looking for a scapegoat and the less work they do, the more they delegate, the better. If something goes wrong, it would never be their fault. If something goes well, they take all the credit. 
  • Arrogant and unskilled people. Arrogance many times is used as a self-defence mechanism in order to hide the lack of skills a person may have. "I don't need to read any books. I think all these new technologies and methodologies are crap. I've been doing this for years. I know what it is best."
  • Software factory concept. "We need to go faster. Let's throw more developers here. Which ones? Doesn't matter. Just hire some monkeys."
  • Mortgage-Driven Development
  • Project managers that think they are the most important member of the team
  • Very deep hierarchy
  • You can't help those who don't want to be helped.
  • I really could go on forever here.... 
So what is really the problem here?

When I first mentally thought about all these items, I realised that almost all the things that make me dislike a project are related to people. Yes, people. One of the few exceptions are uninteresting domain and old technologies. So even if I make sure that I don't work on projects related to subjects I have no interest and that use the latest technologies, the people involved may make it very frustrating. Have you ever been on a project where you thought that the project had everything to be a great project but for some reason it was a pain?

After this analysis, things were not looking good, so I decided to look at all the projects I really enjoyed. It was when I realised that in some of them we didn't use the latest technologies and in a few of them I was not exactly passionate about the domain either. One or two were even quite bureaucratic. So, why did I enjoy them? What was in there that made me put them among the projects I liked the most? Once again, the answer was "people".

The good projects and what I always would like to find

My favourite projects had quite a few things in common but the most important ones were passion, craftsmanship, friendship and trust.

Passion

It's not because you like something that you are going to be good at it. However, to be really good at something, you must have a passion for it.

The best people for a job are the ones that love the job. This in the essential quality that drives people to be successful in whatever they decide to do. A passionate person will do whatever is in his or her power to keep acquiring skills and do the best they can. Passionate people bring innovation, they question what they are doing, they want to contribute, they want to get involved, they want to learn. They want to succeed. Passionate people CARE.

Craftsmanship

The only way to go fast is to go well - Uncle Bob Martin

In all my favourite projects, the focus on quality and the willingness to see users satisfied and using the system was always a big thing. The whole team was focused in delivering the best project we could, taking into consideration all the constraints we were under. It was clear to all of us that to be successful we had to be pragmatic. We also always believed that how it is done is as important as having it done.
Software craftsmen use the right tools for the job, are skilful, are pragmatic, care about the quality of their work, care about their reputation and want to delight every single one of their customers and users. Software craftsmen CARE.

Friendship

So far I've been talking about passionate people and care. However we know that people have different opinions and there are many ways to do the same thing. Now imagine a room full of very passionate people that don't really get along. In the best scenario, there will be some memorable arguments. In the worst, they will kill each other.

Friendship is the answer to that. The importance of social events for a team is enormous, even if it is just a few drinks once or twice a month. Like it or not, we spend more time with our colleagues than with our own family, so it is important that we have the friendliest environment possible. Having lunch together at least a few times per week is another thing that can help improve this friendship. Team members need some time together where they are not always just talking about work. Team members need time to know each other. 

Among friends people feel comfortable to speak their minds. Working with friends helps to improve the quality of the discussions and no one is worried to expose ignorance or give suggestions. Friends help each other, friends learn from each other, friends CARE for each other. 

Trust

Once people can demonstrate their commitment and passion, can demonstrate competence, willingness to learn and contribute and are able to deliver the best software possible, trust is easily established. With trust you gain autonomy and are free to decide what it is best for the project and to do your job well. With trust you can be more effective when delegating or sharing tasks. With trust we can remove all the bureaucracy that impedes that we do our job efficiently.   

Aspirations

I just wish I could find the things I described above in all projects. Companies should aim to hire passionate and skilful people. People that can contribute to their projects and organisation. People that are willing to share and learn.

Unfortunately not always we will find all that. In those cases, the only thing we can do is to try our best to change the environment around us. We can try motivate people and share our passion. We can be nice to everyone, respect our colleagues and promote an environment where everyone feels comfortable to ask for help, to help each other and share knowledge.

With great people we can overcome any obstacle and have an environment where every morning, when we wake up, we would think: "Yay! Today I'll have another great day at work."

Monday, 14 March 2011

My first code retreat

Yesterday I went to my first code retreat, in Winchester UK. In the past I had been sceptical about code retreats since I had doubts if I would really learn something. However, after speaking to a few developers that had been to one before, I was totally convinced that I should give it a go. I thought, even if I don't learn much, at least I'll have a whole day of fun writing code, catching up with some friends and meeting other developers. That was more than enough for me to be convinced that it would be a great day.

Summary of the day

There were around 20+ developers. After introductions and explanation of the problem (Conway's game of life), we started our first session. Throughout the day, we had 6 or 7 sessions. I can't even remember exactly because it was so enjoyable, intense and fun that even if it had been 20 I wouldn't have noticed.  I've paired with some people that I knew before (although never worked with) and some people that I had just met. After each session, we shared what we have learned, approaches we took, problems we faced, etc. If I recollect well, different languages were used and tried including Java, C#, JavaScript, Ruby, Scala and I think Python as well (I'm sure I'm forgetting something).

The first two sessions we just sat down and tried to solve it, without any constraints, besides TDD, that was mandatory for all sessions. This was good so everyone could get familiar with the problem. From the third session onwards, we were asked to try different approaches, like not using if statements, TDD as if you meant it, OOP to the extreme and the best code we could possibly write. At the end of each session, the code is deleted.

We had a good break for lunch and went to the local pub in the evening.

Things I learned and experienced
  • No matter how much you think you know, it is still not much and not enough.
  • Pair-programming with other developers exposes you to different ways of thinking and opens your mind for new ideas.
  • Seeing and using different languages, makes you see software development with different eyes, giving you a much broader understanding and helps clearing up misconceptions you may have.
  • You are not alone. Like yourself, there more talented and passionate developers out there willing to share ideas and learn from each other.
  • I definitely learned a lot and feel I got back from there a better developer. 
  • Besides all the technical learning, it was really great to meet so many talented developers.
Thank you

Firstly I would like to thank Despo and Aimee for organising it and Enrique for running it (and the great chat in the pub). I also would like to thank all the developers that I paired with for helping to make me a better developer. Finally, I would like to thank all the developers that were there for reinforcing my belief that software development is a great profession, full of talented, bright and passionate people and that we can really make a difference in moving our industry forward. 

I wish you all have a great long road ahead of you and I'm looking forward to meeting you again any time soon. 

Links

Official site for the Winchester Code Retreat
London Software Craftsmanship Community - LSCC

Friday, 10 December 2010

Readable Tests: Separating intent from implementation

Very recently, I was working on a test class like this:

public class AnalyticsExpirationDateManagerTest extends TestCase {

 private static final long ONE_HOUR_TIMEOUT = 1000 * 60 * 60;
 private static final long TWO_HOUR_TIMEOUT = ONE_HOUR_TIMEOUT * 2;
 
 private Map<Parameter, Long> analyticsToTimeout;
 private long defaultTimeout;
 
 private Parameter minTimeoutParam;
 @Mock private CacheKeyImpl<Parameter> cacheKey;

    @Override
    protected void setUp() throws Exception {
     MockitoAnnotations.initMocks(this);
     
     this.minTimeoutParam = new Parameter("minTimeout", "type");
     
     when(cacheKey.getFirstKey()).thenReturn(minTimeoutParam);
     
     this.analyticsToTimeout = new HashMap<Parameter, Long>();
     this.defaultTimeout = 0;
    }
 
 public void
 testGetExpirationDateWhenAnalyticsToTimeoutsAndCacheKeyAreEmpty() {
  AnalyticsExpirationDateManager<Long> manager = 
    new AnalyticsExpirationDateManager<Long>(analyticsToTimeout, defaultTimeout);
  Date date = manager.getExpirationDate(cacheKey, 0L);
  assertNotNull(date);
 }
 
 public void 
 testGetExpirationDateWithMinimunTimeoutOfOneHour() {
  this.analyticsToTimeout.put(this.minTimeoutParam, ONE_HOUR_TIMEOUT);
  Collection<Parameter> cacheKeysWithMinTimeoutParam = new ArrayList<Parameter>();
  cacheKeysWithMinTimeoutParam.add(this.minTimeoutParam);
  when(this.cacheKey.getKeys()).thenReturn(cacheKeysWithMinTimeoutParam);
  
  AnalyticsExpirationDateManager<Long> manager = 
   new AnalyticsExpirationDateManager<Long>(analyticsToTimeout, defaultTimeout);
  Date date = manager.getExpirationDate(cacheKey, 0L);

  assertNotNull(date);
  Calendar expirationDate = Calendar.getInstance();
  expirationDate.setTime(date);
  
  Calendar currentDate = Calendar.getInstance();
  
  // Check if expiration date is one hour ahead current date. 
  int expirationDateHour = expirationDate.get(Calendar.HOUR_OF_DAY);
  int currentDateHour = currentDate.get(Calendar.HOUR_OF_DAY);
  assertTrue(expirationDateHour - currentDateHour == 1);
 }
 
 public void 
 testGetExpirationDateWhenCacheKeyIsNullAndDefaultTimeoutIsOneHour() {
  CacheKeyImpl<Parameter> NULL_CACHEKEY = null;
  AnalyticsExpirationDateManager<Long> manager = 
   new AnalyticsExpirationDateManager<Long>(analyticsToTimeout, ONE_HOUR_TIMEOUT);
  Date date = manager.getExpirationDate(NULL_CACHEKEY, 0L);
  
  assertNotNull(date);
  Calendar expirationDate = Calendar.getInstance();
  expirationDate.setTime(date);
  
  Calendar currentDate = Calendar.getInstance();
  
  // Check if expiration date hour is the same of current date hour.
  // When cache key is null, system date and time is returned and default timeout is not used.
  int expirationDateHour = expirationDate.get(Calendar.HOUR_OF_DAY);
  int currentDateHour = currentDate.get(Calendar.HOUR_OF_DAY);
  assertTrue(expirationDateHour - currentDateHour == 0);
 }
 
 public void 
 testGetExpirationDateWithDefaultTimeout() {
  // Default timeout is used when no time out is specified.
  Collection<Parameter> cacheKeysWithoutTimeoutParam = new ArrayList<Parameter>();
  cacheKeysWithoutTimeoutParam.add(new Parameter("name", "type"));
  when(this.cacheKey.getKeys()).thenReturn(cacheKeysWithoutTimeoutParam);

  AnalyticsExpirationDateManager<Long> manager = 
   new AnalyticsExpirationDateManager<Long>(analyticsToTimeout, ONE_HOUR_TIMEOUT);
  Date date = manager.getExpirationDate(cacheKey, 0L);
  
  assertNotNull(date);
  Calendar expirationDate = Calendar.getInstance();
  expirationDate.setTime(date);
  
  Calendar currentDate = Calendar.getInstance();
  
  // Check if expiration date is one hour ahead current date. 
  int expirationDateHour = expirationDate.get(Calendar.HOUR_OF_DAY);
  int currentDateHour = currentDate.get(Calendar.HOUR_OF_DAY);
  assertTrue(expirationDateHour - currentDateHour == 1);
 }
 
 public void 
 testGetExpirationDateWhenMinTimeoutIsSetAfterCreation() {
  AnalyticsExpirationDateManager<Long> manager = 
   new AnalyticsExpirationDateManager<Long>(analyticsToTimeout, ONE_HOUR_TIMEOUT);
  manager.setExpirationTimeout(this.minTimeoutParam.getName(), TWO_HOUR_TIMEOUT);
  
  Date date = manager.getExpirationDate(cacheKey, 0L);
  
  assertNotNull(date);
  Calendar expirationDate = Calendar.getInstance();
  expirationDate.setTime(date);
  
  Calendar currentDate = Calendar.getInstance();
  
  // Check if expiration date is two hour ahead current date. 
  int expirationDateHour = expirationDate.get(Calendar.HOUR_OF_DAY);
  int currentDateHour = currentDate.get(Calendar.HOUR_OF_DAY);
  assertTrue("Error", expirationDateHour - currentDateHour == 2);
 }
 
}

Quite frightening, isn't it? Very difficult to understand what's going on there.

The class above covers 100% of the class under test and all the tests are valid tests, in terms of what is being tested.

Problems

There are quite a few problems here:
- The intent (what) and implementation (how) are mixed, making the tests very hard to read;
- There is quite a lot of duplication among the test methods;
- There is also a bug in the test methods when comparing dates, trying to figure out how many hours one date is ahead of the other. When running these tests in the middle of the day, they work fine. If running them between 22:00hs and 00:00hs, they break. The reason is that the hour calculation does not take into consideration the day.

Making the tests more readable

Besides testing the software, tests should also be seen as documentation, where business rules are clearly specified. Since the tests here are quite messy, understanding the intention and detecting bugs can be quite difficult.

I've done quite a few refactorings to this code in order to make it more readable, always working in small steps and constantly re-running the tests after each change. I'll try to summarise my steps for clarity and brevity.

1. Fixing the hour calculation bug

One of the first things that I had to do was to fix the hour calculation bug. In order to fix the bug across all test methods, I decided to extract the hour calculation into a separate class, removing all the duplication from the test methods. Using small steps, I took the opportunity to construct this new class called DateComparator (yes, I know I suck naming classes) using some internal Domain Specific Language (DSL) techniques.

public class DateComparator {
 
 private Date origin;
 private Date target;
 private long milliseconds;
 private long unitsOfTime;
 
 private DateComparator(Date origin) {
  this.origin = origin;
 }
 
 public static DateComparator date(Date origin) {
  return new DateComparator(origin);
 }
 
 public DateComparator is(long unitsOfTime) {
  this.unitsOfTime = unitsOfTime;
  return this;
 }
 
 public DateComparator hoursAhead() {
  this.milliseconds = unitsOfTime * 60 * 60 * 1000;
  return this;
 }
 
 public static long hours(int hours) {
  return hoursInMillis(hours);
 }
 
 private static long hoursInMillis(int hours) {
  return hours * 60 * 60 * 1000;
 }
 
 public boolean from(Date date) {
  this.target = date;
  return this.checkDifference();
 }
 
 private boolean checkDifference() {
  return (origin.getTime() - target.getTime() >= this.milliseconds);
 }
}

So now, I can use it to replace the test logic in the test methods.

2. Extracting details into a super class

This step may seem a bit controversial at first, but can be an interesting approach for separating the what from how. The idea is to move tests set up, field declarations, initialisation logic, everything that is related to the test implementation (how) to a super class, leaving the test class just with the test methods (what).

Although this many not be a good OO application of the IS-A rule, I think this is a good compromise in order to achieve better readability in the test class.

NOTE: Logic can be moved to a super class, external classes (helpers, builders, etc) or both.

Here is the super class code:

public abstract class BaseTestForAnalyticsExperationDateManager extends TestCase {

 protected Parameter minTimeoutParam;
 @Mock protected CacheKeyImpl<Parameter> cacheKey;
 protected Date systemDate;
 protected CacheKeyImpl<Parameter> NULL_CACHEKEY = null;
 protected AnalyticsExpirationDateManager<Long> manager;

 @Override
 protected void setUp() throws Exception {
  MockitoAnnotations.initMocks(this);
  this.minTimeoutParam = new Parameter("minTimeout", "type");
  when(cacheKey.getFirstKey()).thenReturn(minTimeoutParam);
  this.systemDate = new Date();
 }

 protected void assertThat(boolean condition) {
  assertTrue(condition);
 }
 
 protected void addMinimunTimeoutToCache() {
  this.configureCacheResponse(this.minTimeoutParam);
 }
 
 protected void doNotIncludeMinimunTimeoutInCache() {
  this.configureCacheResponse(new Parameter("name", "type"));
 }
 
 private void configureCacheResponse(Parameter parameter) {
  Collection<Parameter> cacheKeysWithMinTimeoutParam = new ArrayList<Parameter>();
  cacheKeysWithMinTimeoutParam.add(parameter);
  when(this.cacheKey.getKeys()).thenReturn(cacheKeysWithMinTimeoutParam);
 }
}

3. Move creation and configuration of the object under test to a builder class

The construction and configuration of the AnalyticsExpirationDateManager is quite verbose and adds a lot of noise to the test. Once again I'll be using a builder class in order to make the code more readable and segregate responsibilities. Here is the builder class:

public class AnalyticsExpirationDateManagerBuilder {
 
 protected static final long ONE_HOUR = 1000 * 60 * 60;

 protected Parameter minTimeoutParam;
 private AnalyticsExpirationDateManager<Long> manager;
 private Map<Parameter, Long> analyticsToTimeouts = new HashMap<Parameter, Long>();
 protected long defaultTimeout = 0;
 private Long expirationTimeout;
 private Long minimunTimeout;

 private AnalyticsExpirationDateManagerBuilder() {
  this.minTimeoutParam = new Parameter("minTimeout", "type");
 }
 
 public static AnalyticsExpirationDateManagerBuilder aExpirationDateManager() {
  return new AnalyticsExpirationDateManagerBuilder();
 }
 
 public static long hours(int quantity) {
  return quantity * ONE_HOUR;
 }
 
 public AnalyticsExpirationDateManagerBuilder withDefaultTimeout(long milliseconds) {
  this.defaultTimeout = milliseconds;
  return this;
 }
 
 public AnalyticsExpirationDateManagerBuilder withExpirationTimeout(long milliseconds) {
  this.expirationTimeout = new Long(milliseconds);
  return this;
 }
 
 public AnalyticsExpirationDateManagerBuilder withMinimunTimeout(long milliseconds) {
  this.minimunTimeout = new Long(milliseconds);
  return this;
 }
 
 public AnalyticsExpirationDateManager<Long> build() {
  if (this.minimunTimeout != null) {
   analyticsToTimeouts.put(minTimeoutParam, minimunTimeout);
  }
  this.manager = new AnalyticsExpirationDateManager(analyticsToTimeouts, defaultTimeout);
  if (this.expirationTimeout != null) {
   this.manager.setExpirationTimeout(minTimeoutParam.getName(), expirationTimeout);
  }
  return this.manager;
 }

}

The final version of the test class

After many small steps, that's how the test class looks like. I took the opportunity to rename the test methods as well.

import static com.mycompany.AnalyticsExpirationDateManagerBuilder.*;
import static com.mycompany.DateComparator.*;

public class AnalyticsExpirationDateManagerTest extends BaseTestForAnalyticsExperationDateManager {

 public void
 testExpirationTimeWithJustDefaultValues() {
  manager = aExpirationDateManager().build();
  Date cacheExpiration = manager.getExpirationDate(cacheKey, 0L);
  assertThat(dateOf(cacheExpiration).is(0).hoursAhead().from(systemDate));
 }
 
 public void 
 testExpirationTimeWithMinimunTimeoutOfOneHour() {
     addMinimunTimeoutToCache();  
  manager = aExpirationDateManager()
      .withMinimunTimeout(hours(1))
      .build();
  Date cacheExpiration = manager.getExpirationDate(cacheKey, 0L);
  assertThat(dateOf(cacheExpiration).is(1).hoursAhead().from(systemDate));
 }
 
 public void 
 testExpirationTimeWhenCacheKeyIsNullAndDefaultTimeoutIsOneHour() {
  manager = aExpirationDateManager()
      .withDefaultTimeout(hours(1))
      .build();
  Date cacheExpiration = manager.getExpirationDate(NULL_CACHEKEY, 0L);
  // When cache key is null, system date and time is returned and default timeout is not used.
  assertThat(dateOf(cacheExpiration).is(0).hoursAhead().from(systemDate));
 }
 
 public void 
 testExpirationTimeWithDefaultTimeout() {
  doNotIncludeMinimunTimeoutInCache();
  manager = aExpirationDateManager()
      .withDefaultTimeout(hours(1))
      .build();
  Date cacheExpiration = manager.getExpirationDate(cacheKey, 0L);
  assertThat(dateOf(cacheExpiration).is(1).hoursAhead().from(systemDate));
 }
 
 public void 
 testExpirationTimeWhenExpirationTimeoutIsSet() {
  manager = aExpirationDateManager()
      .withDefaultTimeout(hours(1))
      .withExpirationTimeout(hours(2))
      .build();
  Date cacheExpiration = manager.getExpirationDate(cacheKey, 0L);
  // Expiration timeout has precedence over default timeout.
  assertThat(dateOf(cacheExpiration).is(2).hoursAhead().from(systemDate));
 }
 
}


Conclusion

Test classes should be easy to read. They should express intention, system behaviour, business rules. Test classes should express how the system works. They are executable requirements and specifications and should be a great source of information for any developer joining the project.

In order to achieve that, we need to try to keep our test methods divided in just 3 simple instructions.

1. Context: The state of the object being tested. Here is where we set all the attributes and mock dependencies. Using variations of the Builder pattern can greatly enhance readability.
manager = aExpirationDateManager()
                .withDefaultTimeout(hours(1))
                .withExpirationTimeout(hours(2))
                .build();

2. Operation: The operation being tested. Here is where the operation is invoked.
Date cacheExpiration = manager.getExpirationDate(cacheKey, 0L);

3. Assertion: Here is where you specify the behaviour expected. The more readable this part is, the better. Using DSL-style code is probably the best way to express the intent of the test.
assertThat(dateOf(cacheExpiration).is(2).hoursAhead().from(systemDate));

In this post I went backwards. I've started from a messy test class and refactored it to a more readable implementation. As many people now are doing TDD, I wanted to show how we can improve an existing test. For new tests, I would suggest that you start writing the tests following the Context >> Operation >> Assertion approach. Try writing the test code in plain English. Once the test intent is clear, start replacing the plain English text with Java internal DSL code, keeping the implementation out of the test class.

PS: The ideas for this blog post came from a few discussions I had during the Software Craftsmanship Round-table meetings promoted by the London Software Craftsmanship Community (LSCC).

Tuesday, 7 December 2010

A basic ActiveRecord implementation in Java

Recently I was looking for different ways to develop applications in Java and thought that it would be interesting trying to use ActiveRecord in my persistence layer instead of implementing the traditional approach with a DAO. My idea is not to create my own ActiveRecord framework but use the existing ones as a support for this approach.

The scope: Write functional tests that could prove that the methods save and delete on an entity work. I'll use an entity called Traveller for this example.

The technology: I chose to use the following frameworks: Spring 3.0.5, JPA 2.0, Hibernate 3.5.3, AspectJ 1.6.9, JUnit 4.8.2, Maven 2.2.1, Eclipse Helios and MySQL 5.x

I'll be omitting things that are not too important. For all the details, please have a look at the whole source code at:

https://github.com/sandromancuso/cqrs-activerecord

Let's start with the test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  locations={
    "file:src/test/resources/applicationContext-test.xml",
    "file:src/main/resources/applicationContext-services.xml"    
  })
@TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)
@Transactional
public class TravellerActiveRecordIntegrationTest extends BaseTravellerIntegration {
 
 @Test public void 
 testTravellerSelfCreation() {
  assertThereAreNoTravellers(named("John"), from("England"));
  
  Traveller traveller = aTraveller().named("John").from("England").build();
  traveller.save();
  
  assertThereIsASingleTraveller(named("John"), from("England"));
 }
 
 @Test public void
 testTravellerEdition() {
  Traveller traveller = aTraveller().named("John").from("England").build();
  traveller.save();
  
  traveller.setName("Sandro");
  traveller.setCountry("Brazil");
  traveller.save();
  
  assertThereAreNoTravellers(named("John"), from("England"));
  assertThereIsASingleTraveller(named("Sandro"), from("Brazil"));  
 }
 
 @Test public void 
 testDeleteTraveller() {
  Traveller traveller = aTraveller().named("John").from("England").build();
  traveller.save();

  traveller.delete();
  assertThereAreNoTravellers(named("John"), from("England"));
 }
 
}

A few things to notice about this test class:
- As this test is meant to insert and delete from the database, I set it to always rollback the transaction after each test, meaning that nothing will be committed to the database permanently. This is important in order to execute the tests multiple times and get the same results.
- The test class extends a base class, that has the methods assertThereAreNoTravellers and assertThereIsASingleTraveller. The advantage of doing that is that you separate what you want to test from how you want to test, making the test class clean and focused on the intention.
- Note that I also used the Builder pattern to build the traveller instance instead of using the setter methods. This is a nice approach in order to make your tests more readable. 

The Traveller entity implementation

So now, let's have a look at the Traveller entity implementation.

@Entity
@Table(name="traveller")
@EqualsAndHashCode(callSuper=false)
@Configurable
public @Data class Traveller extends BaseEntity {

 @Id @GeneratedValue(strategy=GenerationType.AUTO)
 private long id;
 private String name;
 private String country;
 
}

The Traveller class is a normal JPA entity as you can see by the @Entity, @Table, @Id and @GenereratedValue annotations. To reduce the boiler place code like getters, setters, toString() and hashCode(), I'm using Lombok, that is a small framework that generate all that for us. Just add a @Data annotation.

The real deal here is Traveller's super class BaseEntity (for a lack of inspiration to find better name). Let's have a look:

@Configurable
public abstract class BaseEntity {

 @PersistenceContext
 protected EntityManager em;

 public abstract long getId();
    
 public void save() {
  if (getId() == 0) {
   this.em.persist(this);
  } else {
   this.em.merge(this);
  }
  this.em.flush();
 } 
 
 public void delete() {
  this.em.remove(this);
  this.em.flush();
 }
 
 public void setEntityManager(EntityManager em) {
  this.em = em;
 }
 
}

The BaseEntity class has quite a few things that can be discussed.

The save() method: I've chosen to have a single method that can either insert or update an entity, based on its id. The problem with this approach is that, firstly, the method has more than one responsibility, making it a bit confusing to understand what it really does. Secondly it relies on the entities id, that needs to be a long, making it a very specific and weak implementation. The advantage is that from the outside (client code), you don't need to worry about the details. Just simple call save() and you are done. If you prefer a more generic and more cohesive implementation, make the getId() method return a generic type and split the save() method into a create() and update() methods. My idea here was just to make it simple to use.

EntityManager dependency: Here is where the biggest problem lies. For it to work well, every time a new instance of a entity is created, either by using new EntityXYZ() by hand or when it is created by a framework (e.g. as a result of a JPA / Hibernate query), we want the entity manager to be injected automatically. The only way I found to make it work is using aspects with AspectJ and Spring.

Configuring AspectJ and Spring

My idea here is not to give a full explanation about the whole AspectJ and Spring integration, mainly because I don't know it very well myself. I'll just give the basic steps to make this example work.

First add @Configurable to the Entity. This will tell that the entity will be managed by Spring. However, Spring is not aware of instances of the entity, in this case, Traveller, being created. This is why we need AspectJ. The only thing we need to do is to add the following line to our Spring context xml file.

<context:load-time-weaver />

This makes AspectJ intercept the creation of beans annotated with @Configurable and tells Spring to inject the dependencies. In order to the load-time weaver (LTW) work, we need to override JVM's class loading so that the first time our entity classes are loaded, AspectJ can kick in, the @Configurable annotation is discovered and all the dependencies are injected. For that we need to pass the following parameter to the JVM:

-javaagent:<path-to-your-maven-repository>/.m2/repository/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar

The snippet above is what we must use if using Spring 3.0.x. It works fine inside Eclipse but apparently it has some conflicts with Maven 2.2.1. If you run into any problems, you can use the old version below.

-javaagent:<path-to-your-maven-repository>/.m2/repository/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar

Another thing that is a good idea is to add the aop.xml file to your project, limiting the classes that will be affected by AspectJ. Add the aop.xml to src/main/resources/META-INF folder.


 
  
  <include within="com.lscc.ddddemo.model.entity.*" />
  <include within="com.lscc.ddddemo.model.entity.builder.*" />
  <exclude within="*..*CGLIB*" />
 

 



NOTE: The exclude clause is important to avoid some conflicts during the integration test. AspectJ sometimes tries to do some magic with the test classes as well causing a few problems and the exclude clause avoids that.

Making the integration test work

I'll be using MySQL, so I'll need a database with the following table there:

CREATE TABLE `traveller` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
`country` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB 

As I'm using JPA 2.0, we need a persistence.xml that must be located at src/main/resources/META-INF


 
    
        com.lscc.ddddemo.model.entity.Traveller
 
        
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
 
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/lscc-ddd" />
            <property name="hibernate.connection.username" value="root" />
 
            <property name="hibernate.c3p0.min_size" value="5" />
            <property name="hibernate.c3p0.max_size" value="20" />
            <property name="hibernate.c3p0.timeout" value="300" />
            <property name="hibernate.c3p0.max_statements"
                    value="50" />
            <property name="hibernate.c3p0.idle_test_period"
                    value="3000" />
        
    
 


In our Spring configuration, we also need to tell Spring how to create an EntityManager, providing the EntityManager Factory:


        
    
        <property name="persistenceUnitName" value="testPU" />
    

    <tx:annotation-driven transaction-manager="myTransactionManager" />
 
    
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    
       


In order to separate unit tests and integration tests in my Maven project, I've added a different profile for the integration tests in my pom.xml:


   with-integration-tests
   
    
     
      org.apache.maven.plugins
      maven-surefire-plugin
      
       always
       -javaagent:/Users/sandro.mancuso/.m2/repository/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar
      
      2.5
      true
      
       
        integration-tests
        integration-test
        
         test
        
        
         
          **/common/*
         
         
          **/*IntegrationTest.java
         
        
       
      
     
    
   
  


So now, if you want to run the integration tests from the command line, just type:

mvn clean install -Pwith-integration-tests

If running the tests from inside Eclipse, don't forget to add the -javaagent paramenter to the VM.

Conclusion

So now, from anywhere in your application you can do some thing like:

Traveller traveller = new Traveller();
traveller.setName("John");
traveller.setCountry("England");
traveller.save();

The advantage of using the ActiveRecord:
- Code becomes much simpler;
- There is almost no reason for a DAO layer any more;
- Code is more explicit in its intent.

The disadvantages:
- Entities will need to inherit from a base class;
- Entities would have more than one responsibility (against the Single Responsibility Principle);
- Infrastructure layer (EntityManager) would be bleeding into our domain objects.

In my view, I like the simplicity of the ActiveRecord pattern. In the past 10 years we've been designing Java web applications where our entities are anaemic, having state (getters and setters) and no behaviour. So at the end, they are pure data structures. I feel that entities must be empowered and with techniques like that, we can do it, abstracting the persistence layer.  

I'm still not convinced that from now on I'll be using ActiveRecord instead of DAOs and POJOs but I'm glad that now there is a viable option. I'll need to try it in a real project, alongside with Command Query Responsibility Segregation (CQRS) pattern to see how I will feel about it. I'm really getting sick of the standard Action/Service/DAO way to develop web applications in Java instead of having a proper domain model.

By the way, to make the whole thing work, I had loads of problems to find the right combination of libraries. Please have a look at my pom.xml file for details. I'll be evolving this code base to try different things so when you look at it, it may not be exactly as it is described here.

https://github.com/sandromancuso/cqrs-activerecord

Interesting links with more technical details:
http://nurkiewicz.blogspot.com/2009/10/ddd-in-spring-made-easy-with-aspectj.html
http://blog.m1key.me/2010/06/integration-testing-your-spring-3-jpa.html