Test-Driven Development
Failure vs Fault vs Error |
|
Failure |
Observable incorrect behavior, ex. a+b vs a*b |
|
Fault (bug): |
Related to the code. Failure IFF fault |
|
Error |
Cause of a fault. Usually human error (conceptual, typo, etc.) |
Verification |
Testing (test cases), Static Verification (all possible inputs), Inspection/review/walkthrough, Formal proof |
Granularity: |
Unit Testing -> Integration Testing -> System testing -> Acceptance testing -> Regression testing |
within org |
Developers testing -> Alpha testing |
outside org: Beta testing -> Product release |
what is tdd |
Write tests -> write functional code -> refactor |
"Make it Fail, Make it Work, Make it Better" |
Why TDD |
Provides incremental specification, avoid regression errors |
Structure of tests |
Set fixture, invoke, check, cleanup |
Teamwork Considerations
People are most important asset |
Critical factors in people management |
Consistency, respect, inclusion |
Factors influencing team working |
Group composition, Group cohesiveness, Group communications, Group organization |
|
Group composition |
Task-oriented, self-oriented, interaction-oriented |
Hitchhiker: |
Take credit for team's work w/o contributing |
Couch potato |
Willing to work, but drag their feet |
Absorbing leads to couch potatoes / hitchhikers |
- Mirroring reflects consequences onto hitchhikers |
Sequence Robustness
GUI prototype -> Code |
Dynamic |
Static |
|
Use Case Model -> Robustness diagram -> Sequence Diagram |
Domain Model -> Class Diagram |
Robustness diagrams bridge the "what/how" gap |
Notation |
|
Boundary Class |
a user interface or API class to external system |
|
Entity Class |
a class from the domain model |
|
Controller Class |
a class representing business logic or logical software function |
Valid relationships |
Nouns<->Verbs, Verbs<->Verbs |
Nouns!->nouns |
|
valid ex: Actor->Boundary, Boundary<->Controller, entity->controller |
|
invalid ex: actor->controller/entity, boundary->entity, entity<->entity, boundary<->boundary |
Robustness analysis guidelines: |
|
Make a boundary object for each screen & name them well |
|
Usually not real controller objects, but rather logical software functions |
|
Direction of arrows not important |
|
Boundary/entity classes -> object instances, controllers -> messages |
Sequence Diagrams |
|
SD shows how objects within system interact |
SSD shows how actors interact w system |
Design Class Diagrams
Domain model shows real-world concepts, DCD shows software entities |
Class attributes |
|
Full format |
visibility name : type multiplicity = default {property-string} |
|
Visibility marks |
+ (public), - (private), # (protected) |
|
Attributes assumed private if no visibility is given |
|
Operations assumed public if no visibility is given |
Attribution text vs association line |
|
[IMAGE HERE] |
|
Guideline |
Use the attribute text notation for data type objects and the association line notation for others |
Two ways to show collection attributes |
|
[IMAGE HERE] |
Note symbol: can represent UML note or comment, UML constraint, or Method body |
Operations and Methods: |
|
Operation syntax, UML1: |
visibility name (parameter-list) : return-type = default {property-string} |
|
Operations are usually assumed public if no visibility is shown |
|
Operations to access attributes are often excluded |
UML keywords: |
|
«actor»: |
classifier is an actor, ex: in class diagram, above classifier name |
|
«interface» |
classifier is an interface, ex: in class diagram, above classifier name |
|
{abstract} |
abstract element; can't be instantiated, ex: in class diagrams, after classifier name or operation name |
|
{ordered} |
a set of objects have some imposed order, ex: in class diagrams, at an association end |
Dependency: |
|
[IMAGE HERE] |
|
dependency labels are optional |
ex: <<call>> and <<create>> |
Interfaces, Inheritance, Abstract class, Composition, Aggregation |
|
[IMAGE HERE] |
|
Aggregation |
“has-part” association relationship, exists w/o parent |
|
Composition |
whole-part association relationship, needs parent to exist |
Constraints (3 ways) |
|
[IMAGE HERE] |
Utility class |
|
[CODE HERE] |
|
|
Mapping designs to code
Class-Responsibility-Collaboration (CRC) |
Brainstorming tool used in OOD. CRC cards are usually created from index cards. |
CRUFT |
useless, redundant, or poorly written code |
Don’t Repeat Yourself (DRY) |
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system |
Separation of concerns (SOC) |
|
Design principle for separating a computer |
|
Concern is a set of information that affects the code of a computer program |
You Aren’t Gonna Need It (YAGNI) |
|
A programmer should not add functionality until deemed necessary |
|
"do the simplest thing that could possibly work” |
|
Must be used in combination with several other practices, such as continuous refactoring, unit testing and continuous integration |
Collection Classes: |
One-to-many relationships are common. |
E.g., a Sale must maintain visibility to a group of many SalesLineItem instances |
Object visibility
Visibility |
the ability of one object to see or have reference to another |
Attribute visibility: B is an attribute of A |
|
Relatively permanent visibility |
|
Common form of visibility in OO systems |
Parameter visibility: B is a parameter of a method in A |
|
Relatively temporary visibility |
|
Common to transform parameter visibility into attribute visibility |
Local visibility: B is a (non-parameter) local object in a method of A |
|
Relatively temporary visibility |
|
Two methods: |
- Create a new local instance and assign it to a local variable. |
|
|
- Assign the returning object from a method invocation to a local variable. |
Global visibility: B is globally visible |
|
Preferred method to achieve global visibility is to use the Singleton pattern. |
Code smells
code smell |
quick-to-spot surface indication that something is wrong with your code |
usually found during examining & refactoring |
usually caused by rushed design and a disregard for technical debt |
|
technical debt |
the amount of work you create when you try to save time upfront |
|
right way vs fast way |
Types |
|
Bloaters |
long method, large class, long parameter list (>=3,4), data clumps (ex: RGB always together) |
|
Object-Orientation Abusers |
Switch statements, Refused Bequest (inherit methods but unused or redefined) |
|
Change Preventers |
|
|
Divergent Change (many changes to single class from copy-paste) |
|
|
Shotgun surgery (many small changes to many classes from too much coupling, too little cohesion) |
|
Dispensables |
Lazy class (doesn't do enough), Data class (only fields + getters/setters), Duplicated code |
|
Couplers |
|
|
Feature envy |
A method that seems more interested in a class other than the one it is in |
|
|
Inappropriate intimacy |
Classes know too much about each other's private parts (tightly coupled) |
|
|
Middle man: |
class performs one action delegating work to other class |
Responsibility-driven design
responsibility |
Obligation to perform a task or know information |
Behavior (doing) vs data (knowing) |
Methods vs responsibilities |
methods fulfill responsibilities |
|
Responsibilities are implemented by means of methods that either act alone or collaborate with other methods and objects |
|
|
GRASP: [spell out]
Who is responsible for creating a new instance of a class? |
|
Rules: Assign class B to create class A if: |
|
|
B contains or aggregates A |
|
|
B records A |
|
|
B closely uses A |
|
|
B has the initializing data for A (B is an Expert with respect to creating A) |
|
If >1 option, prefer aggregation |
1. Creator -> Low coupling: |
|
Guideline 1 |
A composite object is an excellent candidate to make its parts |
|
Guideline 2 |
Look at the class that has the initializing data |
|
|
E.g., a Payment instance must be initialized with the Sale total. Hence, Sale is a candidate creator of Payment |
|
Guideline 3 |
In case of complex rules consider delegation of creation to a helper class |
2. Information Expert -> Low coupling, high cohesion, reduce feature envy |
|
Assign a responsibility to the class that has the information necessary to fulfill the responsibility |
|
Many “partial” information experts may collaborate in a task |
3. Low Coupling |
Assign responsibilities so that coupling remains as low as possible. |
|
High to low: |
|
|
***Content coupling: one class modifies another (branch into middle of routine, modifies code) |
|
|
**Common coupling: share common (global) data |
|
|
**Control coupling: use a method parameter (by passing some kind of flag) to control a different method |
|
|
Stamp/Data coupling: passing complex data or structures between modules(& use primitives when possible) |
|
|
Uncoupled: no relationship |
|
|
*** DO NOT DO THIS!!! |
|
|
** TRY HARD NOT TO DO THIS! |
|
Common forms of coupling: |
|
|
TypeX has an attribute that refers to TypeY |
|
|
TypeX calls on services of TypeY |
|
|
TypeX has a method that refers to TypeY |
|
|
TypeX is a subclass of TypeY |
|
|
TypeY is an interface and TypeX implements it |
4. Controller |
|
UI objects should not have responsibility for fulfilling system events |
|
Delegates work to other objects & coordinate / control the activity |
|
Assign responsibility to a class that: |
|
|
Represents the overall System ( Façade Controller ) |
|
|
Represents a Use Case scenario where the event occurs (<usecase name>Handler, <ucn>Coordinator, <ucn>Session) |
5. High Cohesion: Objects should not do many unrelated things |
|
High to low |
|
|
***Coincidental: unrelated functions |
|
|
Logical: multiple logic sections |
|
|
Temporal: related by phases of an operation |
|
|
Procedural: required ordering of tasks (addIngredients, mix, bake) |
|
|
Communicational: operates on same data set |
|
|
Functional: all essential elements for a single function are in same module (takeOff, fly, land) |
|
|
*** DO NOT DO THIS UNLESS UNAVOIDABLE!! |
Refactoring: |
|
Goal: Keep program readable, understandable, and maintainable |
|
Preserve behavior by using tests |
Ex: rename, extract method, move method, replace temp w query |
SOLID: [spell out]
S: Single Responsibility Principle |
|
Each class should have a single overriding responsibility (High Cohesion) -> many small classes > one big class |
|
Each class has one reason why it should change |
O: Open/Closed Principle |
|
Objects are open for extension but closed for modification |
|
Extension via inheritance, polymorphism |
L: Liskov Substitution Principle |
|
Subclasses should be substitutable for their base classes |
|
class that implements an interface must be able to substitute any reference throughout the code that implements the same interface |
I: Interface Segregation Principle |
|
Use several small interfaces vs one larger multipurpose one |
|
Don’t make clients depend on interfaces they don’t use (Athlete -> SwimmingAthlete, JumpingAthlete) |
D: Dependency Inversion Principle |
|
High-level modules should not depend on low-level modules. Both should depend on abstractions. |
|
Abstractions should not depend on details. Details should depend on abstractions (writeJava; writeJavaScript -> develop() calls writeJava, writeJavaScript) |
ISP vs LSP |
ISP: parent <-> client |
LSP: parent <-> child |
|