Check out a free preview of the full Enterprise Architecture Patterns course

The "Separation of Concerns Q&A" Lesson is part of the full, Enterprise Architecture Patterns course featured in this preview video. Here's what you'd learn in this lesson:

Lukas answers a student question about how far a developer should go when splitting up logic and how to determine which methods to test.


Transcript from the "Separation of Concerns Q&A" Lesson

>> I'm curious, is there a point where you can start breaking up your logic too much? Like is there you can go too far into kind of making smaller and smaller functions and methods?
>> The answer is absolutely. And where that threshold is, where that limit is, is really dependent on the context of, I would say, your comfort level as a programmer, more importantly, your team and your organization's comfort level.

And so I think if you're working on a team, that you need to figure out where the level of abstraction is and where that sweet spot is, the problem that you run into is that, and for me, this is kind of threshold, for me, is that I try to avoid coupling at all costs.

And so, when you look at this code here, you have a bunch of logic that's tightly coupled to the surrounding function block. And so I'm looking at this I'm like, this is a really tightly coupled piece of code. And so I tried to refactor to reduce coupling as much as possible.

I then tried to move my code in a way to increase cohesion. And so, cohesion is really there's a couple of different versions of this. And depending on what you're doing, you may choose to organize it in such a way that you can have like type cohesion or functional cohesion.

But typically, generally, what I tried to do is, I try to have, at least, feature level cohesion, where something that specifically has to do with a feature is kind of grouped together. So, if I'm writing a component that the spec is there that the things for that, the visual presentation of that component is together.

So, I try to, typically, go for feature cohesion. And then from there, I go for functionality cohesion of, I take all my state management and I extract that into a lib. And then from there I then organized by feature, typically. And so, by having things in a logical place, that it makes it easier to find, but you can spread things out so much that it doesn't make sense anymore.

In the sense of, let me give you two examples. So there's this show on Netflix called The Home Edit, and, it's pretty good, except, they talk about, organizing a bunch of different things. And I started thinking about this in terms of programming, that, it would be very, very fast, for you to take all your laundry out of the dryer, and throw it in a basket.

The upfront cost of doing that is zero, pretty much it's just like poop. But then now when you have to go and find an outfit, because everything is coupled to that laundry basket. It's very very hard to navigate. So, this is when I think of course grade code, it's like all your laundry in a basket.

So, a reasonable approach would be let's separate this out, and put our pants in a drawer, our shirts in a drawer, our socks in a drawer, etc. And then, you might even go as far as to say, I'm going to take and separate my casual pants from my dress pants.

My workout clothes might go in the drawer, so that's an appropriate level of cohesion. Wouldn't make sense to separate your wardrobe into outfits and have a drawer for every single outfit. That would be crazy. I mean, maybe, I don't know? If you're Kanye West, possibly. Or saying, I'm gonna put all my black t shirts in a drawer and all my red t shirts in a drawer, it doesn't make a lot of sense.

And so, another thing that they talk about is organize your colors by books. Or books by colors, your books by color. So if you look at the show, it's like, here's all my red books. Here's all my blue books. Here's all my white books. Well, by color, visually, that's one way to do it.

But, for me, I might have MySQL book next to my closure book, just cuz they're blue and that makes no sense. And so, it's also choosing the parameters in which you achieve cohesion in a way that helps you reduce mental complexity. That is the litmus test. Is this helping me parse this model even better, or is it making it efficient?

If not, and you find that you're fighting against your abstractions, then you might need to revisit it and desimplify it.
>> In the code example, with testing, should I test those small functions? Is that direct enough, or should I also test the function with the switch statements?
>> You test them both, ideally.

That when you run your tests, and you run your code coverage is that there's a certain threshold that you should be aiming for, but you can absolutely test your air traffic control functions, and that actually leads perfectly into the challenge. So, we'll see that in a moment. If you have multiple services in your application, does it make sense to have a single instance of those at the top level of the application and then make them available via dependency injection?

And I believe that you should. As a general rule of thumb, for instance, in Angular, you can override the dependency injector at any point in your component nodes. I've never had to do that. The only time I've ever had to override the injectors, when I'm writing tests. And so, the question or the heuristic there that you have to ask yourself is, is there a reason why I would need more than one instance of this thing, to perform this function within this application?

And there are some cases where you might have something that you need to instantiate for, imagine that you have a meeting room and then you have attendees in there. Well, you wouldn't wanna share the same meeting room for all the attendees. And so, from a modeling standpoint, you want to start to split that out.

But from a, I would say a service level that's managing all of that, typically, you only need one service to manage that application. So, I would say it will be very, very rare that you'll ever need a very common service, to have more than one instance. I would recommend keeping it at the top level, and then making it available via dependency injection.

And so, typically, what you have to identify is, what is the shared commonality or the functionality than all of the interested components or parties that they need. And then you place the thing that you're working on in just the level of distraction just above that. And so, this is something we articulated in the previous course, that I really quite like, is that when you understand the level of the interested parties, then that will determine where your implementation goes, which will be at the level just above that.

So if you have two components that are inside of a single app, you might put that in the app. But if you have two components in two separate apps, you might move whatever you're working on into a lib, so that it can be shared across multiple apps. If you have more than one project that needs that functionality, well, then you might consider publishing it as an NPM package, so that all the projects can use it.

Which is where you have component libraries. And so find out where the interested parties are, and then just go one abstraction level up and typically that's where it's going to be. In the case of Angular applications, I would say just have one service at the top level that manages everything.

And by the previous course, I mean production Angular, which I highly recommend you checking out.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now