Professional Documents
Culture Documents
Summary Notes - COMP2911
Summary Notes - COMP2911
WEEK 1:
Agile Development:
Working software more essential than documentation.
Weekly development cycles with small groups of people.
Continuous development until development budget runs out.
WEEK 2:
ADTs: type / data abstraction - separation of the data (struct) and
the operations (functions)
OOP: procedural abstraction - both data and functionality is hidden /
associated within the object.
I.e. an object not only has its own instance of its class’s
variables but also of its functions.
Advantages: easier to divide up the program.
Reuse (e.g. strategy patterns) + reliability (e.g. program is
divided up (identify where the
error exists by evaluating where invalid pre-, post-
conditions are), polymorphism)
See the ’swirling’ example - the benefit is no need for
brute force -> polymorphism
Disadvantages: harder to prove correctness of program.
WEEK 3:
Defensive Programming: blind checking. Redundant = more
complicated code + inefficient.
Design by Contract:
CONTRACT: If the preconditions are true, then the
postconditions are guaranteed true.
Methods: preconditions (input), postconditions (output)
Classes: invariants (conditions to fields that must always
be true / preserved)
I.e. don’t need to test preconditions within the function - note it
in the documentation instead,
and assume the user / caller will take care of it.
Contract document: client / supplier’s obligations and benefits.
Stronger precondition = more burden on client; and vice-
versa with post-condition.
Inheritance: new class built upon pre-existing ones [parent -> child
(+freedom to override)]
Redeclaration: override functionality but keep external behaviour
constant - LSP.
Polymorphism: type adaption caused by inheritance. (see Week 5)
Dynamic binding: naturally tied to polymorphism: function calls
depend on the dynamic context of what type of class (parent or
child class) that function belongs to (could differ due to overriding).
Debugging tests simulate real life operation, hence your tests need
to obey the preconditions as well.
JAVA CONCEPTS:
Javadoc: automatically HTML formatted documentation
embedded within your code.
Try-catch blocks: for handling unexpected inputs and logic
errors. Don’t use them to catch
stack overflows or out-of-memory issues.
API spec bugs (incorrect commenting) vs code bugs (actual
implementation issue).
Asserts in Java: don’t use them for actual processing - use them
only for debugging.
JUnit: use of asserts in Eclipse for debugging purposes.
Useful for test driven development - but TTD can’t test
everything.
Don’t put function calls and assignments in an assert
statement.
@Override, @Decrepit, etc. are metadata tags read at compile
time ~ checks for correct
implementation of the methods you have tagged.
WEEK 4:
Law of Demeter: a class can only look one parent class up or one
child class down at a time - chaining together a series of class fields
reveals internal implementation.
Advantage: “hidden internal implementation = maintainable +
adaptable”.
Disadvantage: multiple function headers per class = space, time
inefficiencies.
E.g. dog.legs.walk() breaks LoD; instead call dog.walk() which
contains legs.walk() inside.
I.e. always use one dot, even if it means more function headers
as a result.
All it’s meant to say is you shouldn’t have direct access to the
internal implementation,
EVER. So basically, don’t ever make your aggregated classes
public?
(Possibly OK for primitives and “structs” - these only reveal
some statistic data, they
don’t reveal your procedural abstraction).
Walkthrough: go through the use case and relate each CRC card
(i.e. each class) to each step.
I.e. a vague sequence diagram.
UML:
Class diagrams:
Name, fields (+,-,#,underlined), methods (incl. <<‘’>>
construct. interface).
Relationships:
Dependence (- ->), association (—>), aggregation (<>—),
composition (<#>—).
Multiplicity (1, * (0+), 1..* (range)): i.e. how many relate
to how many.
Generalisation (parent <|— child), realisation (interface
<|- - class).
More info below:
http://creately.com/blog/diagrams/class-diagram-
relationships/ - easier to just read this.
Sequence diagrams:
`[frames (alt, opt, loop), arrows (left, right, down, (asynchron,
synchron)), guards].
Frame elements (w. top left name box):
Can chain frame elements for a block diagram =
abstraction.
If-else ‘frame elements’, loop ‘frame elements’.
Also frame elements for: parallel processing
(associated with hardware).
WEEK 5:
is-a relation: a child class is not only itself, but also its parent
(inheritance), grandparent classes, etc.
Hierarchy tree: top down relation, can contain both classes and
interfaces.
Every Java type is a subtype of Object.
USAGE:
Variable’s type can be a reference to an interface.
Any class that can implements that interface can be stored
in that variable.
Note no constructor exists for an interface - call the
class object’s constructor.
Can use instanceof InterfaceName to check if an object
implements that interface.
Generics: [JAVA]
Use generics if you have some field / function (parameter or
return value) that needs to be
generalised. All the code writing is the same except your type is
now a variable name as well.
Generics are statically typed, hence they behave differently to
sub typing in arrays.
I.e. compiler automates typecasting for you instead of the
programmer doing it manually.
E.g. List<E> type for lists, element type E. Get an item from list,
auto-typecasts to E for you.
Type variable: unqualified identifier, of which can be a generic
class / interface / method /
constructor declaration.
USAGE: [definition]
Generic identifier: define a class / interface, then put angle
brackets afterwards, and a
generic type (represented as a variable) afterwards: e.g.
ClassName<T>.
Method declarations identical: public T getFirst() etc.
What’s the point of this though? It’s like arguing: you can’t
go up, you can only go down
(which is how polymorphism works to begin with, so that’s
a GOOD thing).
If you want to go up and add, just do: List<Fruits> =
new List<Fruits>(); instead??
Example:
ConcreteList used can be any Fruit definition.
List<? extends Fruit> fruits = apples; // fruits = new
List<Apple>();
// variable type does
automatic typecasting, read-only
// fruits.add(new Strawberry()); // won’t compile
// fruits.add(new Fruit()); // won’t compile because
can’t input using extends
// why? can’t guarantee type safety since unknown
child type (on conversion of
// the List to a different generic type?)
// extends is too loose a definition, super is much
more restrictive.
ConcreteList used has to be same as base class expressed
within “< >”.
List<? super Apple> apples = fruits; // apples = new
List<Fruit>();
// variable type typecasts all
Fruit as Apple
// (and hence, or as child of
Apple)
fruits.add(new Apple()); fruits.add(new GreenApple()); //
valid
// fruits.add(new Fruit()); // invalid - can only add
objects with Apple as super,
// (including Apple itself), not Fruit,
etc. because of type safety
Lab:
Generics equals() function: do by calling .equals() of your
parameterised type E (which must
be an object (can’t be primitive), so it must have an equals()
method), or special functionality like
the generalised .contains( object of type E ) for ArrayList.
WEEK 6:
BFS:
Queue of nodes / states
While (queue not empty)
Pop node off queue, = current node
If goal node reached, break (could be placed elsewhere,
depends on required task)
WEEK 7:
Dijkstra: like a BFS, but considers weighting, and uses a PQ (priority
queue).
Priority queue: based off weighting, not based off time
spent in queue.
WEEK 8: (Agile)
Performance reviews: “rank and yank”
Makes things too aggressive, competitive (survival of fittest
mentality)
Discourages teamwork, encourages greed.
Arguably biased, subjective, unfair, easily exploitable
Can “game” the system if performance measured by some
metric
Agile / Scrum:
Eliminate waste: (muda)
Don’t over-engineer: make a solution more general only if it
doesn’t increase complexity.
Don’t over-produce: e.g. oversupply in goods, unnecessary
software content.
Don’t do excessive work: e.g. unnecessary transportation
Stop overburdening and unevenness: (muri, mura)
E.g. time management
Kanban system: a ‘pull system’.
Do things one at a time, only as you need to. Don’t do
anything in advance.
Software: just-in-time development. No Gantt charts. Highly
flexible to spec changes.
Basically: supply and demand, and responsiveness to
it.
Kaizan: continuous improvement.
Manifesto:
Individuals and interactions over processes and tools: (e.g.
scrum, meetings, sprints)
Working software over documentation: (e.g. Javadoc, + supports
TTD)
Customer collaboration over contract negotiation: (e.g. user
stories, product owner)
Responding to change over following a plan: (e.g. flexible to
spec changes)
MANIFESTO SUMMARY:
Meet customer needs no matter what.
Measure progress by working software (hence always have
working software!).
Maximise efficiency - maximise teamwork.
Scrum process:
[Step 1]: User Stories: user specifies what they want to be able
to do (both functional and
technical).
Stakeholders write user stories, not developers.
Use the simplest tools: an index card suffices.
[Step 2]: Planning Poker:
Rate difficulty and priority of each user story task (done by
a group of developers).
Use of relative estimation: e.g. small, medium, large. No
need for absolute estimates.
[Step 3]: Burndown Chart: scheduling and estimating (time and
priority)
Estimate how long the task will take, then keep track of it.
Measured in ideal days / ideal hours (work without
interruptions).
Prefer problems to turn up early rather than late.
Do not integrate late: agile = integrate as early as possible.
[Step 4]: User Acceptance Tests:
Does your developed product meet all the user stories’
requests?
Minimum Viable Product: what the user will accept
Refactoring:
Change the internal structure of code without changing its
external behaviour
“Refactor your code to use the pattern once you realise it’s
needed”
Refactoring databases (a bit harder): need to migrate all the
data.
Restructuring code: to keep it clean.
WEEK 9:
User-centred design: optimise product to how user wants to use the
product rather than forcing users to adapt to the product.
1. Persona: get different audiences to analyse your system
2. Scenario: get different situations for when your app is being
used
3. Use case: precise modelling of steps 1 and 2
Panel swapping:
http://stackoverflow.com/questions/1097366/java-swing-revalidate-
vs-repaint
Remove ‘master’ panel from frame, attach required panel on
(store all your panels in a list
somewhere). Call functions to suggest to Swing to repaint
the screen.
Event handlers
Timers (don’t really like using Timers for creating a game loop:
events can pile up).
Observer pattern: basically, waits until it is told that some event has
occurred, then passes it on to
all the dependencies that need it. Hence: Observable, aggregating
Observer.
(Association only rather than aggregation, according to
website).
SOLUTION:
‘Strategy pattern’ out the event-watching task: Observable
becomes the master control.
When Observable is told there’s been a change, it passes the
message on to all its
dependencies. Observable ‘unifies’ the entire system to change
at once.
http://www.oodesign.com/observer-pattern.html
Observable: interface / abstract class
Stores a list of objects to observe (Observer). Hence:
attach() and detach().
ConcreteObservable: a full implementation of Observable
Additional field storing a state, with getter, setter for the
state.
Externally: something “sets” the state to a new value, then
calls “notify()” to get all
objects attached to this observer to update themselves.
“Something updates ConcreteObservable”: done by the
main framework. The
main framework also initialises the object.
Controls a bunch of Listeners.
Classical examples:
Model View Controller Pattern: sounds like some standard
implementation for a program.
E.g. GUI: controller (input, update the state), model
(processes logic),
view (GUI output)
Event handling: used extensively here. I’m guessing that
Observer is controlled by the
master system that controls event handling.
WEEK 10:
Decorator, Composite Pattern: read bottom of text file
Anti-patterns: i.e. bad software practises (not necessarily just bad
software design implementations)
Decorator pattern:
[DYNAMICALLY ADD FUNCTIONALITY through an intermediate
component]
[intermediate component = ‘OVERLAYS’ FUNCTIONALITY]
Add additional responsibilities dynamically (i.e. on runtime) to
an object.
Static extension of functionality can be done through
inheritance / adding features and
toggling them on/off with flags.
Decorator Pattern: unlike composite pattern, only composes
one Component inside of it.
1. Have a Component base class and ConcreteComponent
extending the base class.
2. Would like to add additional functionality to
ConcreteComponent dynamically.
3. Hence, use instead a Decorator object that has this
additional functionality + can attach
to any Component implementation you want.
Your additional functionality holds your base
functionality.
GENERICS:
?: shorthand for Object
? extends: going to typecast everything to (up to at best the
base class)
? super Apple: (… = fruits) [example]
Can only write Apple or lower in
Reads out as super of Apple (probably Fruit), or higher (up
to Object).
Then need to typecast back down using:
Class class = fruit.getClass()
class.cast(fruit)
Why do we need it?
Extends [lower bound] is for fruits = apples. (read only,
all elements are Fruit).
Read only because can only store Apple, but read
as Fruit.
Can’t expand the precondition going up the
hierarchy.
Super [upper bound] is for apples = fruits. (read-write
possible, all elements are
Object).
Variables:
Lists: invariant (no sub typing at all for the list itself (sub typing
exists for element)), hence wildcards
https://docs.google.com/document/d/1C6-
ioRYU0VXpl1XmgKNm5BO6tP4GieNN0qyIwpKUiJs/edit