- Agile Practices
- Individuals and interactions over process and tools
- working well with others, communicating, and interacting is more important than raw programming talent
- tools can be overemphasized, start small until you outgrow it
- Working software over comprehensive documentation
- software without documentation is a disaster, but too much is worse than too little
- maintain a rationale and structure document, but should be short and salient
- the code and team members are best at transferring information
- Martin’s first law of documentation: Produce no documentation unless its need is immediate and significant
- Customer collaboration over contract negotiation
- developers shouldn’t go off on their own and disappear
- successful projects involve customer feedback on a regular and frequent basis
- requirements constantly change, best contracts are those that govern the way teams and customers work together
- Responding to change over following a plan
- ability to respond to change often determines success or failure
- business environments change
- customers change requirements
- long-term planning charts will degrade
- make detailed plans for the next two weeks, keep remaining plans flexible
- Principles
- Our highest priority is to satisfy the customer through early and continuous delivery of valuable software
- Welcome changing requirements, even late in development
- Deliver working software frequently
- business people and developers must daily throughout the project
- build projects around motivated individuals
- the most efficient method of conveying information within a development team is face-to-face
- working software is the primary measure of progress
- agile processes promote sustainable development
- continuous attention to technical excellence and good design enhances agility
- simplicity– the art of maximizing the amount of work not done– is essential
- the best architectures, requirements, and designs emerge from self-organizing teams
- at regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly
- Overview of Extreme Programming
- customer team member
- person or group who defines and prioritizes features
- user stories
- know enough about requirements to make estimates
- specific details likely to change so likely a waste of effort to capture
- short cycles
- XP project delivers working software every two weeks
- Iteration is two weeks made up of a collection stories
- customers do not change iteration once iteration has started
- a release is usually three months of work
- acceptance tests
- details about the user stories are captured in the form of acceptance tests by the customer
- once it passes, added to body of acceptance tests and never allowed to fail again
- pair programming
- all production code is written by a pair of programmers
- pair membership changes at least once a day
- good for increasing the spread of knowledge
- studies show it does not reduce the efficiency, yet significantly reduces the defect rate
- test-driven development
- all production code is written to make a failing unit test pass
- facilitate refactoring
- drives decoupling modules
- continuous integration
- check in code and integrate several times per day
- use non-blocking source control
- sustainable pace
- software projects are a marathon
- the team is not allowed to work overtime, with the only exception being in the last week of a release
- open workspace
- working in a “war room” environment may increase productivity by a factor of two
- the planning game
- the essence of planning is the division of responsibility between business and development
- business people decide how important a feature is
- developers decide how much that feature will cost to implement
- customers choose stories whose costs total up to but do not exceed the budget
- simple design
- an XP team makes their designs as simple and expressive as they can be
- focus on stories that are planned for the current iteration, don’t worry about stories to come
- get first batch of stories working in the simplest way possible
- YAGNI: You Aren’t Going to Need It / only if you have proof or very compelling evidence
- Once and Only Once: don’t tolerate code duplication
- refactoring
- code tends to rot
- frequent refactorings
- keeps code clean, simple and expressive as possible
- metaphor
- The big picture that ties together the whole system together
- if a module’s shape is inconsistent with the metaphor, then you know the module is wrong
- Planning
- initial exploration
- identify all really significant user stories
- stories that are too large should be split
- stories that are too small should be merged
- stories that are split or merged should be reestimated
- release planning
- given a velocity, customer can get an idea of the cost of each story
- what to prioritize given cost is a business decision
- iteration planning
- typically two weeks
- order of the stories within an iteration is a technical decision
- the iteration ends on the specified date, even if stories aren’t done
- the planned velocity for each iteration is the measured velocity of the previous iteration
- task planning
- developers break the stories down into tasks
- no one signs up for more points than they have in their budgets
- task selection continues until either all tasks are assigned or all developers have used their budget
- if not enough room, developers ask customers to remove tasks or stories from iteration
- at halfway point, half of the stories should be done, reassess and readjust
- iterating
- at the end of each two weeks, show customer the progress
- they will provide their feedback and new user stories
- customer see progress frequently and have all the data and control they need to manage the project to their liking
- Testing
- test-driven testing
- results in every function having a test
- tells us when we inadvertently break some existing functionality
- helps us view the program from the vantage point of the caller
- immediately concerned with the interface
- force the design to be more testable
- forces us to decouple the software
- write test the way you want it to read
- writing tests before code improves our designs
- acceptance testing
- unit tests are necessary but insufficient
- acceptance tests are written by people who do not know the internal mechanisms of the system
- ultimate documentation of a feature
- in order to make the system testable, it has to be decoupled at the high architectural level
- avoid the temptation to do acceptance tests manually
- deprives those early iterations of the decoupling pressure exerted by the need to automate the acceptance tests
- conclusion
- the simpler it is to run a suite of tests, the more often they will be run
- if we can run tests several times a day, then the system will never be broken for more than a few minutes
- verification is only one benefit
- tests are a form of documentation
- the most important benefit is the impact it has on architecture and design
- Refactoring
- software has three functions 1) perform a function 2) afford change, 3) communicate to its readers
- takes attention and discipline to make a module easy read and change
- strongly recommend that you always practice refactoring for every module
- clean your code everyday
- A Programming Episode
- transcript of a pair programming session
- not all applications need object-oriented design
- What Is Agile Design?
- design of system primarily documented by source code
- design smells– the odors of rotting software
- rigidity: hard to change because every change forces many other changes to other parts of the system
- fragility: changes cause the system to break in places that have no conceptual relationship to the part that was changed
- immobility: It is hard to disentangle the system into components that can be reused in other systems
- viscosity: doing things right is harder than doing things wrong
- needless complexity: the design contains infrastructure that adds no direct benefit
- needless repetition: the design contains repeating structures that could be unified under a single abstraction
- opacity: It is hard to read and understand
- designs degrade because requirements change in ways the initial design did not anticipate
- agile teams don’t allow software to rot
- requirements always change
- agile developers does not apply principles and patterns to a big, up-front design, but from iteration to iteration
- SRP: The Single-Responsibility Principle
- A class should only have one reason to change
- separate responsibilities into different classes
- e.g. business rules and persistence control should almost never be mixed
- responsibility is “reason for change”
- If the application is not changing in ways that cause two responsibilities to change, then there is no need to separate them
- one of the simplest, but one of the hardest to get right
- OCP: The Open-Closed Principle
- Software entities should be open for extension but closed for modification
- Changes are achieved by adding new code, not by changing old code that already works
- In C++, Java, etc possible to create abstractions with abstract base classes
- abstract classes are more closely associated to their clients than to the classes that implement them
- there will always be some kind of change against which it is not closed
- the designer must choose the kinds of changes against which to close his design
- to avoid needless complexity, write code expecting it not to change and when change occurs, implement abstraction that protects against that change
- testing and quick development cycles stimulate change quicker
- developers should apply abstraction only to those parts of the program that exhibit frequent changes
- resisting premature abstraction is as important as abstraction itself
- LSP: The Liskov Substitution Principle
- subtypes must be substitutable for their base types
- substituting should not cause functionality to misbehave
- the validity of model can only be expressed in terms of its clients
- difficult to anticipate assumptions of users
- often best to defer all but the most obvious LSP violations until the related fragility has been smelled
- the is-a relationship pertains to behavior
- design-by-contract: specify preconditions and post-conditions, which need to apply to derived classes
- DIP: The 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
- should not depend on concrete classes, unless the class is not going to change much
- inversion of dependencies is the hallmark of good OO design
- if its dependencies are not inverted, it has a procedural design
- the principle of dependency inversion is the fundamental low-level mechanism behind many of the benefits claimed for OO technology
- ISP: The Interface-Segregation Principle
- polluted interfaces are “fat”
- ISP: clients should not be forced to depend on methods that they do not use
- results in the inadvertent coupling between all clients
- separation can be achieved through delegation (less elegant) or multiple inheritance
- clients can often be grouped by the service methods they call
- such groupings allow segregated interfaces
- Command and Active Object
- command: an interface with one method e.g. do
- e.g. sensor doesn’t need to know much
- initialization can handle wiring
- active object: active object engine maintains a linked list of commands
- run commands walk through and executes each command
- can do non-blocking multithreading
- Template Method & Strategy: Inheritance vs Delegation
- overuse of inheritence very costly
- “Favor object composition over class inheritance” GOF
- template: put all generic code into an implemented method of an abstract base class
- strategy: place generic code into a concrete class and it calls abstract methods of interface that is passed in
- strategy allows details to be used independently of the high-level algorithm e.g. IntSortHandle
- Facade and Mediator
- facade: provide a simple and specific interface onto a group of objects
- e.g. ProductData hides java.sql from application
- by convention all database calls must go through
- mediator: imposes policy in a hidden and unconstrained way
- e.g. showing a list based on text entry
- if policy needs to be big and visible facade
- if policy hidden from users, mediator
- Singleton and Monostate
- singleton: only one instance of class
- benefits:
- cross platform using appropriate middleware
- applicable to any class
- can be created through derivation
- lazy evaluation
- cons:
- destruction is undefined
- not inherited
- efficiency
- nontransaparent
- e.g. use to assure all database access will be through a single instance
- monostate: two instances behave as if they were one
- objects share the same static variables
- benefits
- transparency: users do not know object is monostate
- derivability
- polymorphism: methods can be overridden in derivatives
- well-defined creation and destruction
- cons
- no conversion: normal class cannot become a monostate
- efficiency
- presence
- platform local
- Null Object
- return object that does nothing when you call method
- The Payroll Case Study: Iteration One Begins
- The Payroll Case Study: Implementation
- Principles of Package Design
- Granularity: The Principles of Package Cohesion
- Reuse-Release Equivalence Principle (REP): The graunule of reuse is the graunle of release
- reusability comes only after there is a tracking system that offer guarantees of notification, safety, and support
- we want all of the classes in a package to be reusable
- Common-Reuse Principle (CRP): classes in a package are reused together. If you reuse one, you reuse them all
- Common-Closure Principle (CCP): classes in a package should be closed together against the same kind of changes.
- A change that affects a package affects all the classes in that package and no other package
- composition of packages will likely change over time
- Stability: The Principles of Package Coupling
- project breaking because of what someone else did
- two solutions: weekly build and ADP
- Acyclic-Dependencies Principle (ADP): Allow no cycles in the package-dependency graph
- partition development environment into releasable packages
- can break cycles with DIP or moving some classes to a new package
- Top-Down Design
- package structure cannot be designed top-down
- map to the buildability of the application
- The Stable-Dependencies Principle
- Depend in the direction of stability
- packages we expect to be volatile should not be depended on by a package that is difficult to change
- one sure way to make software difficult to change is to make lots of other software packages depend on it
- not all packages should be stable
- putting high-level design into stable packages make them inflexible
- use abstract classes to create classes that are flexible enough to be extended without requiring modification
- The Stable-Abstractions Principle (SAP)
- a package should be as abstract as it is stable
- concrete classes inflexible because not abstract
- if nonvolatile, concrete is ok e.g. string class
- Factory
- DIP tells us we should prefer dependencies on abstract classes and avoid dependencies on concrete classes, especially when they are volatile
- factory pattern allows us to create instances of concrete objects while depending on only abstract interfaces
- e.g. instead of instantiating Circle or Square directly, the Application could rely on a ShapeFactory interface with ‘makeSquare’ and ‘makeCircle’ methods
- one downside of this approach is each new shape requires new method
- can sacrifices some type safety for flexiblity by allowing shape to be passed into a method as a string
- recommend to not use factories starting out
- only put them in when the need for them becomes great
- The Payroll Case Study (Part 2)
- walk through case studies using covered patterns
- Composite
- can have an instance that is really a proxy for a group of instances
- only if you are going to treat the group of objects identically
- Observer–Backing into a Pattern
- register objects with observers
- pull-model: observer must pull information after being notified
- push-model: notify method includes args with hints
- allows you to add new observing objects without changing the observed object
- allows observed object to be closed
- Abstract Server, Adapter, and Bridge
- Imagine you have a “Switch” that can “turnOn” and “turnOff” a “Light”
- You can’t create a “FanSwitch” subclass from “Switch” because it will depend on Light still
- solve by creating a “Switchable” interface
- Switch can control anything with “Switchable” interface
- Interfaces belong to the client
- logical binding is stronger
- clients should be packaged together with the interfaces they control
- adaptor: through inheritance and delegation, can adapt to the interface of the object
- adaptor doesn’t come cheap, abstract server is appropriate for most situations
- bridge pattern: helpful when type hierarchy has more than one degree of freedom
- rather than combining hierarchies in tree structure, separate them and tie together with bridge
- e.g. separating connection method from hardware in a modem
- recommend to not use bridge unless compelling evidence
- patterns always come with both a cost and benefit
- Proxy and Stairway to Heaven: Managing Third Party APIs
- each object that is to be proxied is split into three parts
- interface that declares all methods that clients need to invoke
- class that implements those methods without knowledge of the database
- a proxy that knows about the database
- neither client nor the ProduceImplementation knows what happened
- proxies are non-trivial
- only may be worth it where the separation of business rules from database implementation is critically important
- also could be useful for third party APIs
- most applications don’t need proxies as they are heavy-weight
- stairway to heaven: have an abstract class that knows about the database with abstract “read” and “write” methods
- the base class also implements methods that help implement read and write
- e.g. PersistentProduct inherits from Product and PersistentObject and implements “read” and “write”
- requires multiple inheritance
- other options for DB interactions
- extension object: knows how to write the extended object on a database
- visitor
- decorator: decorate a business object and give it read and write or decorate a data object that knows how to read/write and give it business rules
- facade: class provides methods for reading and writing
- couples business rule objects with the database, but is probably the best starting point
- Case Study: Weather Station
- Visitor
- allows new methods to be added to existing hierarchies without modifying the hierarchies
- visitor is passed to “accept” function of class
- appropriate class derivative will call visit on it
- dual dispatch because involves two polymorphic dispatches
- first is “accept” which resolves the type of the object that accepts is called upon
- the second is “visit” which resolves to the particular function to be executed
- visitor is like a matrix
- visitor works well where the hierarchy to be modified does not need new derivatives
- acyclic visitor is like sparse matrix using degenerate methods
- decorator: create new class and delegate to contained instance
- wrapping method can perform other actions before and/or after
- State
- allow certain states
- can track with nested switch/case statements
- use transition tables if too hairy
- provides strong separation between the actions and the logic of state machine
- state machines can be useful in high-level application policies for GUIs or distributed systems
- The ETS Framework
- go over case study of testing software strategy
Like this:
Like Loading...