//****************************************************************************//
//************ Metrics & Design Patterns - November 20th, 2017 **************//
//**************************************************************************//

- So, last week, we were finishing talking about the ACYCLIC DEPENDENCY PRINCIPLE
    - Let's say that we're programming our application, and as we're working on the "Error" package we realize that we want all errors to display the error in the UI
        - The LAZY way of doing this is to have the "Error" package inherit from the UI; but this means that the "Error" package is depending on the UI package, and vice-versa
        - INSTEAD, we should create a new package ("Error Dialog", or something), and have it use stuff from BOTH "Error" and "UI"
            - That way, the Error/UI packages can't break each other when they're changed!
    - More commonly in student code, we have a package "1" with classes A/B and package "2" with classes "X/Y", and when we want to share functionality between them, we have "A" import "X" and "Y" import "B", or something like this
        - This creates a cyclic dependency!
    - So, to FIX this, we should instead have A/Y use an INTERFACE with the methods we need from the other package
- "Why are cyclic dependencies awful? Well, in Java, they're not too bad since the Java Compiler is smart about how it compiles changes...but in other lagnuages like C/C++, if you have cyclic dependencies, then it means every time ONE package in that cycle is changed, ALL the packages in the cycle have to be re-compiled"

- Versioning...there's a couple ways to do it, but the most common way:
    
        [major update #].[minor update #].[patch #]

        - e.g. "Version 4.6.19"
    - On the whole, versioning isn't too complicated, though; many companies use alternate schemes just for the sake of it, but as long as it works, that's okay

- Stable Dependencies Principle
    - How do we measure the "stability" of a class? Well, first of all...
        - By STABLE, we mean that the class doesn't depend on other classes at all; we can change our other classes as much as we want, and it won't affect the package's functionality
            - If ANY change in our code changes the functionality of the class, then it's 100% unstable
    - To measure the instability numerically (lower is better/more stable):

        Instability = Co / (Co + Ci)

        - Ci = incoming dependencies (other packages that depend on me)
        - Co = outgoing dependencies (other packages I depend on)

- Another "DESIGN METRIC" is "Abstractness" for a package, which we calculate as:

        A = (# of abstract classes in package) / (# concrete classes)

    - Ideally, something that is 100% abstract should have 0% instability, and something that's 100% concrete/unstable should be 0% abstract
        - "Something that's 100% abstract and 100% unstable means that nothing is using that package and it isn't doing anything useful - this is the ZONE OF USELESSNESS"
        - "Something that's 0% abstract and 0% unstable is the ZONE OF PAIN - it means the package is doing EVERYTHING on its own with no abstraction to organize it"

- Other useful design metrics we don't cover in this class: Method complexity, methods per class, lack of cohesion, coupling, ineritance tree depth, Halstead/McCabe measure, etc.

========================
// Design Patterns
========================

- Design patterns are part of a larger scheme we'll call "design expertise", which are common ways of solving problems; this includes:
    - Architectural Styles
    - Frameworks / Class library design
        - "Sadly, we don't have time to go over most of this"
    - Design patterns ( ways of solving common design problem)
        - A good resource for this is a website called BALL OF MUD (or something like that)
    - Language idioms (e.g. avoiding "magic numbers", clean coding practices, language-specific stuff like when to us lambda expressions, etc.)
- e.g. there are 2 reasons we use singletons: it allows global access to a model, and allows us to deal w/ classes we only want one instance of

- So, here, we're going to focus on some common DESIGN PATTERNS:

    - Singleton/Monostate, we already talked about earlier

    - FACTORY pattern
        - Let's say we have an "Encryption" class with a few different kinds of encryption (RSA, DES, BlowFish, etc.); how do we determine which kind of encryption we should use?
            - Well, instead of directly calling methods on Encryption, let's have an "IEncryptFactory" interface with 1 method on it that takes in a key, specifying which type to use; then, we can handle the appropriate logic for that
                - "Factories are one of the few cases where switch statements are perfectly acceptable"
            - Example code for the factory:

                public class EncryptionFactory {
                    public Encryption createEncryption(Key encryptTypeKey) {
                        String algorithm = encryptTypeKey.getAlgorithm();
                        if (algorithm.equals("DES")) {
                            return new DESEncryption(encryptTypeKey);
                        } else if (algorithm.equals("RSA")) {
                            return new RSAEncryption(encryptTypeKey)
                        }
                        throw new Exception("Unknown encryption type specfied");
                    }
                }

        - Now, we might not always need a full class for the factory pattern; in that case, we can just create a static "Factory method" on the class; e.g.:
            
                public class Person {
                    (...)
                    public static makeNewPerson(String line) {
                        (...)   //parse the line and create the appropriate person
                    }
                }

            - This allows more descriptive naming

    - BUILDER pattern
        - This is another pattern that's meant to instantiate a new instance of a class
        - Let's say we're creating a new User, where the name/age are mandatory and their address, email, and location are optional
            - "We don't want to have a bunch of different constructors to handle all the different possible combinations, or to have something arbitrary like setting 'null' for optional parameters"
            - In that case, we'd have a "UserBuilder" class with a bunch of method like this for EACH optional instance variable:

                    public UserBuilder email(String email) {
                        this.email = email;
                        return this;
                    }
                    (...)

            - ...and the mandatory options as part of the constructor:
                    public UserBuilder(String name, int age) { ... }
            - And THEN, finally, we'd have a "build" method like this on the class:

                    public User build() {
                        User u = new User(this.name, this.age);
                        u.setEmail(this.email);
                        (...)
                    }
            - To use this, we'd then say something like:

                    User newUser = UserBuilder("Fred", 19).email("...").build();

                - "This looks like a violation of the Law of Demeter...but again, here it's okay, since it's part of the design pattern and we're ONLY calling stuff within the class."
                    - "This has come up as a test question before: if it ends in 'build', it is NOT a violation of the Law of Demeter"