Observations on design pattern use in Java vs. C#
Steve Yegge's OOP version of the proverb "for the lack of a nail, the battle was lost"

Observations on design pattern use in Java vs. C#

I'm fond of saying that most problems in software engineering are due to one thing trying to do two or more things, or two or more things trying to do the same thing (this could be true of functions, classes or even human engineers).

Even though design patterns in programming languages such as Java and C# are meant to discourage this tendency, my early experiences with Java (circa 2002 - 2006) managed to put me off design patterns for a long time.

At the height of popularity of OOP/GoF design patterns, you had to wade through layers of Factory, Adapter, Mediator, Command and other patterns to find the one function call that actually did the work. If you want to read a more brutal takedown of that trend, you might want to read Steve Yegge's famous rant, Execution in the Kingdom of Nouns.

In that era, this is (roughly) how you would read a file in Java (code from OpenAI GPT):

Article content

Here's how you'd do it (again, roughly) in C:

Article content

So naturally, I stuck with languages such as C++, JavaScript, Python and Golang for most of my career -- all languages that were not militant about OOP, and allowed you to write fairly functional code.

But recently, I've been working on some large, enterprise level C# code bases, and I'm finding that perhaps the .NET world has, at some point in the past few years, struck a reasonable balance between OOP and functional programming.

I've found the common pattern of Controllers, DTOs, Models, Repositories, Services and Proxies can make very large code bases consistent, readable and therefore easier to modify. Without going too far, this pattern manages to solve the problem of "one thing trying to do two or more things", or at the risk of attracting architecture astronauts, "separation of concerns": Models represent data at rest, Repositories perform CRUD operations on said data, Services provide business logic on top of data, Proxies provide access to external services, Controllers handle requests, and data is passed between these different constructs using DTOs. For example, if you want to know where products are fetched from a third party API, you know the code will be found in only one place: ProductProxy; if you want to know where it is updated in the database, you know it will always be in the ProductRepository etc.


Article content
Source:

I'm still not sold on Mediators and Commands, and I probably would not replicate the above patterns in JavaScript or Golang, but at least in the context of .NET Web APIs, they seem to work adequately. Thoughts on Clean Architecture, I will keep for another day (because for me, "architecture" and "how code is organized" are two different things).

I would actually say the the common pattern you mentioned that was a virtue in .NET can be used, as is, in Java as well. In fact, in my humble opinion, I would go as far as to say a framework such as spring is comparatively much simpler compared to modern .NET in following that pattern. Which makes you wonder if Java’s “complexity” is a fault of the language or the architect behind that specific implementation.

Like
Reply

This kind of ecosystem-specific architectural evaluation is refreshing. Looking forward to your thoughts on Clean Architecture, particularly given your intriguing distinction between architecture and code organization patterns. That's a perspective worth exploring deeper.

To view or add a comment, sign in

More articles by Hasitha Liyanage

  • "The machines are fine. I'm worried about us."

    As I draft the LLM usage policy for my engineering team, I'm once again reminded of an Asimov story I read as a…

    6 Comments
  • Managing hostility at work

    Judging by the news and social media, the world seems to be becoming an increasingly angry and intolerant place…

    3 Comments
  • A day in the life of an HFT developer, two decades ago

    I have my early background as a high frequency trading systems (HFT) developer to thank for a technical skillset that…

    21 Comments
  • An introduction to philosophy for tech professionals

    (This is a somewhat experimental post. If well received, I may do more of it.

    4 Comments
  • How to do a deep code review

    The idea that code should generally be reviewed in the same order the runtime executes it (and not in the order it…

    17 Comments
  • A case for more self-managed developers

    There’s a bit of a paradox in developers not wanting to deal with chores outside their core responsibility of coding…

    6 Comments
  • Bottom-up vs. top-down tech design

    Nearly 25 years ago, when I was an intern at a capital markets trading systems company (later acquired by the London…

    3 Comments
  • How to do user story level tech designs

    In this article, we try to find a practical middle ground between the two extremes of big design up front (BDUF) and no…

    3 Comments
  • Vertical slicing - a practical example

    In the previous article, we discussed developers' natural tendency to break down tasks horizontally and execute…

  • Why you should vertically slice your stories (and how to do it)

    Horizontal slicing of stories Typically, when you ask an engineering team to plan out the development tasks for a new…

    6 Comments

Others also viewed

Explore content categories