Published on

Making Good Software Takes Time

Authors

If you have been working as a software engineer for a while, you must have faced the dreaded question of "Why this is taking so long?" from your immediate boss or executives.

While their question is valid and innocent from their point of view and they are right, it is a question that is not always answered properly.

Some people don't answer this properly, as it's awkward to make a conversation on this, and just resort to making the manager happy by burning the midnight oil.

Though your manager is happy for time being, the question is still unanswered. And this kind of temporary fix is not sustainable in the long run.

So why does it take so long?

Short answer: Because of non-functional requirements.

Long answer:

Software requirements are broadly divided into two categories:

  • Functional requirements
  • Non-functional requirements

Functional requirements are the ones that are required to be fulfilled by the software aka "the spec"

Nonfunctional requirements are the ones that happen in the background, not seen by the user typically but need to be present in the software.

What are these Non-functional requirements?

  • Security
  • Performance
  • Availability
  • Reliability
  • Scalability
  • Observability
  • Maintainability

Let's take an example specification and dive into this topic:

The following is the user story:

As a user, I want to be able to create a new blog post. I want to keep it simple, just a title and a body. I should have the ability to edit and delete the blog post. I should be able to view all the blogs created by me in descending order of creation date.

Pretty standard user story, right? Yes.

Let's write down the functional and non-functional requirements for this:

Functional Requirement:

Store the text in a database. Have the ability to retrieve the text and show it to the user.

Non-functional Requirements:

Security/Authorization:

  • A non-logged-in user cannot create a blog post
  • A logged-in user can create a blog post
  • A logged-in user cannot edit or delete a blog post of a different user
  • A logged-in user cannot create more than 10 posts in one hour aka rate limiting

Performance & Scalability:

  • The blog post creation time should be indexed in the DB.
  • Index API should respond in 200 ms.
  • Should be able to handle the peak loads when there is a viral blog post.

Reliability & Availability:

  • Software should work as expected even when there is a software failure/hardware failure in one part of the system
  • The system should handle the sudden failure of the DB.
  • The system should handle if one of the web servers goes down.

Observability:

  • The system should be able to monitor the performance of the system and take appropriate action.
  • Logging and error handling/reporting should be done.

Maintainability:

  • Software should be easy to maintain and extend.
  • Software should be easy to test.
  • Software should avoid complexity by abstraction and encapsulation.

From the above points, we can observe that the non-functional requirements are not trivial. It takes considerable time to achieve these requirements.

These non-functional requirements are often not talked about, but they are important for a well-designed software.

Only when things go wrong, do we see the importance of these non-functional requirements.

Example:

Monitoring is not present on the system, and a user could not create a post. Systems won't be able to alert us when it's not working for the user. It's only observed when an internal team member notices it or worse when a user complains about it on Twitter.

Summary:

The Non-functional requirements are as important as functional requirements. Engineers need to effectively communicate the non-functional requirements to the team/stakeholders by emphasizing the importance of these requirements. One way of doing this would be creating cards for all the non-functional requirements when breaking down a story/epic.

For following the rigor, we create a checklist for the non-functional requirements and cross-check them before merging a pull request.