Software Design


There are numerous benefits to simplicity. It’s easier to understand simple solutions. It’s easier to extend simple solutions. It’s less expensive to maintain simple solutions. The complex is the opposite. So why are most implementations complex? Because while it’s hard to build simple solutions, it’s easy to build complex ones.

We try to make the design as simple and elegant as possible. We use a few rules to help us achieve a simpler design. The first is to choose the simpler design if there are a few options. Then, you need to choose a testable design. Try to verify that design before implementing it. Do not over-engineer. Choose good metaphors. Use appropriate design patterns. Discuss your design with the team and improve it according to their feedback. It’s essential to simplify the design if others find it hard to understand. Refactor to a simpler design when it becomes too complex. Avoid premature optimization. Never forget that your ultimate goal is the simplest possible design that meets requirements.


The Rails Way and similar approaches work well only for smaller projects. We rarely use such approaches. We dedicate special attention to architecture from the beginning of development because most of our projects successfully grow and become large long-term projects. We prefer architectures that allow us to succeed in the long term. Our Guides cover the great architectures we use for successful long-term software projects. Such architectures bring numerous benefits: it becomes easier to extend and maintain functionality, it’s easier to swap old components with better new alternatives, it’s easier to scale, and it’s easier for new hires to understand code base. We also tend to use approaches such as Domain Driven Design that can be applied to all the platforms we work with from web backends and frontends to iOS and Android applications. All these things help us to reduce risks and costs, not to mention increase team member satisfaction.

Design Patterns

Design patterns are an essential part of our software design. This doesn’t mean that we apply design patterns to every piece of code. It means that we try to structure our code in the best possible way with the help of great design patterns. We maintain a great balance of simplicity and more complex design patterns.

NECOLT Guides has an extensive design patterns section. We actively maintain this section and everyone in the team follows and applies it. This set of patterns is used mostly in the software we deliver. We also use less common patterns that are not added to our Guides.


Software rarely remains unchanged for a long time. New features and improvements are constantly being implemented. Old features are removed. Optimizations are performed. Sooner or later, even the simplest or most elegant solutions become too complex. This increases costs, complexity, and the risk of introducing bugs. When this happens, it’s time to refactor and get back on track.

We do a lot of small refactorings often. Such refactorings are part of the new functionality. Developers are encouraged to make such small isolated improvements whenever it’s necessary. Small refactorings usually don’t influence the entire code base, and as it doesn’t take a lot of time, there is no need for a sophisticated process.

Sometimes a system needs to be changed significantly. For example, when a business model has been significantly altered, and some of the entities have fallen out of use or been changed significantly. Large refactoring is necessary if those entities were used heavily in the system. Such refactoring is not included in User Stories and is scheduled as a dedicated refactoring task. We prefer to dedicate time to such refactorings when no other refactorings or big features are under development. Otherwise, this leads to a complex integration process.