Lessons learned from 3 years in a single project
By: Jakub Dzikowski
Tags: Software Development, Best Practices, Productivity, Agile

Our culture of work

We are a fully remote company and we do not work on-site. Usually we provide small teams of 2–5 people in quite a short to medium term projects of 6–18 months. We get our job done, implement features, improve the performance or code quality of the existing projects. The client is happy and we leave. But there are obviously some projects that take more time.

Since we have small teams with no managers, the developers are responsible for the contact with the client. No bottlenecks, we speak with clients directly. Besides that, we at SoftwareMill, hire only advanced professionals from Poland. (Note: If you worked in the industry for a few years already and you think your expertise is below that level — there is actually a good chance you’re an advanced professional — you know what you don’t know. Socrates would be proud of you.)

Each one of our developers has slightly different technical background, preferences, habits and different career history. However, we have common standards regarding quality of code and software engineering process, that might not be so obvious for developers working in other companies (like CI, testing, pair programming, code reviews etc.).

Because of small teams and highly experienced developers, with no exceptions, we have no pre-set hierarchy in teams. Some of us feel better in particular technology, some of us are better in getting things done, some of us are better with talking with the clients. But, basically, we are more-less equal regarding experience and skills.

All of these results in great autonomy in work process. In a few projects there are some technical stakeholders that impose some practices, nevertheless, in most cases, the decision is ours. In the project I worked in for the last three years we had the full autonomy regarding the software engineering process. Our client required the working software only.

The communication with the client

Clients are often busy. They need the features we implement, but simultaneously they have their own companies, their own businesses to run, what consumes almost all ot their time. There are obviously cases when a client is represented by dedicated Product Owner or by the person who is technically involved in the project. Then the communication is more fluent. However, in my project, we were talking directly with one of the company owners, and he is a really busy person.

Basically, I have three pieces of advice here:

Insist on face to face meetings. Do, whatever it takes, to have regular meetings. Adapt. You cannot change everything.

The face to face meeting changes everything. When you work remotely and you have meetings on Skype or Google Hangouts/Meet, your communication is limited. You cannot take advantage of most non-verbal signals, because they are disturbed or hidden by the medium you communicate through. You cannot really feel the other person intentions, recognize real goals and attitude. After face to face meeting you just understand each other better.

Regular meetings are about coordination of software development process. You need to verify that you are going in the right direction on a regular basis. The sooner you will find out some misconceptions, the easier you will fix them.

Since our client was a really busy man, meeting during standard business hours was almost impossible. We had to constantly reschedule and eventually cancel meetings, what led to frustration and gaps in our understanding of the domain and business requirements.

After few weeks we agreed to schedule meetings twice a week at 8:00 PM and it was one of the best project decisions we made. That was it. We had regular meetings. We had regular feedback. We felt that our work was meaningful.

We cannot involve our client in the business analysis to the extent we wanted, but hey, we were senior developers, we were able to handle it. We just gathered the ideas and high-level requirements, formalized them, made some assumptions about the things we were not sure of, but we got it. We adapted. Regular meetings, twice a week, was enough to confront our assumptions with the reality and gather feedback about working features. We were able to carry on.

The code quality

Some agile practitioners argue that there are no compromises on code quality. The reality is different. Probably in most cases an enterprise application will require better quality than a startup, when you want to check whether a feature is desired by your customers. As a senior developer you need to know what tradeoffs you can make. You will eventually take some technical debt. You just need to keep low interest rates.

At the end of the day your client pays for the features delivered. You don’t need to build microservices when the monolith is sufficient. You don’t need to test every edge case in Selenium tests. You don’t need sophisticated architectural patterns when the simple solution works.

But that doesn’t mean you don’t care about the code quality. Different domains require different quality. It is OK to have some parts of the code better covered with tests, and test the happy path in the other parts. The crucial thing is to determine when the better quality is required.

But you cannot do it by yourself only. You need a different perspective.

Code review is a must. Internal discussions about the tech and business domain is a must. Pair programming is sometimes useful, however I don’t think it’s crucial.

Those techniques are useful not only in ensuring required code quality, but also in dissemination of knowledge among the team. They build better understanding of the project with all its complexity. They also lead to better coherency in the code and the architecture.

The Conway’s law works, even within such small teams. Everyone has different way of thinking and different coding patterns. It is good to take some actions to unify them. If you don’t, you may end up with chaotic code, duplication and lack of common understanding.

It is very useful to have some kind of automatic code formatting tool (regardless of an IDE). For the backend code we had Scalafmt (and, unfortunately, no linter, like for example WartRemover). We had ESLint with Airbnb rules for the frontend.

Funny thing is that at the beginning, when we introduced Airbnb rules for ESLint, we had about 550 ESLint errors that couldn’t have been fixed automatically. Way too much to fix it manually, we had to deliver business features. Instead we added a linter step in our CI environment what verified that there are no more ESLint errors than 550. We were following the Boy Scout Rule to fix them and constantly decreased the number of allowed errors. After a few months we got rid of over a half of it.

Finally, you need to be careful with the Boy Scout Rule. Don’t over-scout. Your client pays for the working software. You must find a balance.