//****************************************************************************//
//**************** More Design Principles - November 6th, 2017 **************//
//**************************************************************************//

- So, for M12, you'll be doing an individual report on a program's architecture; PLEASE choose an example from "The Architecture of Open-Source Software" (NOTE TO SELF: THEY HAVE THE BATTLE FOR WESNOTH AS AN OPTION!)
    - Once you've found a decent-sized example that you're interested in, you'll follow the report guidelines on T-Square and write a report critiquing the design of the program (good and bad)
        - Exemplary papers will show evidence of having looked at the source code (e.g. on Github), external sources, and a thorough understanding of the design principles we've talked about in class, applied to these systems; "You can still get a low A as long as you've used a few different sources and demonstrate understanding of the design principles"
    - This is due the day we get back from Thanksgiving
---------------------------------------------------------

- So, GRASP principles are well and good, but they're VERY textbook-specific; an interviewer probably wouldn't have heard of them if you named them, even though they're very good principles to follow
- So, let's go over some of the more well-known design principles in software development

- LAW OF DEMETER
    - Basically, we should ALWAYS try to minimize coupling in our program
        - A non-coding example: If an army team is setting up a defensive position and needs to set up a foxhole, a general doesn't tell the colonel to tell a major to tell a captain to tell a seargeant to tell a private to dig the foxhole; INSTEAD, he just says "Colonel, I need a foxhole here", and leaves it up for the colonel to decide how to do that
            - "If you need to call a chain of twelve getters to call the method you need, it's probably a sign you're not following this law"
    - More formally, the law says that objects should ONLY send messages to:
        - Itself (the class is allowed to call its own methods)
        - Objects sent as arguments 
        - Objects created by the class' methods
        - Objects directly accessible via the class' attributes
    - An example of what NOT to do:

        sendMsg(userId, msg) {
            um.findUserId(userId).getConnect().getSocket().send(msg);
        }

        - NOW, this chain of calls is fragile; if we change the "Socket" class into a "Pipe" class, this method call will break, even though it shouldn't have anything to do with the class we're using to send stuff!
    - A better way would to have a "send" method on ALL of these classes, and to instead have a chain of calls like this:
        sendMsg(userId, msg) {
            um.send(userId, msg)
        }
        ...
        send(userId, msg) {
            connection.send(msg);
        }
        ... 
        send(msg) {
            socket.send(msg)
        }
        - This is MUCH less fragile!
    - "Now, sometimes there'll be an API that's designed this way that forces you to have to call methods via the chained-getter way...there's really not much of a way around that, but try to do minimize this kind of stuff as much as possible"

- TELL, DON'T ASK (TDA)
    - We TELL objects what to do instead of asking them about their internal state and then making decisions
    - e.g. if we have an accounting program, our "purchase" class shouldn't just be a container for the data but do nothing else; it should be able to calculate what the total purchase is FOR US, instead of having that logic required in the calling class
        - This way, instead of doing something like:
            public void makePurchase() {
                Purchase pur = getPurchase();
                pur.total = pur.subTotal * (1 - pur.discount);
                (...))
            }
        - We can say just say: "purchase.getTotal();"
    - "If you learn about 'code smells', this is one of them"

- COMMAND QUERY SEPARATION (CQS)
    - This is a bit of a controversial one
    - Basically, this says 

- And finally, the BIG one: SOLID
    - This is a set of 5 principles created by Robert Martin ("Uncle Bob"), and it's HUGELY popular among developers
    - The 5 principles are:
        - SINGLE RESPONSIBILITY PRINCIPLE
            - Every class should have ONE overriding thing that it does (not a single method necessarily, but a single overall goal)
            - Another way of putting it: every class should have ONE reason to change ("Major changes should be isolated from one another, so that a change in one part of the program shouldn't require changes to an unrelated part of the system")
                - e.g. Let's say we have a "CompGeometry" class that let's us calculate the area of shapes, with a "Rectangle" class that has a length/width variable and method for calculating its area
                    - Let's say we THEN add a "DrawShapes" class, and we say "hey, Rectangle already has some information we need to draw it, let's add a "drawRect" method to that class"
                - The PROBLEM with this is that it means our Rectangle now depends on both the "CompGeometry" class and the "DrawShapes" class; if EITHER ONE changes, then we have to update the rectangle class, even though the change 
                    - The solution to this, in this case, would probably be to create a new "DrawRect" class that gets information from our original Rectangle class; that way, the logic for storing information and drawing it is kept separate
        - Open / Closed Principle
        - Liskov Substitution
        - Interface Segregation
        - Dependency Inversion