Results 1 to 40 of 959

Thread: What if there was a NEW vb6

Threaded View

  1. #11
    Super Moderator FunkyDexter's Avatar
    Join Date
    Apr 2005
    Location
    An obscure body in the SK system. The inhabitants call it Earth
    Posts
    7,957

    Re: What if there was a NEW vb6

    I think Jeff's main complaint is that the authors waited until the end of the book to point out the (somewhat obvious) concept of "write simple code, then worry about patterns".
    Yeah, I got that too and if the book was just a recital of how to apply the various patterns followed by a warning at the end I'd agree with him. But one of the great strengths of the book is that it fully describes the problem each pattern is meant to solve before it describes the pattern. The authors spend as much time explaining why and when to implement a pattern as they do explaining how. No doubt, understanding the Why and the When is probably more important than understanding the How.

    I'd also disagree with his statement that patterns equal complexity. Miss-applied patterns equal complexity but correctly applied ones equal simplicity. A really good example is the strategy pattern (which rather also neatly dovetails into the inheritance vs composition debate that we touched on earlier). I'll try and summarise the example from the book because I think it's quite an easy one to follow.

    Imagine you're simulating Ducks. All ducks Quack and Swim in the same way but they look different. So you implement a base class of Duck with an implementation of Quack and Swim and an abstract method for Display. You'd then implement a few derived classes (Mallard and RedHead) which would implement their own Display methods. Voila, you've got a bunch of ducks that swim, quack and fly appropriately without any duplication of code. Inheritance is a wonderful thing.

    Then you implement a Rubber Duck. Rubber Ducks don't quack, they squeak, so you overrode the Quack method from the base class to make a different noise. This seemed like a pretty good solution at the time and kept things nice and simple. Gotta love Kiss programming.

    Then you're asked to implement flight for the ducks. Mallards and RedHeads fly but Rubber Ducks don't. You've now got two obvious choices. You could:-
    1. Implement it in the base class and override it to do nothing in the Rubber class. This is starting to increase the amount of overridden implementation of the Rubber class though (and therefore the coupling from the derived class to the base class).
    2. You could make Fly abstract in the base class and implement it in each derived class - but that means RedHead and Mallard are going to implement exactly the same code so you'll be violating the DRY principle. And you know that the vast majority of ducks are going to want to share that Fly and Quack behaviour so you're going to violate it ALOT.

    Realistically you probably pick option 1 as the simplest.

    Now someone asks you to implement a WoodenDecoy duck which doesn't fly or quack. So now you add another derived class which overrides Quack to do nothing and overrides Fly to do nothing. And you've just violated the DRY principle because a wooden duck and a Rubber duck share the same behaviour for Fly (I.e. they don't) but each has it's own (admittedly empty) implementation.

    So maybe, instead you implement a Flyable and NonFlyable duck class which inherits from Duck and then have all the other ducks inherit from them... except how does that marry up with the Quack method. Some ducks Quack but don't Fly (the newly introduced DecoyDuckWithRealisticQuackAction), some Fly but don't Quack (the newly introduced RemoteControlledFlyingDuckBoat), some Quack and Fly (Mallards and ReadHeads), some don't Quack or Fly (the plain old Decoy) and then you've still got that bloody aggravating Rubber duck which insists on bloody well squeaking... SQUEAKING! Where the hell's that going to fit in. And they ALL still swim. Go on, design an inheritance tree that properly manages this lot. I dare you!

    This is a real world problem (well, sort of, it is if you substitute products or orders or staff for rubber ducks anyway) that most OO programmers have faced at some time or another. The book walks you through this problem in full before it ever gets to offering a solution (which is why I think Jeff's criticisms are invalid) and then offers up the Strategy Pattern as a solution.

    The strategy pattern is a classic example of favouring composition over inheritance. It says, instead of just inheriting behaviours from the base class you should make each behaviour a class in it's own right and then have each instance of duck compose a set of behaviours.

    • Write an iQuackBehaviour interface and then derive Squeak, Quack and DoNotQuack classes from it. Write an iFlyBehaviour interface and derive FlapWings, Glide and DoNotFly classes from it.
    • Give the base duck class an iQuackBehaviour member and an iFlyBehaviour member(in other words, have it compose those behaviours)
    • Change the Quack method on the base class to just call the Quack method of its iQuackBehaviour and the Fly method to call the Fly method of its iFlyBehaviour
    • Now have each derived class set it's own behaviours in the constructors (n.b. to those interested in Inversion of Control you would, of course, make these properties of the derived class rather than setting them in the constructor but that's a different issue, you'd probably implement a factory too) e.g.

    Code:
    Public RubberDuck()
    {
       QuackBehaviour = new SqueakBehaviour();
       FlyBehaviour = new DoNotFlyBehaviour();
    }
    At this point you can remove all implementations of Fly and Quack from the derived classes, they're no longer needed. You still implement Display in each derived class because you decided previously that no two types of duck look the same. And you can still use plain old inheritance for the swim method because all ducks swim and you want to keep things simple (until someone introduces China duck ornament at which point you'll refactor). We've got all the benefits of shared behaviour where we want it and we've got built in flexibility where we need it. Adding new behaviours and new derived duck classes is now a piece of cake and we can do so with confidence that we're not affecting extant duck types and behaviours

    If you tried to design a plain old inheritance tree for this lot it would be hugely complex, prone to breaking and difficult to maintain. The domain added a bunch of complexity but the domain is out of our control. The pattern, far from adding complexity, removed it.


    DuckStrategy.zip
    Edit> I've attached a class lib to demonstrate just how much the strategy pattern can simplify a complex inheritance tree. I'm afraid it's in C# because that's where I'm fluent these days but it shouldn't be beyond the wit of either VB.Net or VB6 programmers to digest it.

    Note that, although this pattern favours composition, it still relies on implementation inheritance for the Fly, Quack and Swim methods. As such it cannot be implemented in VB6.

    I'm sure you can find a way to work around that but I'm willing to bet you won't be able to without either violating the DRY principle or increasing the coupling between the classes. I'm willing to bet I'll see a pretty chunky Case or If statement appearing somewhere.

    VB6 was a great language. It let me knock out relatively shallow LOB business applications for years. But it was designed when OO was in it's infancy and so missed out on a few of the key features that OO really requires. As the apps I was producing grew in both scale and complexity I could not deny that VB6 was starting to fail me, largely because of those OO omissions. I could not take advantage of the work that was being done by others in the field of good software design and, instead, still had to rely on the same old hacks and workarounds which, while they worked, were not producing clean and maintainable code anymore.

    I moved to .Net (and then C#) because they offered better ways of designing my applications and designing (not writing) my code. And no, Olaf, I didn't move before I was ready to understand these concepts. I moved because I already understood them.

    I say again, if VB6 continues to work for you then use it. I do think you're putting yourself at some risk of having the rug pulled from under your feet but that risk does seem to be diminishing as MS continues to offer support for the run time. Familiarity is not cheap, and it's familiarity with VB6 that supports many of you in knocking out and maintaining your apps. That's a pretty compelling reason to stick with it.

    But don't fool yourself that VB6 offers you the same abilities in terms of software engineering and good design that more modern languages do because it doesn't. Those more modern languages have the benefit of over a decades more hindsight than VB6 does.

    VB6 may well be the right choice for many of you. The benefits may well outweigh the costs. But do take some time to understand the costs before you make that choice.


    And one last thing in a post I've definitely allowed to become overly long: There is no such thing as Death By OO, merely Death by Bad OO. If, in the above example, we had continued to try to cram every possible combination of behaviours into our inheritance tree that would have been Bad OO and our application would surely have died from it. But Good OO contained the solution that we needed. Spend some time learning these patterns and all your worries vanish.

    Edit> Hey, Sitten, was that the kind of design discussion you wanted? If so then start up some discussions in threads of your own. A few codebank submissions would be great place to start. I'd love to see more of this sort of stuff being discussed and would happily dive in. I've had half an eye on the template pattern thread but haven't contributed because I've never been aware of Hook as a pattern. I'd have said hooking is a technique used when implementing a Template pattern (amongst other uses) and that's led me to think I might be missing the point.
    Last edited by FunkyDexter; Aug 16th, 2015 at 05:06 AM.
    The best argument against democracy is a five minute conversation with the average voter - Winston Churchill

    Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width