Aspiration and Advisory

View Original

Software Complexity: Developers View

Developers often complain about the complexity of the software they have to develop or support. They mention application architecture, amount of supported code, code complexity, business requirements, and the way customers use an application (user experience). Let us have a look at the most prevalent complaints, underlying issues, and ways to deal with them.

Application Architecture

Complaint. Application architecture is too hard to understand because of lots of components, unclear responsibilities, and dependencies between them. Another issue is that multiple design patterns used without actual need. Data flow is too complicated or not transparent.

Issue. Application architecture missing proper documentation about the overall structure, separate components, and data flow. Architect and developers use patterns without a deep understanding of their purpose.

Solution. Document architecture from the very beginning of the project e.g., using UML diagrams. Describe all components, their responsibilities, and dependencies. Discuss design patters usage with the team to avoid over-usage, apply KISS, and YAGNI principles. Describe data flow and make sure every team member has access to it.

Explanation. This kind of complaints is common for small startups grown to a big application. An architect should schedule and perform refactoring of architecture to adapt it to constant growth and new requirements. Need to documenting everything and introduce control of architectural changes.

Amount of Supported Code

Complaint. Application has too big codebase. Navigation between the components is problematic. Developers have to work with lots of external dependencies. Hard to do changes in multiple components simultaneously. 

Issue. Application code does not have a proper structure, and the structure is inconsistent or too complicated. Application stores external dependencies in the inconvenient or inconsistent way. There is no easy way to commit to multiple repositories and sync code.

Solution. Come up with a convenient and extendable code structure both for application code and external dependencies. Ideally, there should be no difference between application code and external dependencies from the developer's point of view. Use only one package manager to handle all the dependencies. Make sure that every component has a clear and well-documented interface, use programming by contract. Store all the code in the same place e.g., using monolithic repository strategy. 

Explanation. Such problems usually appear when an application had multiple architects, and each one used a different code structure and package manager. Need to unify code structure to make it convenient for developers, and control this structure in the future. Developers should be able to work on a few components and interact with other components using only interfaces. A monolithic repository can solve access and sync issues, only make sure that it is easy to use.

Code Complexity

Complaint. Code is hard to read and understand. Too many classes. Dependencies between classes are not transparent or hard to guess. 

Issue. Code styles and standards are not defined. Components have inconvenient or inconsistent structure. Names of classes, methods, and properties do not explain what they do.

Solution. Define strict code styles, white guidelines, share and discuss them with the team. Conveniently organize component content, document this structure, and make sure that all components written in the same way. Define strict standards related to code complexity using existing metrics — cyclomatic complexity, NPath complexity, etc. Use one of the naming conventions to write all code in the same style. Automate all code style and complexity checks e.g., using built-in IDE tools and continuous integration.

Explanation. This issue appears in the middle and big projects developed by several teams. Common code style and naming conventions can eliminate (or significantly decrease) time needed to switch between components. Automated checks help to maintain consistency and prevent such issues in the future.

Business Requirements

Complaint. Business requirements are changing too often. There is no way to build an architecture to handle all future use cases. Developers rewrite code constantly. Need to spend lots of time to retest the functionality. Technical debt is overgrowing.

Issue. Wrong or missing software developing methodology. Lack of or poorly organized business processes inside the team. Not extendable or over-complicated application architecture. Developers are not aware of the refactoring best practices. Nobody writes automated tests. Nobody controls the overall application and code quality.

Solution. Use agile methodology — Kanban is better for a small group; Scrum is suitable for a bigger team. Discuss and reorganize business processes; involve product owners and customers if needed. Refactor architecture to make it simple (KISSYAGNI) and flexible (SOLIDGRASP), but cover all the requirements with automated tests first. Get familiar with refactoring best practices and automated tests. Cover all the acceptance criteria with automated tests, make sure that code always passes them. Write a list of all technical issues, prioritize them, and schedule a time to fix them.

Explanation. Agile methodology is not a silver bullet, but it is quite useful to achieve needed flexibility. It is crucial to organize business processes to help the team, not to interfere. Each developer always has to know one thing he/she has to do. Architecture simplicity and flexibility are essential, but it is almost impossible to achieve both, so try to maintain a balance. Refactoring and automated tests are must-have for any software engineer. Automated tests may take some time in the very beginning when the team is not familiar with them, but they will save much more time in the future. Be aware of your technical debt and always justify its reduction.

User Experience

Complaint. Customers use an application in the unexpected, not supported or not intended way. It is impossible to use an application workflow. Customers report multiple issues because of invalid data passed to an application.

Issue. Missing or insufficient documentation. The user interface is complicated, not intuitive, and inconsistent. An application does not validate input data properly. Customer can not understand how to deal with errors as they are not self-explanatory.

Solution. Write proper extensive documentation that covers every aspect of an application — user interface, data formats, possible errors, supported workflows, etc. Application page should have a link to an appropriate documentation page that explains what this application page does. Improve user interface to make it more intuitive. Add possibility to send feedback from any page and collect all entered data (or make a screenshot).

Explanation. Pretty much every application has such errors. The best practice here is to explain to the customer how to use an app before granting him/her access to it. You may also ask several customers (focus group) to explain their needs and workflows, and then customize an application to fit these requirements.

Do You Have a Complaint?

This article does not cover all possible issues related to software complexity. It just shows common problems and proposes convenient ways to deal with them. But even if you will follow all mentioned best practices, it does not mean that you will have no issues.

The longer an application exists, the bigger it is — and the more complaints you have. Developers will always be displeased by the way app built, works, and used. You should collect this feedback, understand the issues, and fix them as soon as possible. Such an approach reduces team effort and saves a lot of time and money in the long run.