Software Is Hard but Simple

There are many approaches to building software such as test first, domain first, database first, event sourcing first, and use case first. On top of that, there are different software patterns such as Ports and Adapters, Onion, Hexagon, Active Record, Transaction Script, 3 or N Tiers, Domain Models, CQRS, MVC, Event Sourcing, Microservices, Monoliths, and a combination of them. These all describe the strategic design while there are many others that talk about tactics. Besides, well-known coding patterns patterns (Singleton, Bidge, Factory, Builder, and so on), that category also includes OOP, SOLID, and other named principals such as "fail fast", KISS, DRY, YAGNI, Composition Over Inheritance, the Law of Demeter, etc.

These are all good for theorizing, training your intelligence, passing exams, and showing off with coworkers. However, the usefulness of that knowledge is pretty limited when it comes to small or medium-sized projects with a couple of devs. The enterprise world is a much better fit for all those architectural guidelines. And to be honest it is hard to reconcile them even there as they often advise following contradicting approaches, leading to unavoidable analysis paralyses or poor code. Code that is hard to work with, to say the least. That becomes so confusing that even experienced senior developers get puzzled and make suboptimal decisions.

All those thick classical books and articles still leave simple daily questions unanswered. Here are some that sound pretty naïve.

  • Where to do the validation? Is that in this class or the one that contains it? How should we react to the result of validation? Should we throw or return a success flag with an error message? What about Debug.Assert checks? Should we repeat similar validation on every level of a call stack or use DRY and put it in the lower-level method?

  • Should we intercept exceptions, where, and how?

  • Is it ok to create an object that is not valid till we call a couple of initializing methods or set a couple of properties?

  • Do we check all or some method parameters? How should we react to invalid parameters? Should we try to fix invalid input or throw an exception? Should the exception contain as many details as it can, or just give a brief and broad description? Where do we catch exceptions?

  • Is it ok to copy and paste logic if it is similar but different or should we always go DRY?

  • How many lines are ok to be in a method?

  • Can we return null here or there or should we never return null and rather use a null object pattern?

  • There are multiple ways to organize a diagram of classes for a given problem. What diagram is better? How to organize a solution in Visual Studio?

I am not going to say that I have a single answer to these questions as the real answer is "it depends". But I come to writing code from a different angle and that lets me answer those questions naturally. That angle is a manifestation of broader ideas related to harmony, entropy, stability, probability, degree of freedom, human perception, and philosophy that are the essence of many interesting productivity metrics in code and even in your life.

Stay tuned!

2
Subscribe to my newsletter

Read articles from Dmitry Dezuk (Dezhurnyuk) directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dmitry Dezuk (Dezhurnyuk)
Dmitry Dezuk (Dezhurnyuk)

Senior Software Developer with over 10 years of performance-focused .NET development experience. I assist developers in solving architectural challenges and simplifying complex software projects. Writing as Dmitry Dezuk to share everyday productivity tips for developing faster and more reliable software.