Software Development Lessons From a Day of Farming in Poland

A Brazilian programmer walks into a Polish farm may sound like the beginning of a joke, but that’s how my last weekend started.

It all began when my girlfriend and I were invited to a wedding in Poland. My girlfriend’s family live in a lovely village near Krakow, so we planned to stay there for over a week.

A day before traveling, I recorded the Clean iOS Architecture pt.5 video, so in my first morning there I kept my regular physical exercise and work schedule. I was done with the video editing by 11 am and, for the rest of the day, I volunteered to help with the day to day farm duties.

Just like when I join a new software team, I was trying to find how to deliver a meaningful contribution. I usually look for areas of the code where people have been struggling with or avoiding at all. And there in the farm, I found the perfect analogy: gardening.

Due to high demands on other areas of the farm (priorities), the grass (code) grew out of control this year. Just like unmaintainable messy code, the grass became a problem. The garden usually is well kept (QA) but, like software teams, they also face technical, environmental and social challenges and there were good reasons why the garden (codebase) couldn’t have been looked after better. For example, one of the family members was away on a trip and couldn’t contribute (developers on holiday / short on staff). The rain (uncontrollable and unpredictable environmental challenges) made the work much harder since the usual tools are not suitable for muddy terrains. Also, the tractor needed repair (technical challenge) and fixing it could be more critical (priorities) to the overall farming needs (like keeping the CI server running to not block the dev team). In many areas of the farm (like crops), the work is a race against the clock (literal deadlines!). As an example, the raspberries were not picked up on time, and they rotted, so such crucial tasks will always trump the gardening duties.

However, gardening was being put to the side for too long. Taking care of the wild grass wasn’t the priority, but was getting in the way and stressing everyone out (again, just like that messy code we can’t find the time to clean). In short, the job had to be done. And with my lack of farming experience, solving the grass problem was probably the best contribution we could provide. And there we went into a pairing session towards a clean garden.

The grass was pretty out of control. It looked like a tough, and endless job.

The grass was pretty out of control. It looked like a tough, and endless job.

Committed chopped-off grass in the cart (history).

Committed chopped-off grass in the cart (history).

We started trimming the most straightforward part first, where the grass wasn’t so tall. We also had a fantastic machine (IDE/refactoring tool) to assist us. For the short grass (tested and predictable code), it was really a smooth and almost effortless job. The machine has a storage compartment (stage) that “automatically” stores (track) the chopped-off grass (changes). Eventually, we would have chopped-off enough grass that we would have to empty the compartment (commit) before carrying on.

Remote destination.

Remote destination.

The earlier we emptied the machine, the better since the engine slows down when almost full (it crashes when completely full). However, if we kept emptying it too early, we would waste a lot of time with no real benefits. Checking (status) the storage compartment (stage) take little to no time at all, so we would check the compartment often and decide if we had enough to commit or if we could carry on for a little longer before committing. The “committed” grass was put into a cart (history) that would later be pushed to some other place (remote).

The analogy with git is not perfect as we couldn’t “revert back” history. The closest we could get to “reverting back” was to throw the chopped-off grass back to the ground and make it messy again! But we didn’t want ever to do that. The remote destination was a place to “reuse” the grass. Nothing is wasted, so the chopped-off grass is mixed with other waste to become compost. That compost can feed the soil with enough nutrients to support the farming (sharing/reusing code between modules to achieve business goals).

Along the way, we found many obstacles. For example, ants and wasp nests (bugs), trees (frameworks), rocks (stability and security issues), weird objects (unnecessary dependencies) and tall grass (lack of tests and visibility).

Getting rid of bugs nests (fixing bugs) were not our goal, but we would encounter them from time to time. Refactoring is not the time to fix bugs. Instead, we would just document them so we could report back and fix them later if they were a problem. For example, at some point, we thought we found a bee nest, which could be valuable to the farm (another source of food and income). We reported it to my girlfriend’s dad, but it ended up being just a wasp nest, which we didn’t want to mess with!

Apart from wild bug nests, there are also controlled and desired nests, like the farmed beehives. Beehives are valuable assets to the farm (like linting, build warnings and errors), so they are carefully kept in a special area. We were advised not to bother the bees (follow the linting rules!). The machine noise could make the bees feel threatened and attack us, so the grass in front of the hives was kept intact (don’t break the team rules).

Don’t mess with the bees!

Don’t mess with the bees!

Dead tree found during the refactoring.

Dead tree found during the refactoring.

Trees (frameworks) are another crucial part of the garden but were super annoying obstacles to the cleaning up process. We had to maneuver the machine around the trees since they are immobile and we can’t change then (like 3rd-party or system frameworks). Eventually, we found a dead tree, like a framework that is not required anymore. The dead tree roots (dependencies) are still buried deep in the ground, so we documented it and left the work to remove it for another day.

