Prev: Last Call for Papers Reminder (extended): The World Congress on Engineering WCE 2010
Next: CFP CGVCVIP 2010: new date - until 29 March 2010
From: Daniel T. on 23 Mar 2010 08:44 Vladimir Jovic <vladaspams(a)gmail.com> wrote: > Daniel T. wrote: > > Vladimir Jovic <vladaspams(a)gmail.com> wrote: > > > Daniel T. wrote: > > > > Vladimir Jovic <vladaspams(a)gmail.com> wrote: > > > > > > > > > PS In case I wasn't clear enough, here is a simple ASCI diagram: > > > > > a -> b > > > > > \-> c -> d > > > > > \-> e > > > > > \-> f > > > > > > > > > > The question : How to test class c, using stubs for classes > > > > > d,e,f? An example in c++ would be perfect, but java or other > > > > > language is ok as well > > > > > > > > Looking at your diagram, if 'd', 'e', and 'f' were all ints > > > > would you be concerned with testing 'c' in isolation to them? I > > > > think not. You can be sure that 'int' is fully tested and > > > > functions, and you rely on that fact when testing to see that > > > > 'c' works. > > > > > > Yes, off course. Doing that makes not sense. > > > > > > > Things aren't much different when 'd', 'e' or 'f' are classes > > > > that you write, except that you have more work to do in order to > > > > make sure they are fully tested before you can test 'c' properly. > > > > > > The problem I am facing is the unit tests are becoming more and > > > more complex as the we go more levels down. But is there an > > > alternative? > > > > I'm not sure what you mean by "levels down" do you mean d, e, and f > > are harder to test than c, or that c is harder to test than d, e, > > and f? > > If the system looks like this: > > a -> b -> c -> d -> .... -> x -> y > -> ... > -> ... > -> ... > > where all these are classes, then testing a is basically the > functionality test. But if you want to write unit tests for b or c, > things are more complicated then for example writing for x or y. > Unless you use mock classes. Not at all. Your job when testing b or c is the same as when testing x or y... make sure that each function meets its postconditions when its preconditions hold true. The cyclomatic complexity of 'b' should be about the same as the cyclomatic complexity of 'x'. > > Either way, if you distributed your functionality well, no class > > should be harder to test than any other. > > Might be a stupid question, but is there a metric or method to measure > functionality distribution? I use the number of tests necessary for thorough path test coverage. Figure out the cyclomatic complexity of each module (class) in your system, and try to bring them on par. Don't be dogmatic about it, but if you have some modules that are much higher than average, those are god classes and need to be re-distributed. Classes that are much lower are data buckets and should probably take on more responsibility. Here is the original paper on cyclomatic complexity: http://classes.cecs.ucf.edu/eel6883/berrios/notes/Paper%204%20(Complexity %20Measure).pdf As a practical matter, you determine the cyclomatic complexity of a class by adding the following: +1 for each non-const member function. +1 for each loop ('while' and 'for') in the member functions of the class +1 for each decision ('if' and 'case') in the member functions of the class -1 for each exception ('throw') in the member functions of the class Yes, you are literally counting keywords here, which makes it an easy thing to do. Maybe you can even write a tool that does it for you. BTW, the above assumes two things, (1) that you never put mutating state inside a conditional and (2) that you only throw an exception when there is a contract violation.
From: Garrett Smith on 16 Apr 2010 01:53 Daniel T. wrote: > Vladimir Jovic <vladaspams(a)gmail.com> wrote: >> Daniel T. wrote: >>> Vladimir Jovic <vladaspams(a)gmail.com> wrote: >>> >>>> PS In case I wasn't clear enough, here is a simple ASCI diagram: >>>> a -> b >>>> \-> c -> d >>>> \-> e >>>> \-> f >>>> >>>> The question : How to test class c, using stubs for classes d,e,f? >>>> An example in c++ would be perfect, but java or other language is >>>> ok as well >>> Looking at your diagram, if 'd', 'e', and 'f' were all ints would >>> you be concerned with testing 'c' in isolation to them? I think not. >>> You can be sure that 'int' is fully tested and functions, and you >>> rely on that fact when testing to see that 'c' works. >> Yes, off course. Doing that makes not sense. >> >>> Things aren't much different when 'd', 'e' or 'f' are classes that >>> you write, except that you have more work to do in order to make >>> sure they are fully tested before you can test 'c' properly. >> The problem I am facing is the unit tests are becoming more and more >> complex as the we go more levels down. But is there an alternative? > > I'm not sure what you mean by "levels down" do you mean d, e, and f are > harder to test than c, or that c is harder to test than d, e, and f? > > Either way, if you distributed your functionality well, no class should > be harder to test than any other. > >>> The key to "self-containment" is that 'c' does expose its 'd', 'e' >>> or 'f' and rely on others changing the state of them outside of >>> itself. In other words, your aim should be a containment >>> relationship (as defined by Riel, not the UML version of >>> containment) wherever possible. >> Great. Do you recommend Riel's book to improve OO design? I found this >> on the net: >> http://lcm.csa.iisc.ernet.in/soft_arch/OO_Design_Heuristic.htm >> (summary of OO design from Riel) > > Yes, I recommend it highly. > I see: | 2. Users of a class must be dependent on its public interface, but a | class should not be dependent on its users. What about IoC? What is wrong with depending on abstractions. | 18. Eliminate irrelevant classes from your design. Only classes? What about methods or even statements? Dead code makes the code harder to read and hides bugs. | 37. Derived classes must have knowledge of their base class by | definition, but base classes should not know anything about their | derived classes NO abstract classes? If an abstract class has two methods, m1 and m2, m1 calls m2, and m2 is abstract then it must be implemented by the subclass. That seems to violate this principle. I agree with a lot of what is written, though it seems a bit rough. [...] -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Daniel T. on 16 Apr 2010 09:37 Garrett Smith <dhtmlkitchen(a)gmail.com> wrote: > Daniel T. wrote: > > Vladimir Jovic <vladaspams(a)gmail.com> wrote: > > > Do you recommend Riel's book to improve OO design? I found this on > > > the net: > > > http://lcm.csa.iisc.ernet.in/soft_arch/OO_Design_Heuristic.htm > > > (summary of OO design from Riel) > > > > Yes, I recommend it highly. > > I see: > > | 2. Users of a class must be dependent on its public interface, but a > | class should not be dependent on its users. > > What about IoC? What is wrong with depending on abstractions. From the book: If a contained object is dependent on the class that contains it, then it is not reusable. If the card reader of an automatic teller machine has knowledge that it is contained in an ATM, then it cannot be taken out of the ATM and used to build a security door... When a contained object must send a message to its containing class, then the containing class should be made more general through judicious use of inheritance. In this way, the contained object does not depend on the containing class, only on its base class. It is easier to require a reuser to inherit from some abstract class than to use a particular class (effectively ruining any chance of reuse outside of the original domain). In other words, there is nothing wrong with depending on abstractions, there is something wrong with depending on concrete types. > | 18. Eliminate irrelevant classes from your design. > > Only classes? What about methods or even statements? > > Dead code makes the code harder to read and hides bugs. The heuristic that covers methods is: "Do not clutter the public interface of a class with things that users of that class are not able to use or are not interested in using." As for statements, the book is aimed at Object-Oriented heuristics, not general programming heuristics. Now you might wonder why two different heuristics? The answer is due to the difference in granularity and reusability. In order for a class to be reusable, it often must provide methods that not all users use. (For example, there are many methods on your typical container class that may never be used in any one particular context, or even in an entire program, but they are used by some of their clients.) However, an "irrelevant class" is defined in the book as a class that has only the standard complement of methods that all classes are expected to implement (as per heuristic 4: "Implement a minimal public interface that all classes understand.") Such classes have (almost literally) no functionality within any system. > | 37. Derived classes must have knowledge of their base class by > | definition, but base classes should not know anything about their > | derived classes > > NO abstract classes? If an abstract class has two methods, m1 and m2, > m1 calls m2, and m2 is abstract then it must be implemented by the > subclass. That seems to violate this principle. Here there is some confusion about what the "knowing something about" means: If base classes have knowledge of their derived classes, then it is implied that if a new derived class is added to a base class, the code of the base class will need modification. Riel goes on to specifically address the use of polymorphism to avoid these sorts of issues. In other words, your example does not violate this heuristic, rather it is a method for avoiding the violation of this heuristic. More concretely: class Base { virtual void foo() = 0; public: void bar() { foo(); } }; The class above depends only on its own interface, it does not depend on the interface, or implementation of any derived class. > I agree with a lot of what is written, though it seems a bit rough. The heuristics alone as a bald list do seem a bit rough, but you have to remember there is an almost 400 page book that goes along with them. Also, keep in mind, the book was written in 1996 when people were new to OO. Now, some of the heuristics are things that are an ingrained part of the community.
From: Garrett Smith on 16 Apr 2010 21:00 Daniel T. wrote: > Garrett Smith <dhtmlkitchen(a)gmail.com> wrote: >> Daniel T. wrote: >>> Vladimir Jovic <vladaspams(a)gmail.com> wrote: > >>>> Do you recommend Riel's book to improve OO design? I found this on >>>> the net: >>>> http://lcm.csa.iisc.ernet.in/soft_arch/OO_Design_Heuristic.htm >>>> (summary of OO design from Riel) >>> Yes, I recommend it highly. >> I see: >> >> | 2. Users of a class must be dependent on its public interface, but a >> | class should not be dependent on its users. >> >> What about IoC? What is wrong with depending on abstractions. > > From the book: > > If a contained object is dependent on the class that contains it, > then it is not reusable. If the card reader of an automatic teller > machine has knowledge that it is contained in an ATM, then it cannot > be taken out of the ATM and used to build a security door... > Thanks you for the clarification and elaboration. Is the conclusion in the first sentence is strongly supported by the rest of the paragraph? The rest of the paragraph misses a more obvious point: Why paint yourself into a corner with tangled design as tight coupling? Arguments about the security door are going to seem like far fetched theoretical paranoia to a project manager who is commissioned to a project regarding ATM cards and won't likely have much influence. The Card's implementation details depending will result in confusing code in the Card. Such coupling might cause problems when a new ATM vendor comes on the market (different host environment). Addressing those problems is going to cost money and having everybody in a mad scramble trying to make things work in the new version or make of the ATM when it is released. This sort of thing is unfortunately too common with javascript for the web. Programs are often tied to proprietary (mis)features of a particular host environment (browser). Then when "it doesn't work", you end up seeing code like: | <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" > The sad thing is that most of the "cross browser" javascript libraries that you'll see suffer from these avoidable problems. Implementation code is also often tied with details of a javascript library. The jQuery javascript library, for exmaple, provides methods that are very complicated and loosely defined. When they change, it tends to "not work" for the user going through an upgrade. > When a contained object must send a message to its containing class, > then the containing class should be made more general through > judicious use of inheritance. In this way, the contained object does > not depend on the containing class, only on its base class. It is > easier to require a reuser to inherit from some abstract class than > to use a particular class (effectively ruining any chance of reuse > outside of the original domain). > OK. > In other words, there is nothing wrong with depending on abstractions, > there is something wrong with depending on concrete types. > Right. >> | 18. Eliminate irrelevant classes from your design. >> >> Only classes? What about methods or even statements? >> >> Dead code makes the code harder to read and hides bugs. > > The heuristic that covers methods is: "Do not clutter the public > interface of a class with things that users of that class are not able > to use or are not interested in using." Right. As for statements, the book is > aimed at Object-Oriented heuristics, not general programming heuristics. > OK. > Now you might wonder why two different heuristics? The answer is due to > the difference in granularity and reusability. In order for a class to > be reusable, it often must provide methods that not all users use. (For > example, there are many methods on your typical container class that may > never be used in any one particular context, or even in an entire > program, but they are used by some of their clients.) Sounds cluttered. I try to get maximum reuse out of each module. Who wants to use a module that is largely irrelevant? Regarding code that must be downloaded before being interpreted, certainly the user does not! However, an > "irrelevant class" is defined in the book as a class that has only the > standard complement of methods that all classes are expected to > implement (as per heuristic 4: "Implement a minimal public interface > that all classes understand.") Such classes have (almost literally) no > functionality within any system. > I see. But what if someone *is* genuinely interested in using that interface? What if, for example, an interface is defined and then an implementation implements all of those methods in a specific way such that other implementations would find irrelevant? What about State or Strategy, for that matter? For example, an interface with a "blendTo" method that acts as a strategy. Color transition is implemented in a way that would make no sense to the transition for length, yet ColorTransition and LengthTransition have identical interfaces, making them both redundant. >> | 37. Derived classes must have knowledge of their base class by >> | definition, but base classes should not know anything about their >> | derived classes >> >> NO abstract classes? If an abstract class has two methods, m1 and m2, >> m1 calls m2, and m2 is abstract then it must be implemented by the >> subclass. That seems to violate this principle. > > Here there is some confusion about what the "knowing something about" > means: > > If base classes have knowledge of their derived classes, then it is > implied that if a new derived class is added to a base class, the > code of the base class will need modification. > > Riel goes on to specifically address the use of polymorphism to avoid > these sorts of issues. In other words, your example does not violate > this heuristic, rather it is a method for avoiding the violation of this > heuristic. > I see. I think the problem is his terminology "no knowledge". Obviously, a superclass that is designed to be such knows that it has a subclass (a subclass has knowledge of its superclass should go without saying). Reil is not capable of describing exactly what it is that is a problem from which he has derived his badly written principle. A more suitable principle, IMHO: Do not rely on implementation details or other side effects of an object - code to the interface (as above). > More concretely: > > class Base { > virtual void foo() = 0; > public: > void bar() { > foo(); > } > }; > > The class above depends only on its own interface, it does not depend on > the interface, or implementation of any derived class. > Right. *That* makes sense. >> I agree with a lot of what is written, though it seems a bit rough. > > The heuristics alone as a bald list do seem a bit rough, but you have to > remember there is an almost 400 page book that goes along with them. > Also, keep in mind, the book was written in 1996 when people were new to > OO. Now, some of the heuristics are things that are an ingrained part of > the community. Ah, if only it were true with javascript community. Take a look at, for example, Dojo or MooTools. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: johnzabroski on 28 Apr 2010 15:32
On Mar 22, 7:40 am, Vladimir Jovic <vladasp...(a)gmail.com> wrote: > Hello, > > In the article in Lahman's blog here:http://pathfinderpeople.blogs.com/hslahman/what_is_oo_development_all... > the explanation about self-containment in OO tells this: > > *** > As a practical matter that means that any object responsibility can be > exhaustively unit tested without implementing any other object behaviors > *** > > What if the system is complex, and this class handles other classes? > What are strategies for handling this case? > > Since I am working in C++, I can imaging that the testing class is > implemented as a template, where the template parameters are the classes > that the tested class handles. > Or, is there other way? > This seams like a complex solution just to simplify testing. > > Thanks in advance. > > PS In case I wasn't clear enough, here is a simple ASCI diagram: > a -> b > \-> c -> d > \-> e > \-> f > > The question : How to test class c, using stubs for classes d,e,f? > An example in c++ would be perfect, but java or other language is ok as well The problem here is methodological, and has nothing to do with code. You are fundamentally abusing the static production rules of your third generation language. You are using an inheritance hierarchy to create a "controller tree". In Executable UML, Balcer and Mellor emphatically state: "The first rule of control partitioning is that you do not make controller objects. The second rule of control partitioning is that *you do not make controller objects.", Executable UML, page 236, http://books.google.com/books?id=zBS0aWNjBqcC&pg=PA236&lpg=PA236&dq=The+first+rule+of+control+partitioning+is+that+you+do+not+create+controller+objects.&source=bl It is fundamentally obvious to anyone looking at your example that you are using object superclasses as a way to control leaf classes. What you've effectively done is build a lattice, or house of cards, for a software system. The reason unit testing is getting progressively harder is that you don't actually have any real world analagous units to test, so as you make changes to your software, you have to edit the lattice appropriately. This requires preserving an entailment relation through all leaf classes that ensures value paths are steady. Technically speaking, this is fundamentally impossible to do and will guarantee client code will break if it is using value paths now absorbed by the new class. Bottom line: Your software, as implemented, sucks, and is not testable in the way OO programmers discuss testability. Kent Beck pioneered Test-Driven Development as a way to help prevent programmers from making such design mistakes, because testing first generally causes programmers to steer clear of such awful designs. |