Administrative Question -- credit for code
If we were to make our project a real project and make it executable would there be anyway to get credit from it possibly? senior project? independent study?
Not in this class. Senior Project -- many senior projects start in CS375 -- if you can find a
client! Independent study -- possibly -- never happened -- and whoever acted as advisor on the
project would want something from it (we do independent studies. projects, theses, etc for
free). For example -- I would want to incorporate it in the materials for this class.
When does the first iteration end
Each iteration starts with the team deciding how long the iteration will take -- one week,
2 weeks, .... and what will be analyzed+designed+coded+designed. This is called
a time-box.
When the time is up, that is it. Whatever work that has not been done is completed in a later
iteration. The wise time, learns something about how fast they can work. They use this
to schedule the work for the next iteration.
Domain
I am still a bit unsure as to what is explicitly part of the domain. How do we discern what is part of the domain and what is not?
If you can kick it, it is real, and so in the domain.
If it does not go away when you destroy the computer.... it is real and so in
the domain.
If it ceases to exist when your computer is destroyed then it is inside the software and
not part of the domain.
Which is the commonest of the last 5 GRASP patterns
I don't know. I also don't think the information is important. They are are
sophisticated. They are all used. And often they are used together in the more complex
"Gang of Four" patterns.
Chapter 25 pages 415 -- Polymorphism
Is there another method other than polymorphism to execute the UML diagram on page 415?
No. The UML "realisation" and "Generalization" arrows imply polymorphic behavior.
Luckily, the code is easy, even in C++. See
[ fig25_25_1.cpp ]
and
[ test.fig25_25_1.cpp ]
plus stubs
[ Sale.cpp ]
and
[ TaxLineItems.cpp ]
for example.
Note: I had hoped to use my log to figure how long the above code took to write
and test. But I uncovered a bug in the logging script:-( Even so, I seem
to have started just after 7am and finished linking the code into this page before
7:15am. So it took 15 minutes to encode and test Figure 25.1 including stubs
for two dependent classes.
Once done.... I wouldn't expect to change the interface again. I would
have to replace the stubs for the concrete classes... After that I can
create new Tax Calculator classes any time I like. compile them separately
and use them without breaking the existing code. Priceless.
Chapter 25 pages 416-435 -- Polymorphism
What improvements does the landedOn method provide in the Monopoly Problem? What was lacking about the method used in the pseudocode?
Switches are hard to get right, hard to modify, and a source of future problems.
It is nearly always beetter to write code that automagically selects the right
behavior with zero programming.
class Player
{
Square * location;
...
virtual Something takeTurn(....) //Fig 25.3 Page 417
{
...
location=board->getSquare(location, fvTot);
location->landedOn();
}
...
};
I think we need another example of polymorphic C++ code...
First think back to the beginning of the class when we simulated the Dice
Game.
Look at pages 8 to 11 of Larman.
Remember that when we did this in class we had many ways of rolling the
dice.
As long as they fitted the same interface the game worked.
Now look at the code I wrote:
[ DiceGame.cpp ]
[ Die.cpp ]
[ testDiceGame.cpp ]
[ testDie.cpp ]
Polymorphism lets you extend ANY class with new behaviors
without rewriting the original.
To demonstrate polymorphism in C++ I edited Die2 to inherit from
Die
[ Die2.cpp ]
and tested it
[ testDie2.cpp ]
(of course).
I then generated a new version of DiceGame:
[ DiceGame2.cpp ]
that uses both kinds of dice... and tested it
[ testDiceGame2.cpp ]
and (of course) it worked (after removing one stupidity).
Notice that I only changed one line of code in the DiceGame class
< DiceGame(){die1 = new Die(); die2 = new Die(); }
> DiceGame(){die1 = new Die(); die2 = new Die2(); }
We could go further and switch dice as the program runs....
Here are my notes
[ polymorphism.html ]
from CSci202.
Chapter 25 pages 433 -- Information Hiding
In Parnas' quote, he mentions that difficult design decisions, along with design decisions that are likely to change should be hidden. Considering that, if you have just a normal design decision, do you just leave those alone?
Interesting question..... key point -- easy decisions are not likely to change and so you
don't have to hide them in a special module. So, think about the probability
that you might make the wrong decision and the the ammount of rewriting involved.
For years I have separated the part of the design that handle the hardware from the
core logic of the program. It has never caused a problem. Just a little extra thought.
Chapter 25 pages 427-434 -- Protected Variations
The section on protected variations confused me. Can you explain it more?
When we analyse a problem area we can often spott things that vary. The stakeholders
will mention that they are about to through out their old Spangling Server and replace it with
a new faster, cheaper, and smaller version. Or you discover that one part
of an organization insists on using 9 digit ISBNs and the rest 13 bit ISBN. Or, on a smaller
sclae, the behavior of Wodgets change as time goes one. There are times when their state lets
them execute the zark procedure, and their are times when they can't. Here
we have a varying state. We would like instances of Wodget to change
class... something that is not part of normal
object technology. Again something varies and we need a wat to handle the variation.
And so it goes on.
When you have variations like this -- it wise to take a little time and ingenuity to find a way
of containing the damage. Finding a way to stop the variation infecting the whole
system. For example with every function testing to see which kind of ISBN is needed. Or
which Spangling Server we have running... This is known as Protected Variation.
It is one of the oldest design principles in the business.
We had an example at the beginning of this class when I brought in a dozen ways of
simulating a throw of the dice. Each group figured out a way of faking the behavior, even tho'
some of them only hard dominoes of playing cards, not dice. We often need the same
solution in real life problem areas.
Protected Variation in Design
The original way of hiding variations was to hide them behind a collection of functions.
So, for example you would have half-a-dozen subprograms for controlling a plotter. These
would be used in exactly the same way when the old Calcom Drum plotter was replaced by a new
Wang flat bed plotter. You might even design a whole language for
driving graphic devices which carefully disguised the different gadgets.
Been here, done this.
These days you think in terms of creating a class -- which contains a list of function, of course,
that do the same thing. Only here we attach the function to objects, and can use
inheritance and polymorphism to place difference behind a wall which presents a common interface.
To summarize: PV implies the use of interfaces and abstraction in design. Often you can
Indirection and Polymorphism.
Chapter 25 pages 428 -- PV
What is meant by the statement that an Operating System is an example of indirection to achieve PV?
It means that because we have an operating system you don't have to worry about most of
the administartive and physical details of the hardware. Example -- when was the last time you
thouhgt about what that folder on your desktop actually is -- what the data structure is?
When programming, do you worry about the hundreds of other processes running on your computer?
Do you actually know what happens when you execute
stream.fopen("foobar.dat",ios::in);
and does it matter?
These are some of the many design decisions and physical VARIATIONS that the OS
PROTECTS you from.
Chapter 25.2 pages 421 -- Pure Fab
Could you give a more detailed explanation on when or where a pure fabrication would be used?
Breifly, when you can solve a problem (high coupling, low cohesion, variations, ...)
by inventing a class of objects.
More below...
Chapter 25 pages 422-423 -- Pure fabrication
As applications are pluggable, can Pure Fabrication Patterns be used as a strategy to introduce objects in the domain model at any layer in the design?
Yes -- Protected Variation include pluggable components -- a component hides different
implementations behind a common (standard?) interface.
No. Pure Fabrication is defined as adding classes to the design that do not appear in the
domain. They are classes invented to make the code better, not to reflect the real world,
or to interface with the user interface.
If, however you invent a class and you discover that it was in the domain already -- this is a
"Duh" moment -- then you (1) slap your face, (2) add it to the domain model and (3)
use Information Expert instead. Note: slapping your face is an important step because
it discourages you from being lazy when domain modelling:-)
Chapter 25 pages 424 -- decomposition
can you explain behavioral decomposition
See
[ 15q.html#behaviorial decomposition ]
(last class)
Behaviorial decomposition and coupling
Can you explain how using behavioral decompostion can affect coupling?
Normally adding a class because it can hold a particular behavior (not to reflect
the real world) can lower coupling. However, if it attracts behaviors that need data
or operations that are in other classes then it becomes coupled to them and
this raises the overall coupling.
When you refactor the code you notice that the fabriactes class is always calling another class
to get is work done.... perhaps it is time to remove the middle man? Or does it satisfy some
other need such as Protected Variation?
Chapter 25 pages 425 -- Pure Fabrication
Pure fabrication seems to address a specific need and is used as a last resort. How would pure fabrication be overused if it was created for a specific need?
PV is overused in several ways. (1) People try to handle variations that never actually happen.
The counter to this is to say YAGNI -- You ain't Gonna Need It. (2) People use
PV as an excuse for adding unreal ideas into the domian model. This muddles up things
that are needed for technical reasons with ideas that the stakeholders are paying for.
Chapter 26 pages 436-440 -- Factory and Adapter
Are simple and concrete factory used like GoF adapter pattern?
No. Factories are used to create objects. An alternative to Larman's Creator GRASP pattern.
Adapters are organizational or structural patterns that hide variations behind a common
pure fabrication. They are used in a different way.
The only thing they have in common is that they are part of the design not that is not found
in the real world. The solve technical problems not model domain issues.
2008
Chapter 25 pp 25.4 -- GRASP methods
Has there been situations where one can use all the GRASP patterns with in
interaction diagram? If so, is it recommended?
I'm sure it will happen -- if the diagram is complex enough.
The number you use is irrelevant -- what matters is if you come up with
a maintainable working design.
Chapter 25 pp 413 -- GRASP
Out of the last four GRASP patterns Polymorphism, Indirection, Pure
Fabrication, and Protected Variations which would you say is the most
important or the one we should worry more about?
All of them... equally. And they also have a habit of fitting together.
These are the sophisticated tools of an OO designer's trade.
In my experience, however, C++ students have more trouble figuring out
one pattern more than any other....
Chapter 25 pp 414 -- Polymorphism
Can I understand the solution for Polymorphism is to create a controller
to handle the alternatives?
Not just a GRASP controller.
Polymorphism is an invisible hand that
helps the program execute the right code when a message is passed.
Chapter 25 pp 414-421 -- GRASP: More Objects With Responsibilities -- Got
Polymorphism
When is polymorphism not needed?
Small programs. Simple projects. No modifications. No class hierarchies.
In other words -- programming in the 1960s.
Chapter 25 pp 414-420 -- Polymorphism
Should we write code first to locate our polymorphism cases or is it done
in the OO/D phase?
No. You should incorporate polymorphism in your designs before you
discover it in code... it is part of the UML.
Chapter 25 pp 413-135 -- Polymorphism
How effective are polymorphic operations while replacing components in a
client-server relationship?
It should work OK. Especially if the client-server use the CORBA protocols
that allow polymorphic message passing between remote objects.
Similarly, I'm sure that Java Remote Messaging (or whatever they call it)
is
polymorphic.
Not so sure about RPCs -- they predate objects.
Chapter 25 pp 426 -- Indirection.
"By adding a level of indirection and adding polymorphism, the adapter
objects protect the inner design against variations in the external
interfaces." I'm not clear on how exactly that is being done. It seems to
me that a change to the TaxMasterSystem's interface would necessitate a
change in the TaxMasterAdapter. If that adapter wasn't there, you'd just
have to change code in whatever class (probably Sale) was responsible for
tracking the taxes, wouldn't you? Could you go over this?
The idea is to have fixed interfaces and variable internals. Your design
should
specify a fixed point behind which variation can occur.
So you shouldn't change the Interface as much as add in new variation
behind the
indirect object.
Question: do you change the way you drive when you get a new battery?
Chapter 25 pp 427-433 -- Protected variation and Polymorphism
Protected Variation and Polymorphism seem related. What is the difference
between the two? Where would you apply one pattern over the other?
Polymorphism is a powerful technology that is very useful for
handling Protected Variation. Protected Variation gives one reason "why"
for a particular use of Polymorphism.
Chapter 25 pp 421 -- Pure Fabrication
When (as the book states) is a solution by Expert not appropriate, thus
causing me to use a Pure Fabrication pattern?
You use it when expert, creator, controller, ... and all the others are
not appropriate.
Expert fails when there is no class in your design or in the domain model
that has the data, or doesn't know where to find it. Sometimes it fails because
you end up with bad coupling between experts. Sometimes you have two many partial experts.
You have to use your brain.
Chapter 20 pp 413-425 -- Pure Fabrication
Would pure fabrication be a class that you create that has nothing to do
with your original design except for the fact that it has code that is used
several times throughout. Ex So instead of writing code several times for
say adding two numbers, I could make an add class that would do the work
and I would just pass the numbers?
Yes. But you might also invent a class (with no inspiration from the
domain) to reduce coupling or because it looks cohesive. It is not
just a matter of needing the functionality more than once. It can be
for other reasons.
Chapter 25 pp 413-435 -- Pure Fabrication
Why is Pure Fabrication even an option? Is it just named as a last resort
or is it really used that often?
Because there are some occasions when nothing else works.... for example
you just didn't notice an important idea in the domain. Then the design
process
tells you that you missed something.... you Fabricate it and then discover
that it was there all along!
But sometimes the best way to make software easy to change is to
add a class that acts as a hinge and separates one part from another
by a flexible coupling... As an example, in the "Apollo 13" movie
they have to connect a round hose to a square hole -- and use
the cardboard cover of a manual to do it. This is very like
fabricating a new object to make the system work with no
reference to worls outside the system.
Warning -- do not over do Pure Fabrication
Chapter 25 pp 424-425 -- Decompositions
Can you explain in better detail of what a
representational decomposition
and a
behavioral decomposition
is?
Designing software is all about breaking the software into pieces that
make some kind of sense. We call this process "decomposition". Then
the different parts can be "composed" to make the software work. In OO
projects we decompose the solution into classes. But where do these
classes come from?
When you create a class of objects -- why do you do it? Do you
do it because the client is always talking about something like
that? If so Larman would say you have a "representational decomposition".
Do you discover it during design or coding -- and it makes the
program more maintainable but has no meaning to your client? If
so Larman would call this a "behavioral decomposition".
For example, in my Login handout the "Finder" class is the result of behavioral
decomposition, but using "Person" is from a representational one.
Chapter 25 pp 413-435 -- Adapter/Bridge
Can you provide examples(actual code if possible) of an adapter and bridge
design pattern.
For some reason everybody uses the stack as an example...
Adapter:
[ wiki?AdapterPattern ]
(A stack in Java).
Bridge -- the C++ STL stack and queue are bridges or wrappers
for other STL classes. Here is an abbreviated version of the
definition of a stack:
class stack {
... //declares c as a suitable container
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
Chapter 25 pp 425-427 -- Indirection
My question is on Indirection, seems like a simple enough example in the
book but is there any other examples that might be worth while in knowing?
I'm sure there are.... does any body in the class have an example?
Chapter 25 pp 426 -- De-couple
Can you give an example on how to de-couple objects?
See previous.
I have a simple example of an object that decouples my
code from some C++ library functions.
Suppose I don't like the way we get random number is C++ then
I can create a class of Random objects with this interface
class Random
{ public:
Random(double lowest=0, double highest=1);
virtual double next();
...
};
I could test it like this
Random r(0,1);
for(...) cout << r.next() << endl;
and implement it by including
private:
double low, range;
in the above class and then writing:
Random::Random(double lowest=0, double highest=1)
{
low = lowest;
range = highest - lowest;
srand(time(NULL));
}
double Random::next()
{
return low+(range*rand())/RAND_MAX;
}
Chapter 25 pp 433 -- Information Hiding
The book briefly covers information hiding. Give examples of information
hiding and how it relates to protected variations?
Parnas formulated Information Hiding in the 1970's. In his example he
split a program into 3 modules: one handled the input device (a card
punch),
one handled the logic of problem, and one handling the output device (
a line printer). So when the user wanted to change the program to use
magnetic tape... the input and output parts changed but not the middle.
When the user got a disk drive the same thing happened. And so on.
Our division of UI + Domain Layer + Services is inspired by this.
Chapter 25 pp 433 -- Information Hiding
Information hiding is good because it doesn't allow users to alter data.
The clever idea is that you can know how to use a class without having
to know how it works. Like your watch. So not only is the data hidden
but so can the code!
Parnas had a strong version of Information Hiding.
If a programmer was using a data type (think class) then all you
would be told about where the operations that you could do to it.
All other code would be hidden from you. In C++ this tends to
mean that you are given a header (Widget.h) file and a compiled
(Widget.o) file but not the source code (Widget.cpp) of the whole file.
Now this does share some information about the data in the Widget
objects -- but this is inevitable given the way C++ works.
Brookes argued that all code should be available for every body to read an
modify. But later he stated he had rethought this to match Parnas.
The XP people (as always) have their own extreme position: all code
is open to the team: to read and to write at any time.... but you
instantly test all changes.
Chapter 25 pp 413-435 -- Open-Closed Principle
I got confused when reading about the Open-Closed Principle. Could you
please go over it.
See next...
Chapter 25.4 pp 434 -- OCP
An example of an
Open-Closed Principle
is... X can be opened to Y and always Z. And it's only open to Y if it Y
needs to access something and has permission to. While Z can always access
it because it has permission to.
That look right?
I'd express it like this: if X uses Y in some way or other you don't want
changes to Y to effect X, but you also want to be able to change Y in ways
that don't change X.
Chapter 26 pp 459-461 -- considering grasp and other principles in the
design
Should we avoid extracting child objects out of parent, and then passing
around the child objects?
Sounds like the law of Demeter to me.
Previous
Should we consider exceptions and errors in all projects
Sadly, yes.
An empirical law: the exceptional case is often as important as the normal
one.
(From a hospital project).
Code smells and stenches -- in real working environments
Do real companies talk about code smells?
Depends how "hip" they are. The term "code smell" is a recent invention of
the eXtreme Programming people.... but it has caught on in many forward
looking workplaces. "Stench" is not as common and more of a joke or insult.
Note. The more traditional, set-in-their-ways places may not have "got"
this
idea yet. But it usually catches on pretty fast when introduced.
What are the best strategies used to apply polymorphism
If you've got it in you implementation language -- use it.
In design -- follow GRASP.
How exactly does test-driven development work
You write tests, you write code, you test the code and fix it until
all tests are OK. Then stop.
How well does that work? Very well -- if you choose your tests well.
Hint: if you don't have a TDD environment like JUnit get into the habit
of starting with a main program that defines a test of the classes
you are about to write. For example, in C++ use main and cassert...
I might start with this
#include <iostream>
#include <cassert>
int main(int argc, char* argv[])
{// test prime number function
assert( prime(2) );
assert( prime(3) );
assert( not prime(4) );
assert( prime(5) );
assert( not prime(9) );
assert( not prime(42));
}//end main
and the work on it (if time I'd do this in class) giving the following
series of (failing) attempts:
[ tp.cpp ]
[ tp1.cpp ]
[ tp2.cpp ]
How does the implementation model differ from the use case model
Use case models (requirements) define the problems, the Implementation
models describe solutions -- in detail.