Consultant's Corner: Developing a successful solution
In this article, Software Engineer Zbigniew Manasterski goes into detail about his latest freelance project for an international financial institution and provides a glimpse of the often fluid and challenging work conditions high-end developers navigate in.
Welcome to the Consultant’s Corner series, our blog for independent IT freelancers. Here you can find out what fellow high-end IT consultants are up to in their current or recent projects. Read about trending technologies, and get inspiration from the freelance journey of other like-minded IT professionals.
Introduction
I am a software engineer currently working as a freelancer for an international financial institution. Together with two other colleagues, both consultants as well, a year and a half ago, we were tasked with designing and implementing a new application to replace an existing one, for one of the business units. The system was supposed to be used to automate part of the business process for which the unit had responsibility. This process involves interacting with customers and translates into higher revenue for the company. The old application did not conform to global policy placed by the company’s international headquarters and was generating too many incidents for such an important business process. These two factors were enough to approve a budget for a new project.
The project setup
Every project team in the organization works in Scrum – both employees and consultants. There are no ‘buts’ in this scrum – there is a development team, a Product Owner (PO), a Scrum Master and stakeholders. The Product Owner dictates the contents of the product backlog, and the development team estimates and accepts the contents of the sprint backlog. There are no architects nor analysts in this setup, so my two colleagues and I have taken on these roles as well. We discuss requirements and UX design with the business, plan architecture, create code and test – before we handle features for business to acceptance testing.
Challenging project beginnings
At the beginning of the project, stakeholders of the business unit were a bit doubtful of the IT part of the team – us and our PO. But three months after the project started, we lost our PO – he left the organization to create a startup – and this turned out to be better for the project. As the old PO already had a bad history with the business unit and did not trust it to deliver any actionable or usable requirements. There were a few trust issues on both sides, and the business side were hesitant about whether we would be able to comprehend their needs, in part due to the complexity of the domain. But the team got assigned a new PO, who promptly set up a couple of workshops, and insisted on having extra refinements and meeting with current business stakeholders, and things started to look up.
At the same time, it was announced that the organization would be transitioning to a new structure, where business units across several countries would be merged. Also, the applications used in some countries needed to be integrated or replaced by new, common ones. A top manager who was responsible for the business unit we worked for, as well as other similar units from other integrating countries, sent his analyst to act as a supplemental PO and give some cross-country requirements.
From a shaky start to solid collaboration with the business side
Thanks to the new PO and support from our management, we started spending a lot of time talking with the business. We got to know each other better, and the business started to be more involved in the project. But there were clashes between the stakeholders – some were putting pressure on delivering local features, and some were working on fitting the application to other global requirements. Sometimes we had to act a bit as negotiators between them. At the same time, we had to keep in mind that none of the current local processes in any of the business units could be mapped fully to the application – to fit everyone. The local processes had to change. Still, some of the local requirements were related to different legal rules in each country, and that is something that we needed to keep remembering as well. Given a limited amount of time, we pointed out it was impossible to deliver all the locally required features for every country. We managed to get stakeholders to focus on delivering all the features required to replace the old application. Additionally, once priorities were aligned amongst stakeholders, it was possible to proceed with the project more smoothly and further improve relations.
In need of a modern approach to software design
Good relations with the business side enabled us to use Domain-driven design (DDD) methodology for the project, but still, the situation was not ideal. We managed to create the Ubiquitous Language, and an excellent domain model, just as described in the book “Domain-driven design” by Eric Evans.
But the organization was undergoing many changes. The business unit for which the project was for, was being merged into a cross-country unit, with new and more involved leadership. This new leadership delegated additional stakeholders to the project to impose a new vision and new priorities. One such difference was a set of reporting features. The local unit required a lot of reporting features implemented so employees could conduct quality assurance tasks within the application. This was in part because the old application was so unstable that it forced the business to constantly check if the application and the process were working correctly.
However, this part was not as important for the new leadership, and after delivering several new reporting features, we were directed to other tasks. According to the new stakeholder, data analysts should be able to use our database to conduct any reporting needed.
Later in the project, this turned out to be a big issue. Since we stopped discussing what would be needed for reporting, we did not discover parts of the knowledge required to create the correct domain model – ours was close, but not entirely what it should be.
No room for mistakes
We learned that when data analysts came to us to ask how to work with our data model to retrieve data for the reports they needed. In our model, it turned out that the contracts between our customer and external companies, who were providing some services used in this process, were not upheld by our application. We were shuffling resources that should be assigned to a certain provider for a certain period, before that period ended, between other providers. We were aware of this period of time existing, and we had this concept in our model. However, we were not aware that we should keep the resources assigned for this period to providers at all times.
This issue could cause problems – providers were billing the organization we worked for in part based on the resources’ assignments. These assignments were also used to assess the performance of the providers. Companies with worse performance could get fewer resources assigned in the next periods, and have less work because of that – potentially leading to the termination of employees. Essentially, what was our mistake could end up costing somebody his or her job! On top of that our application was already live when we discovered this.
Refactoring the newly developed model to fit the business
Thankfully, the organization we work for grants a lot of freedom to developers to select the scope of work they accept each sprint. It is set up in such a way as to allow software engineers to have enough time to deliver quality code, that follows SOLID* rules. The application we created had a lot of unit and integration tests written – some based on user stories – as we consider code that is covered with automated tests to be of higher quality than similar code without any tests. With 80% of code coverage, we were comfortable to do some brainstorming to figure out a way to refactor our model to match the business process more closely. We had to change the lifecycle of one of our aggregates, and introduce a brand-new entity, to facilitate managing events related to the new lifecycle.
Furthermore, we added tests for the new scenarios, and we also performed extensive manual testing, which helped us catch a few previously unnoticed edge cases. The logic grew more complicated, but with one additional round of refactoring and testing, we managed to cover all cases, and we deployed changes to production. Then we were able to explain to the data analysts how to use our data model. After completing a couple of iterations of ‘test reports’ with them, we were confident that the business would base their decision on valid data.
The result is efficient business processes
Overall, the project was a success. The business team is incredibly happy with the tool. They are impressed by the looks, thenavigation and layout – all elements that we were in continuous dialogue about throughout the project, and most importantly, the tool fulfills their needs. The management had hoped the project would have finished faster, but they are still happy with the results. There is less manual work in the process now, and it is easier to do quality assurance and find any issues with the process. The tool will replace its older counterpart in other countries within the organization so that the same one is used everywhere.
Good relationships helped pave the way for the project
Throughout the project, I had a chance to observe the evolution of a fruitful stakeholder relationship, and I learned how important having a good one is. Without the goodwill, we would not have been able to deliver all the features in scope (as tests and quality were a must, any lack of time meant reducing the scope). This would have resulted in the business unit’s workers taking on more manual labor than necessary.
Lastly, we would not have been able to create the ubiquitous language needed to make the domain model that enabled us to communicate with the business about features and requirements efficiently.
SOLID principles make for better results
It was proven again how important it is to have good code coverage and how important it is to follow SOLID principles when writing code. Following these principles makes code much easier to test using unit and integration tests. Having SOLID and covered code allowed us to go smoothly through a couple of domain breakthroughs and refactoring sessions. At any time, we were confident that if necessary, we would be able to change and refactor our model and code, to match new domain discoveries and new business requirements.
Thank you for reading!
Further reading
If you are interested in learning more about Domain Driven Design I recommend reading “Domain-Driven Design" by Eric Evans, or “Implementing Domain-Driven Design” by Vaughn Vernon.
*SOLID stands for following principles: Single Responsibility, Open-closed, Liskov Substitution, Interface segregation, and Dependency Inversion. Explanation of these principles can be found in many places, but I would recommend reading it from one of the biggest promotor of SOLID principles: Robert C. Martin. One of his articles titled “Principles Of Ood” holds short but informative explanation.
Who
Zbigniew Manasterski is a Software Developer with ten years of commercial experience focused mostly on developing solutions with the use of technologies such as .NET Core or ReactJS. He is skilled in Object-Oriented Programming (OOP); he has strong competences in web development, particularly in the frontend layer; however, he is also experienced in the backend area. He has worked within several sectors including electronics and telecommunication industry as well as a Microsoft Development Center in Norway.