Command Pattern leading to class explosion [closed]
Asked Answered
C

2

7

It seems like whenever I use the Command Pattern, it always leads to a significantly larger number of classes than when I don't use it. This seems pretty natural, given that we're executing chunks of relevant code together in separate classes. It wouldn't bother me as much if I didn't finish with 10 or 12 Command subclasses for what I might consider a small project that would have only used 6 or 7 classes otherwise. Having 19 or so classes for a usual 7 class project seems almost wrong.

Another thing that really bothers me is that testing all of those Command subclasses is a pain. I feel sluggish after I get to the last few commands, as if I'm moving slower and no longer agile.

Does this sound familiar to you? Am I doing it wrong? I just feel that I've lost my agility late in this project, and I really don't know how to continuously implement and test with the speed that I had a few days ago.

Canaliculus answered 5/2, 2011 at 17:43 Comment(0)
U
6

Design patterns are general templates for solving problems in a generic way. The tradeoff is exactly what you are seeing. This happens because you need to customize the generic approach. 12 command classes does not seem like a lot to me, though, personally.

With the command pattern, hopefully the commands are simple (just an execute method, right?) and hence easy to test. Also, they should be testable in isolation, i.e. you should be able to test the commands easily with little or no dependencies.

The benefit you should be seeing are two-fold:

1) You should have seen your specific, complicated approach simplified by using the pattern(s) you chose. i.e. something that was getting ugly quickly should now be more elegant.

2) Your should be going faster, due to the simplified approach and the ease of testing your individual components.

Can you make use other patterns, like composite, and use good OO design to avoid duplicating code (if you are duplicating code...)?

Underset answered 5/2, 2011 at 17:50 Comment(14)
I'm not duplicating code. They're pretty simple execute methods that perform distinct tasks. It was just the large number of classes that bothered me - given I only have about 4 or 5 domain classes.Canaliculus
@mike yeah 12 classes are not a lot. If they are simple, you should be able to test them easily. I also think once the pattern is in place and you get used to it you'll go fasterUnderset
Also, it's not meaningful to test them in isolate. At that layer in my architecture, they're subject to the full set of business rules. That also, is an area that's quite annoying.Canaliculus
@mike you are supposed to test in isolation. You should also test the classes that use the commands tooUnderset
@mike, where specifically are you slowing down? Testing? Implementing the commands? Something else?Underset
Hm. Let me rephrase. I've Unit tested all of the domain classes. My Command classes use those, and I therefore wrote Integration Tests for them. Do you think it would have been better if I only Unit tested the Command classes, and not Integration tested?Canaliculus
Testing is slowing down significantly, I would say.Canaliculus
why is testing slowing down? You should unit test the commands as you write them in the spirit of TDD, and you should also integrate to make sure the logical units the commands encapsulate are correct.Underset
I'm not sure why I didn't Unit test them to be honest. Integration tests are what are taking the longest amount of time. I'm just not sure anymore.Canaliculus
I think it might help to describe what I'm doing. First, I use TDD and write a Unit test for the domain object, if I need one. Then, I again use TDD and add to a Facade, while producing an integration test for the Facade and domain object. Finally, I TDD an Integration test for Command, stretching from the Command, to the Facade, to the domain object. Where did I go wrong in there?Canaliculus
@mike let me ask this: how fast are you going? Are you delivering features on time? things take time to do correctly...if you hadnt used the command pattern, do you think you would be going faster? Is the code cleaner with the command pattern? Software development can be frustrating -- keep with itUnderset
I'm implementing a 2-4 small features a day, putting in 1-4 hours per day. Maybe I just feel that I'm going slow because some of my classmates burned through the assignment without tests. (It's a college SE project, so you understand that it's reasonably small). I think it's just demoralizing to see someone finish so fast - even though I know theirs is riddled with bugs and mine is bullet proof. Your last comment made me feel a lot better, though.Canaliculus
@mike -- ahh a college project. You are going to be a good software developer if you start off now doing it the right way. If your project were ongoing you would see the benefits down the line in terms of maintainability and code simplicity.Underset
@Underset Thanks for the encourage. It really got me over the wall I'd been having for the last 24 hours. I backed up, reverted my non-tested code, planned some more, TDDed and succeeded with another feature. :)Canaliculus
M
4

That doesn't seem like a lot of command classes, but I agree with you that it smells a little if they make up more than 60% of your classes. If the project is complex enough to merit the use of the command pattern, I suspect you'll find some classes begging to be split up. If not, perhaps the command pattern is overkill.

The other answers here have great suggestions for reducing the complexity of your commands, but I favor simplicity where I can find it (ala the bowling game).

Mancuso answered 5/2, 2011 at 18:0 Comment(3)
I'm afraid to drop the Command pattern. It's where I parse text input, match it against regexes, and execute the work. It's a small amount of work, but has meaningful, cohesive functionality. Do you think that merits dropping the pattern?Canaliculus
I think that sounds like a great argument for using the command pattern! I would take a look at the rest of your classes and make sure they all have that same sense of meaningful, cohesive functionality, but it sounds like you're on the right track.Mancuso
I decided to stick with it and finished the project today. Turned out better than I thought yesterday - especially when I stepped back and executed 120 automated tests over those commands. :)Canaliculus

© 2022 - 2024 — McMap. All rights reserved.