Saturday, March 19, 2016

OO Bootcamp: Day 3

We kicked off the day with a post-mortem. Why did we struggle so much with designing am elegant solution to the metric conversion problem?

  • We lacked the vocabulary. We didn't know about the quantity pattern.
  • We were not familiar with the language and framework. Pairs that did not know ruby spent half the time googling how to write in ruby. 
  • Not all pairs were familiar with the tools. Not every uses Vim. Even those who used Vim did not use the same key bindings.  
  • We did not have a good sense of code smell so we spent more time implementing crappy designs that we should. 
What did we learn?

1. Don't just pass around strings and other primitive data.

Having random primitive data floating around is a clear indication of encapsulation violation. They're raw data - who's using them? Who's responsible for them? Having a number 1 floating around in your system without it being represented as a symbol anywhere or a Boolean that just floats around in and out of objects indicates that it has meaning and that it's part of a behavior that may change over time. Isolate it in a single entity so that it doesn't fly all over the place.

2. Don't continue on a design you think is shaky.

If you do not have a solid base, things just get worse - much worse. If the design is bad, create a new design and refactor so that the next task is easier. 

3. Don't bother creating a new class if it has no behavior.

Someone created an NoArithmeticException class and it had no special behavior (like telling us how to resolve the error). Why be a class? Just use a built in one! Sometimes even if it makes sense conceptually, the code you'll end up writing may not justify it. If you do it too early you may also not really understand what the base needs to have as you haven't seen enough of the differences yet. Another example is the rectangle and square. Why create a new square class? There's no special behavior. It's just a special rectangle.

4. Stop writing "create" in the procedure name if it's returning an object.

The absence of create should imply that something is being created and returned. We use create_builder because it actually didn't return anything and only created new instances. Just call a.quantity versus a.create_quantity

5. Minimize branches of logic in code.

More logic branching the more complex the software because more paths means more cases to test and eventually if there are lots of path it grows exponentially! For example if A has 10 cases and B has 10. A passes B data. Well, for each type of input there are 10 possible paths. The measure of this complexity is commonly known as the McCave Cyclomatic Complexity which measures the number of possible paths through a programs source code.

One technique to avoid creating too many logical branches is to put your guard clauses up top and avoid else statements. Why? Because else statements are signs of unique behavior. Move them to a different place to reduce the complexity in the current object.

6. Only use inheritance under these two conditions

Humans are great at seeing inheritance everywhere. We look at the code and our first instinct is to make some is-a relationship . Here's a test to help you guard against that intuition which is often wrong:

1. You're using almost all the code in the superclass and it has its own specialized classes (otherwise why bother creating it at all). No need to rewrite over and over. 
2. The grand mother test. Be able to explain to grandma why X is a type of Y. For example, saying that a stack of poker cards is a type of array makes NO sense. 

7. Don't spend too much time upfront on design.

You can create really elaborate models during the design process that result in unnecessary code. That's why we keep design short because we know it's inherently flawed (combined with our tendency to jump to inheritance). . 

Polymorphism Exercise

We all went outside and were told we could be asked one question "are you better than the person next to you (right / left?) and were told what to say based on some criteria of better (first it was month of year and then it was number of show lace holes on one side of our shoe). Then people would ask us these questions  to sort us.

How did this demonstrate polymorphism in action?

We were all different people with different data. However, we had the same interface (same question you could ask all of us). The sorter then interacted with that interface and was able to sort us accordingly. This is the key of polymorphism - where we have different objects that conform to a common interface so that they could be use interchangeably / treated the same / interacted the same way by other objects. One useful concrete example: a sort object that can sort any object as long as they have X, Y methods. In Java, this is implemented through the Comparable object.

Same interface, different underlying forms.

No comments:

Post a Comment