Podcast: Play in new window | Download
Subscribe: Apple Podcasts | Spotify | TuneIn | RSS
Allen brings the dad jokes, Michael unplugs, and Joe gets a second wind as we discuss the anti-patterns found in object oriented programming.
Having difficulty reading these show notes via your podcast player? You can find this episode’s full show notes at https://www.codingblocks.net/episode67.
Sponsors
- Linode – Use code “CODINGBLOCKS17” for $20 towards hosting (up to four months free!)
Survey says …
During Michael’s favorite portion of the show, this episode we ask: How many different podcasts do you subscribe to?
News
- Super thanks for the latest reviews:
- iTunes: AdamCurtis, Alofanzo, StefanAge, Woody11309, Sotmo
- Stitcher: 0x00f3
- Secure your ElasticSearch servers…AWS being targeted – https://www.bleepingcomputer.com/news/security/over-4-000-elasticsearch-servers-found-hosting-pos-malware-files/
- iPhone X is here! Well, not quite yet. But kinda.
- Thanks to our amazing audience, we’ve reached another milestone: 2 million downloads!
Object Oriented Mistakes
Anemic domain model
- The use of the domain model without any business logic.
- The domain model’s objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places). Martin Fowler considers this to be an anti-pattern, but some disagree that it is always an anti-pattern.
- Anemic domain models are contrary to the whole notion of object oriented design – data and business logic should be combined
- You’ll typically see these things as standalone classes with other classes operating on them – aka a business layer or as Martin Fowler referred to as “transaction scripts”
Benefits
- Clear separation between logic and data
- Works well for simple applications
- Allows for stateless logic – much easier to scale
- Removes the need for a complex db / stateful mapping layer
- Easier to use with dependency injection as constructors are simpler
Drawbacks
- Logic cannot be implemented in an OO way
- Violation of encapsulation and information hiding principles
- Requires an outside class or layer to perform business logic
- The side effect is the domain object cannot guarantee a “good” state at any point in time – it’s a dumb object
- Typically needs some sort of service layer when being used between different applications
- Makes the model less expressive
BaseBean
- Inheriting functionality from a utility class rather than delegating to it
- It’s not THAT you’re inheriting, it’s that you’re inheriting for the wrong reasons
- You’re creating a game, and it has a car class with properties like “weight” and “topSpeed” and methods like “accelerate”. Later when you go to create a bullet class, you see that car already has the stuff you need – so you make your bullet inherit from your car…
- Why is this bad? It’s confusing, and can cause problems later when new features are added (seatbelts) or when you try to logically treat things the same. GameObjects.Get<Car>().Accelerate()
- Even worse, sometimes when you inherit you don’t need everything in that class…
- How do you know if you’re walking down this path? Does inheriting feel “wrong”? Throwing NotImplimentedException?
Call super
- https://en.wikipedia.org/wiki/Call_super
- Requiring subclasses to call a superclass’s overridden method
- How it works:
- Base class has some cool method.
- But not cool enough, so you need to override it in your subclass.
- However, doing so *requires* that you call the super’s version.
- It is this _requirement_ that is the anti-pattern
- So how does this happen?
- The base class may be assuming that a child class will augment some functionality or set some state that it relies on.
- The base class may need to perform some setup operations for the class/framework to function correctly
- Maybe these tasks are private?
“Whenever you have to remember to do something every time, that’s a sign of a bad API.”
Martin Fowler – https://www.martinfowler.com/bliki/CallSuper.html
- How do we fix this?
- Template methods to the rescue!
- https://en.wikipedia.org/wiki/Template_method_pattern
- Discussed during episode 16
- Template methods to the rescue!
Circle-ellipse / square-rectangle problem
- Subtyping variable-types on the basis of value-subtypes
- Violates the Liskov Substitution principle…
- A subtype of a supertype should be substitutable for the super type.
- Super Type Fruit, Sub Type Orange. The Orange should be able to be used anywhere type Fruit is used – ie you could substitute the Orange for Fruit
- A subtype of a supertype should be substitutable for the super type.
So where’s the problem?
- Super type Ellipse
- stretchX and stretchY
- Sub type Circle
- stretchX and stretchY would change a circle into an ellipse – changing the meaning of an object
Switch the two?
- Super type Circle
- Properties of radius and diameter
- Sub type Ellipse
- Cannot have meaningful properties of radius and diameter
So what’s a developer / engineer / programmer to do?
- Change the model
- Return boolean indicating success of the call
- Throw an exception for an invalid method on the subtype
- Return the resulting value after the method call
- Allow for a weaker contract (stretchX and stretchY would simply change both the x and y values for a circle)
- Modify the subtype to the super type on the change – could be very dangerous – expect some runtime exceptions!
- Make everything immutable – calling the method returns a new object – similar to the problem above with type changes
- Factor out modifiers – take anything that could mutate the ellipse and put it into an MutableEllipse class…yuck
- Put preconditions on modifiers – Ellipse and Circle would then have a property called IsStretchable and upon calling stretch that would be called (similar to exception)
- Factor out common functionality into an abstract class – now there is no inheritance
- Drop inheritance relationships – Common operations factored out into interfaces that each class would then implement independently
- Just merge the circle class into the ellipse – basically get rid of the circle class unless you have a specific need for it
- Inverse inheritance – mutators are pushed up from the sub-class to the super-class
- Use a different language or feature of a language
- Using a language like LISP, you can change the class type without losing the object’s identity
- Use a different paradigm – challenge the entire problem
- Interesting analogy – Prisoner :: Person –> Person.walkNorth — Prisoner doesn’t have the freedom to do so
- Rather than Circle and Ellipse, what about OneDiameterShape and TwoDiameterShape
Circular dependency
- Introducing unnecessary direct or indirect mutual dependencies between objects or software modules
- DLL hell example, Can’t upgrade A because it depends on B, which depends on C, which depends on A….
- How can you tell? Can be tough, static analysis, or when you hit that first problem….
- Can sometimes cause memory leak problems because the GC can’t cleanup
- Often indicitive of flow/hierarchy problems where information would preferably flow in one direction (down)
- Somewhat common and encouraged in functional programming?
- What to do about it? Run static analysis tools like NDepend, beware of “reaching out”, and utilize patterns like IoC or Observers that cut concrete ties
Constant interface
- Using interfaces to define constants
- This is a Java thing.
- Why would you be tempted to do this?
- Maybe you’re thinking of composition over inheritance?
- i.e. I need some constants but I can only inherit from one class. But I can implement many interfaces. Maybe?
- You want a way to conveniently share a value across your app/namespace
- Maybe you’re thinking of composition over inheritance?
- Why is this bad?
- A constant is an implemention detail. Now you’re implemation is leaking out of your class.
- Think about all of the uses and subclasses of your this class that expose this constant.
- Users don’t care about your constants
- It’s part of the interface. Meaning it ‘s part of the contract. For a constant.
- But the class implementing the constant could provide it’s own constant of the same name but with a different value. Now the “constant” has lost it’s meaning.
- Some of this assumes that your class “implements” this interface.
- In Java, you can make this interface act and seem more like an enum.
- Which would make have a variable/reference to a type of this interface seem odd.
- In Java, you can make this interface act and seem more like an enum.
- A constant is an implemention detail. Now you’re implemation is leaking out of your class.
- What are the alternatives?
- Keep your constants private and part of your class.
- Really need these constants usable across your app? Use enums.
- Don’t want to use an enum? How about a class with public static variables instead.
- https://www.codingblocks.net/programming/what-if-interfaces/
Resources We Like
Tip of the Week
- Make large files from the cmd line like a bearded sysadmin (Stack Overflow)
- How to make and use truly private variables in JavaScript (YouTube)
- TypeScript example – https://www.typescriptlang.org/play/index.html
- Two new brand spanking new podcasts for you to check out: