During my professional career, I’ve seen many technical solutions. They fall into few categories:

  1. "Stone bricks" - they do what they have to in a crude and the simplest possible way, they are not re-usable in any case and no-one bothers a lot about their maintainability. Such solutions are typical outcomes of “focus-on-your-current-goal” projects. They may work smoothly, but they bring a technical debt and it’s hard to enhance them with additional functionality (usually)
  2. "Large Hadron Colliders" - “overtechnicized”, complicated monstrosities that happen usually when someone had too many ideas that:
    • didn’t apply to current scenario
    • had unrealistic assumptions
    • were not understood / not respected by the team
    • were not executed correctly
    • or simply didn’t make sense
  3. "Oddlings" - things that work and make sense, but I’d just do them in a different (sometimes completely different) way. And… that’s nothing wrong about that. Projects are not puzzles, there are many proper solutions and usually there’s no perfect one. It’s awesome, because we all can learn from others that way.
  4. "My ones" - :D
Obviously, categories #1 and #3 are the most often seen ones, but I’ve recently encountered a typical #2 and I’d like to elaborate a bit about that particular case. Purpose is purely educational. I won’t go through the details as I restrict myself here to enumerating some general principles that should be followed to avoid #2 mistakes.

  1. Every element of application architecture should have a reason of its existence - using cool programming language features is not enough

  2. Proven and widely accepted principles / rules are awesome, but every such principle has some conditions it has to meet to be applied (for instance, use DTO to reduce coupling between applications, but client that calls all the CRUD ops on corresponding server can’t be decoupled by using DTO).

  3. Don’t make your application architecture seriously impact efficiency of programmers’ work. If they have to create 5 different methods to do what they usually do with 1, start being skeptical.

  4. If you’re enhancing the framework with something you want everyone to use, you have two solutions: either make application require that enhancement (lack will be reported during compilation or automated tests) or make development tools doing it automatically, without programmer’s interaction. Just asking developer to remember about something won’t work (especially if enhancement is annoying to use).

  5. Elements of application architecture have to be easily navigable / browsable / readable and “mapable” on design documents.

  6. Make sure that functional domain can be divided between programmers in a way they don’t interfere with each other’s work. Ownership is the key - ALWAYS!

  7. If you’re creating something up-front (something that is not needed right now, but plays some role in a scaffold you’re preparing), make sure you really know what you’re doing.

  8. If you’ve prepared a carefully designed scaffold that really makes sense, make sure that you’re able to prevent it from breaking but non-intentional (and sometimes mindless) programmer actions of your team mates (it’s so easy to add additional references… or reading data directly, bypassing your masterpiece of DAL).

  9. ALWAYS. VALIDATE. YOUR. SOLUTION. WITH. SOMEONE. ELSE. PERIOD.