Chopping the grass around a broken and unnecessary object in the system.

Chopping the grass around a broken and unnecessary object in the system.

More annoying than the trees were objects that didn’t belong to the garden but there they were. With no role in the overall system, unwanted objects were just annoyances. For example, a broken car that we couldn’t get rid of (because it was broken!). We tried, but moving the car would require a lot of effort. We had to chop the grass around the car and pretend it wasn’t there. Like a suite of broken integration tests that can’t even be built anymore, but there it lives in the codebase.

What was the ladder doing in there? It ended up being the kids just playing around.

What was the ladder doing in there? It ended up being the kids just playing around.

We also found a ladder in a totally unexpected place, since there was nothing there to reach. The portable ladder is like import statements for unnecessary dependencies that are never referenced in the code. Those are easy to fix, we just remove them!

Rocks were another big problem since they could damage the blade (stability and security issues) or even break our machine (break the build and stop progress) so we had to check the ground (write more tests) before moving along. The fear of rocks (fear of breaking the software) got worse and worse as we approached the tall grass (untested, complex and coupled part of the system).

At some point, the machine (IDE) ran out of fuel (memory) and crashed. We fueled it up again (restarted the IDE) and kept going.

Restarting our IDE after a crash.

Restarting our IDE after a crash.

In the above photo of the machine, notice the storage compartment where it “automatically” stores the chopped-off grass. This “automation” tool is an important part to our productivity, but little did we know we would have to soon get rid of it.

As we finished the short grass (tested, visible and predictable), we stumbled upon the biggest problem: the tall grass (untested, unknown and unpredictable). The tall grass is that area of the code that everyone is afraid of. No one wants to touch it with fear of breaking it or being stung by wild bugs. “There might be big rocks and quiet bug nests hidden in there. And you don’t want to poke them!”

IDE without the storage compartment (DROPPED productivity).

IDE without the storage compartment (DROPPED productivity).

Another big problem was that the tall grass was wet. When using our refactoring machine on the tall wet grass, it would quickly fill up the storage or even worse, block the compartment door. Literally creating a big ball of mud that would crash our machine (IDE)! The only thing we could do to stay productive was to get rid of the storage compartment and let the machine throw the grass to the side.

Chopping the grass without the storage compartment.

Chopping the grass without the storage compartment.

Removing the store compartment fixed the blockage problem but increased the amount of manual work. It was just like we had to stop using our refactoring tool because the results were too unpredictable. It got to a point where manually doing some parts of the work was faster and more comfortable. This often happens to codebases, and although it feels like “it’s faster and easier” not to refactor, it’s always slower. When we cannot easily refactor our code with automation tools, we are almost always wasting time. If the grass is cut every other week, it’s an easy job. If we wait a month, it gets harder and harder. As the effort needed to clean increases, we start to justify to ourselves why we shouldn’t do it or why we should wait another month (which makes it even worse).

In our case, we now had not just to chop the grass, but also manually collect it from the ground to the cart. It may sound easy, but it’s not.

Manually collecting the chopped-off grass from the ground.

Manually collecting the chopped-off grass from the ground.

During the process, we would sometimes stop to rest from the sun and evaluate if we were doing a good job and find out how we could improve (Pomodoro technique or Hammock Driven Development). We eventually had a lunch break and came back, just like we would in an office. After a couple of hours, we reached a point where the grass was too tall for the machine as there was no visibility (lack of tests) and we were too afraid of rocks (stability and security issues). Without our refactoring tool, we had now two options: manually and carefully chop the grass with a scythe (shotgun refactoring) or using a tractor (big rewrite).

The broken tractor mentioned at the beginning of the article was about ready, and it was the most viable option. In the following day, the tractor helped to mercilessly chop-off all the grass, leaving behind a big pile of grass to be picked up. And the work was done.

Conclusion

Even though we bash and endlessly complain about legacy and messy systems, many of those systems still convert well for the business. So did the system we were working on. In the middle of all that mess, the system was still profitable (producing food). It was actually advised NOT to cut the grass around the crops, not to damage the productive areas. So after we finished with the grass, we went on another quest to collect the system’s profit.

Plums: one of the system’s profitable products.

Plums: one of the system’s profitable products.

Digging up the potatoes: one of the system’s profitable products.

Digging up the potatoes: one of the system’s profitable products.

Cabbage: one of the system’s profitable products.

Cabbage: one of the system’s profitable products.

Drying the products under the sun, so they don’t rot.

Drying the products under the sun, so they don’t rot.

After a great day at the farm, we prepared a delicious meal with the fresh food we picked up. It was an incredible experience that I definitely want to repeat.