Saturday, May 31, 2014

"Slowly and carefully"


I once asked a coworker with an official title of Senior Software Architect, how he makes decisions and gives recommendations on the architecture of our product. “Slowly and carefully”, he replied. He was an honest and hard-working person, a very smart guy, and probably a decent architect. Yet our product’s architecture was terrible, and it was not improving as time went by.

Two deadly sins of software architecture were ubiquitous in our code base

  • Everything was tightly coupled with everything else
  • Same information was defined in multiple places

In day-to-day work these problems caused lots of hard-to-trace bugs, showing up in seemingly unrelated portions of the code. Changes required touching lots of code, leading to more bugs. And it was very hard to write tests – so tests were not written.

So, what was my colleague doing wrong? The architectural changes he and the team inflicted on the code base were fine - mostly because very little changes were made. There was no opportunity for a serious refactoring effort to improve on the underlying structure. The bad stuff that accumulated over time continued to accumulate. The new features represented good ideas, but were poorly implemented – or, rather, were implemented in much the same way as old ones, creating more bad code.

Looking back, there was a culture problem with the approach of “slowly and carefully, with no objective criteria, teamwork, or testing”. The architect did not write code. He provided suggestions that were implemented by other people. Programmers wrote code per instructions, and did not create tests to fully exercise the added or modified code. The architect did not have the feedback on how well his ideas fit into the code base, and programmers had very vague feedback on how their changes affected the system.

Most of the time, the architect's solutions were fine.  He was familiar with the code, has been on the project for a long time, and knew the team well. But since his suggestions were hardly ever challenged, and never tested against competitive ideas, it is impossible to tell whether what he offered was really good - or barely good enough.

Every so often, a developer would complain that the solution suggested by the architect did not work, and it became a point of pride for others to write some “clever” code to fit the square peg (architect’s suggestion) into a round hole (existing code). It is well established that the “clever” code is more bug-prone and harder to maintain, compared to straight-forward and easily readable code.

Sometimes, no amount of cleverness could fit a new elegant idea into the clunky existing code, and then people improvised on their own. Most of the time, those were good, solid solutions, but not always. There also was an illicit feel to the situation, and some developers tried to avoid code reviews in these cases. There were a few scary monstrosities quietly sneaked into the code base as a result.

Splitting the implementation and design work prevents everybody from learning from their successes and mistakes. Having an architect dictate unchallenged solutions creates sub-par performance, tension and funny feelings even on the best-intentioned team.


Thursday, May 15, 2014

Magic-8 ball, and other approaches to problem-solving


There is a complicated way to do complicated things. Think long and hard. Spend hours staring into the blank space, screen or a sheet of paper or a list of specifications, or what-have-you. Then spend more hours furiously typing or writing or arguing out loud, while pacing nervously. Grab heavy, plain-jacket books with no pictures and very small font, throw them around. Doodle, draw up UML charts, and write down dozens of numbers… Do all of the above in freshly dry-cleaned business attire, or PJs, or worn-out jean shorts, or nothing at all.  Repeat until half hour before the deadline. Feel very excited about the results. 

This is pure magic. It is shrouded in mystery and emotion, takes magical amounts of time, and delivers unpredictable results with unknowable certainty. When it succeeds, it triumphs heroically, and when it fails, it does so with a big loud bang.  

There is also an easier way. Make up something, anything, however wrong it may be. Devise a test, and perform it. Go back to the drawing board, the text editor, the spreadsheet, etc. Notice the problems in the previous idea and implementation. Then try again, taking the new information into account. Update the test as well. Continue until happy with the results. Heavy books, typing furiously, and worn-out jeans may still come in handy, but this way those are means to an end, not a pure expression of experiencing a difficult and unfair world.  

When a complicated problem is solved by taking a small step at a time and adjusting, there emerges a combination of two possible solution paths. One path is as expected: iterating over small steps leads to a locally optimal solution. The achieved solution is local to wherever the initial, the least educated and therefore the most random, guess happened to be. In a lot of situations, this is good enough: achieved solution is proven to fit the problem by a series of tests, it is achieved in a reliable and predictable way, and no magic is required.

The other path is less expected, but nevertheless fairly common. Making small steps in the possible solution space allows to build an intuition about the underlying patterns and relationships. In addition to a set of concrete, tried-and-tested solution points, there emerges a deeper understanding of the problem. This leads to an intuition that allows to escape the local maximum, and helps reason about the entire solution space. Furthermore, a test-driven approach gives additional freedom to try out and gain confidence about further-fetched ideas in a systematic way.   

The iterative approach is simple, rational, and pragmatic. It succeeds routinely and quietly, and fails rarely and cheaply. Magic may still happen, but it will be more grounded and less dramatic.  More importantly, magic is not a requirement for success. 

How magical do you want your problem-solving to be? 


Monday, May 5, 2014

Monkey see, monkey do

Chimpanzee at Monkey World Ape Rescue Centre

A programmer, computer programmer, developer, or software engineer is a person who writes computer software. [Wikipedia, "Programmer"]

Computer programming (or programming) is a process that leads from an original formulation of a computing problem to executable programs. … The purpose of programming is to find a sequence of instructions that will automate performing a specific task or solve a problem. [Wikipedia, "Computer Programming"]

Software engineering is the application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software.  It involves the establishment and use of sound engineering principles in order to economically obtain software that is reliable and works efficiently on real machines.[Wikipedia, "Software Engineering"]

Engineering is the application of scientific, economic, social, and practical knowledge in order to design, build, maintain, and improve structures, machines, devices, systems, materials and processes.  Origin of term: from Latin ingenium, meaning "cleverness" and ingeniare, meaning "to contrive, devise". [Wikipedia, "Engineering"]

Code monkey means an unskilled computer programmer who can only perform programming tasks by copying examples, usually where they do not truly understand how the code works. ‘Code monkey’ is also a job description for a job that treats even experienced programmers in a way that trivializes their problem-solving abilities.[Wikipedia, "Code Monkey"]

Owls @ Dragonheart, Enschede

Thursday, May 1, 2014

Agile smells


“In computer programming, code smell is any symptom in the source code of a program that possibly indicates a deeper problem.” – Wikipedia

Agile way of working provides for a lot of flexibility.  Agile values and frameworks come with significant freedom for all participants, letting teams and stake-holders design their own implementations of Agile. And with the freedoms come the risks, and the smells.

Agile smell, similarly to code smell, is not necessarily a problem by itself, but rather a likely indicator of a serious problem with the team’s way of work.  Smells can be caused by following the letter, but not the spirit, of the Agile framework, gaming or cheating the system, or simply lack of understanding the reasons behind the framework rules.

Does your team’s Agile implementation smell?  

Smells “We do not really work together” 

  • Team members are routinely late to or even skip daily Scrum. Those who come to Scrum deliver short statuses: “Everything is good. My work is on track.”
  • Immediately after the daily Scrum meeting is over, team members retreat to their private spaces to work on their tasks. Or put on headphones. Or display in some other way that talking is over, and "real" work has began.
  • Scrum board is out of date. Online tracking tool is hardly used for anything, but reporting.
Daily Scrum, visual board and knowing how the Spring work for the entire team is progressing are important to facilitate team members working together to get work done. When a Scrum meeting or a Scrum board do not bring forward interesting and relevant information about the minutiae of team’s work, this is an Agile smell of the team not working together.  

 Smells “Agile is something we do when we are not too busy with real work”

  • Agile framework meetings are regularly rescheduled or cancelled to make time and space for technical and product meetings.
  • There are permanent roles on the team, that are not Agile roles.
  • During the retrospective the team reflects on the iteration behind, but hardly anything happens based on that discussion.

Agile framework may look like a game, but every role, ceremony and artifact are there for a reason.  Doing just bits and pieces that fit into the schedule does not make a team Agile.  It just makes people busy.  

Smells “We are not as self-organizing and empowered as Agile tells us to be”

  • The conversation in meetings revolves around the manager or Scrum Master, with each team member talking to that person, rather than the entire team.
  • The work is prepared, researched and even assigned by the manager or one senior team member.  That person coordinates all interactions with other teams. 
  • All or most communication between team members is facilitated by the manager.

Agile approach is built around a strong, motivated, powerful team with a servant leader working to serve the team.  Many groups struggle with becoming that team, especially when coming from the traditional model where the manager is above and in charge of the team. These smells are an indicator that the team is operating in the command-and-control structure, rather than following Agile principles.