From: Vladimir Jovic on
johnzabroski(a)gmail.com wrote:
> On Apr 30, 5:22 pm, "johnzabro...(a)gmail.com" <johnzabro...(a)gmail.com>
> wrote:
>> On Apr 29, 4:50 am, Vladimir Jovic <vladasp...(a)gmail.com> wrote:
>>

>>> What are alternatives? How to fix such architecture?
>
> Model the problem -- I can't really give better advice without knowing
> something about the problem. Based on experience with this code
> smell, where superclasses are pervasively controlling leaf classes, I
> can *guess* what the general solution would look like, but I don't
> want the general solution to be your *actual* solution. So what
> follows is my analysis of the meta-problem, not the problem domain
> itself.
>
> If you are writing code in a way such that superclasses are
> controlling leaf classes, then you have a Specification where the
> problem can be broken down into Stages (what you are currently using
> classes with arbitrary names for). If at each Stage you cannot
> predict what the sequences of actions will be, then you also need a
> Sequence abstraction so that each Stage is composed of Sequences. But
> this analysis is not complete; you need to recursively specify what
> the specification of each stage and sequence is. In other words, a
> Sequence must collaborate with a SequenceSpecification and a Stage
> must collaborate with a StageSpecification. A StageSpecification is
> composed of SequenceSpecifications, so that when you want to reuse the
> Stage, you instead focus on reusing its Specification, giving you a
> degree of freedom in how to implement the Stage by taking advantage of
> what the Specification *doesn't* say. This analysis will allow you to
> *easily* apply parametric polymorphism on-demand at each Stage and
> Sequence, as well as allow for implementation hiding.

It looks like you are forming a state chart.

>
> Your current solution doesn't really allow parametric polymorphism in
> a safe way, and it doesn't allow for implementation hiding since the
> parent superclasses must know about their child subclasses in order to
> properly control them.
>

In other words, use "tell, don't ask" principle to remove the super
classes. Correct?

btw what tools are you using to model the problem?
I modelled few things, but only on paper. Today I thought of trying
kivio to model a problem I am facing.
From: johnzabroski on
On May 3, 8:06 am, Vladimir Jovic <vladasp...(a)gmail.com> wrote:
> johnzabro...(a)gmail.com wrote:
> > On Apr 30, 5:22 pm, "johnzabro...(a)gmail.com" <johnzabro...(a)gmail.com>
> > wrote:
> >> On Apr 29, 4:50 am, Vladimir Jovic <vladasp...(a)gmail.com> wrote:
>
> >>> What are alternatives? How to fix such architecture?
>
> > Model the problem -- I can't really give better advice without knowing
> > something about the problem.  Based on experience with this code
> > smell, where superclasses are pervasively controlling leaf classes, I
> > can *guess* what the general solution would look like, but I don't
> > want the general solution to be your *actual* solution.  So what
> > follows is my analysis of the meta-problem, not the problem domain
> > itself.
>
> > If you are writing code in a way such that superclasses are
> > controlling leaf classes, then you have a Specification where the
> > problem can be broken down into Stages (what you are currently using
> > classes with arbitrary names for).  If at each Stage you cannot
> > predict what the sequences of actions will be, then you also need a
> > Sequence abstraction so that each Stage is composed of Sequences.  But
> > this analysis is not complete; you need to recursively specify what
> > the specification of each stage and sequence is.  In other words, a
> > Sequence must collaborate with a SequenceSpecification and a Stage
> > must collaborate with a StageSpecification.  A StageSpecification is
> > composed of SequenceSpecifications, so that when you want to reuse the
> > Stage, you instead focus on reusing its Specification, giving you a
> > degree of freedom in how to implement the Stage by taking advantage of
> > what the Specification *doesn't* say.  This analysis will allow you to
> > *easily* apply parametric polymorphism on-demand at each Stage and
> > Sequence, as well as allow for implementation hiding.
>
> It looks like you are forming a state chart.

It's not a state chart, it is a collaboration diagram (technically,
not a diagram, since I described the solution in text).

State charts explicitly define execution semantics. What I am instead
doing is saying, you are using "class" to represent a Stage class, and
methods to represent a Sequence class, and inheritance to represent
sequential coupling. I am then saying that what you are doing is
mathematically not versionable, because you have no way to predict
paths through the system used by existing clients, especially in an
open system (e.g., not a "small in-house system" or "embedded
system").

Also, the collaboration diagram represents modeling process
refinement, whereas state charts can model reactive systems. I can
discuss the details as to why this is different some other time (or
forget about it).

> > Your current solution doesn't really allow parametric polymorphism in
> > a safe way, and it doesn't allow for implementation hiding since the
> > parent superclasses must know about their child subclasses in order to
> > properly control them.
>
> In other words, use "tell, don't ask" principle to remove the super
> classes. Correct?
>
> btw what tools are you using to model the problem?
> I modelled few things, but only on paper. Today I thought of trying
> kivio to model a problem I am facing.

I honestly don't use tools. A text editor, some auto-complete, a web
browser, a 30" monitor, and two 20" vertical monitors is all you need.
From: Garrett Smith on
johnzabroski(a)gmail.com wrote:
> On Apr 16, 9:00 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
>> Daniel T. wrote:
>>> 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.

[snip signature]

>
> Interesting. I would love examples of shitty Javascript code. Where
> should I start looking?
>

OK, but to make to make a good assessment of a piece of code, the
language, and problem context needs to be understood. A fundamental
difference with web apps is variant deployment environment. Could be
IE6, Chrome Frame, various JScript builds, Opera masking as IE, iPhone,
Blacberry 9000.

> I don't think the problem is especially unique to prototype-based
> languages like Javascript, though...

No, but there are significant problems that contribute to really bad
javascript.

There are many many ways to cause problems in code, both with strategies
and overall design.

ECMAScript is a simple but flexible and powerful dynamic language yet
taken for something that is not real programming.

RIA development is relatively new and there is much bad advice and
misinformation.

Interviews for front end engineering are hard on both ends (interviewer
and interviewee). With so much misinformation what should the
interviewer ask? What should he trust? With such a great amount of
misinformation and harmful advice, the majority of web developers hired
are really quite bad at what they do.

Variations exist in implementations of the language itself and
especially in various browser DOMs which were historically awful.

Historically, browser detection has been used to address these and other
issues. A consequential effect of that is that it obfuscates the problem.

With little information on how to solve such problems, developers turned
to javascript libraries. These things are now considered to be "de
facto" industry standard.

So with all that, lets take a look at a popular javascript library:
jQuery. No problem and no context is presented here, only the
constructor, which is oddly placed in the prototype as
`jQuery.prototype.init`.

It is not necessary to know what it is doing to see that the number of
loops and `if` and `else` statements is quite high. For those who know
the HTML DOM, it is still an eyesore to look at.

| init: function( selector, context ) {
| var match, elem, ret, doc;
|
| // Handle $(""), $(null), or $(undefined)
| if ( !selector ) {
| return this;
| }
|
| // Handle $(DOMElement)
| if ( selector.nodeType ) {
| this.context = this[0] = selector;
| this.length = 1;
| return this;
| }
|
| // The body element only exists once, optimize finding it
| if ( selector === "body" && !context ) {
| this.context = document;
| this[0] = document.body;
| this.selector = "body";
| this.length = 1;
| return this;
| }
|
| // Handle HTML strings
| if ( typeof selector === "string" ) {
| // Are we dealing with HTML string or an ID?
| match = quickExpr.exec( selector );
|
| // Verify a match, and that no context was specified for #id
| if ( match && (match[1] || !context) ) {
|
| // HANDLE: $(html) -> $(array)
| if ( match[1] ) {
| doc = (context ? context.ownerDocument || context :
| document);
|
| // If a single string is passed in and it's a single tag
| // just do a createElement and skip the rest
| ret = rsingleTag.exec( selector );
|
| if ( ret ) {
| if ( jQuery.isPlainObject( context ) ) {
| selector = [ document.createElement( ret[1] ) ];
| jQuery.fn.attr.call( selector, context, true );
|
| } else {
| selector = [ doc.createElement( ret[1] ) ];
| }
|
| } else {
| ret = buildFragment( [ match[1] ], [ doc ] );
| selector = (ret.cacheable ? ret.fragment.cloneNode(true) :
| ret.fragment).childNodes;
| }
|
| return jQuery.merge( this, selector );
|
| // HANDLE: $("#id")
| } else {
| elem = document.getElementById( match[2] );
|
| if ( elem ) {
| // Handle the case where IE and Opera return items
| // by name instead of ID
| if ( elem.id !== match[2] ) {
| return rootjQuery.find( selector );
| }|
|
| // Otherwise, we inject the element directly into the jQuery object
| this.length = 1;
| this[0] = elem;
| }
|
| this.context = document;
| this.selector = selector;
| return this;
| }
|
| // HANDLE: $("TAG")
| } else if ( !context && /^\w+$/.test( selector ) ) {
| this.selector = selector;
| this.context = document;
| selector = document.getElementsByTagName( selector );
| return jQuery.merge( this, selector );
|
| // HANDLE: $(expr, $(...))
| } else if ( !context || context.jquery ) {
| return (context || rootjQuery).find( selector );
|
| // HANDLE: $(expr, context)
| // (which is just equivalent to: $(context).find(expr)
| } else {
| return jQuery( context ).find( selector );
| }
|
| // HANDLE: $(function)
| // Shortcut for document ready
| } else if ( jQuery.isFunction( selector ) ) {
| return rootjQuery.ready( selector );
| }
|
| if (selector.selector !== undefined) {
| this.selector = selector.selector;
| this.context = selector.context;
| }
|
| return jQuery.makeArray( selector, this );
| },

No for loops in that method, but a combined total of 21 if and else
statements over 104 SLOC. That is the entry point for most jQuery
programs and it is one of the simpler and more clearly defined methods.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/

From: johnzabroski on
On May 14, 5:38 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> johnzabro...(a)gmail.com wrote:
> > On Apr 16, 9:00 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> >> Daniel T. wrote:
> >>> 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.
>
> [snip signature]
>
>
>
> > Interesting.  I would love examples of shitty Javascript code.  Where
> > should I start looking?
>
> OK, but to make to make a good assessment of a piece of code, the
> language, and problem context needs to be understood. A fundamental
> difference with web apps is variant deployment environment. Could be
> IE6, Chrome Frame, various JScript builds, Opera masking as IE, iPhone,
> Blacberry 9000.
>
> > I don't think the problem is especially unique to prototype-based
> > languages like Javascript, though...
>
> No, but there are significant problems that contribute to really bad
> javascript.
>
> There are many many ways to cause problems in code, both with strategies
> and overall design.
>
> ECMAScript is a simple but flexible and powerful dynamic language yet
> taken  for something that is not real programming.
>
> RIA development is relatively new and there is much bad advice and
> misinformation.
>
> Interviews for front end engineering are hard on both ends (interviewer
> and interviewee). With so much misinformation what should the
> interviewer ask? What should he trust? With such a great amount of
> misinformation and harmful advice, the majority of web developers hired
> are really quite bad at what they do.
>
> Variations exist in implementations of the language itself and
> especially in various browser DOMs which were historically awful.
>
> Historically, browser detection has been used to address these and other
> issues. A consequential effect of that is that it obfuscates the problem.
>
> With little information on how to solve such problems, developers turned
> to javascript libraries. These things are now considered to be "de
> facto" industry standard.
>
> So with all that, lets take a look at a popular javascript library:
> jQuery. No problem and no context is presented here, only the
> constructor, which is oddly placed in the prototype as
> `jQuery.prototype.init`.
>
> It is not necessary to know what it is doing to see that the number of
> loops and `if` and `else` statements is quite high. For those who know
> the HTML DOM, it is still an eyesore to look at.
>
> | init: function( selector, context ) {
> |    var match, elem, ret, doc;
> |
> |    // Handle $(""), $(null), or $(undefined)
> |    if ( !selector ) {
> |      return this;
> |    }
> |
> |    // Handle $(DOMElement)
> |    if ( selector.nodeType ) {
> |      this.context = this[0] = selector;
> |      this.length = 1;
> |      return this;
> |    }
> |
> |    // The body element only exists once, optimize finding it
> |    if ( selector === "body" && !context ) {
> |      this.context = document;
> |      this[0] = document.body;
> |      this.selector = "body";
> |      this.length = 1;
> |      return this;
> |    }
> |
> |    // Handle HTML strings
> |    if ( typeof selector === "string" ) {
> |      // Are we dealing with HTML string or an ID?
> |      match = quickExpr.exec( selector );
> |
> |      // Verify a match, and that no context was specified for #id
> |      if ( match && (match[1] || !context) ) {
> |
> |        // HANDLE: $(html) -> $(array)
> |        if ( match[1] ) {
> |          doc = (context ? context.ownerDocument || context :
> |                                                      document);
> |
> |          // If a single string is passed in and it's a single tag
> |          // just do a createElement and skip the rest
> |          ret = rsingleTag.exec( selector );
> |
> |          if ( ret ) {
> |            if ( jQuery.isPlainObject( context ) ) {
> |              selector = [ document.createElement( ret[1] ) ];
> |              jQuery.fn.attr.call( selector, context, true );
> |
> |            } else {
> |              selector = [ doc.createElement( ret[1] ) ];
> |            }
> |
> |          } else {
> |            ret = buildFragment( [ match[1] ], [ doc ] );
> |            selector = (ret.cacheable ? ret.fragment.cloneNode(true) :
> |                                              ret.fragment).childNodes;
> |          }
> |
> |          return jQuery.merge( this, selector );
> |
> |        // HANDLE: $("#id")
> |        } else {
> |          elem = document.getElementById( match[2] );
> |
> |          if ( elem ) {
> |            // Handle the case where IE and Opera return items
> |            // by name instead of ID
> |            if ( elem.id !== match[2] ) {
> |              return rootjQuery.find( selector );
> |            }|
> |
> |    // Otherwise, we inject the element directly into the jQuery object
> |            this.length = 1;
> |            this[0] = elem;
> |          }
> |
> |          this.context = document;
> |          this.selector = selector;
> |          return this;
> |        }
> |
> |      // HANDLE: $("TAG")
> |      } else if ( !context && /^\w+$/.test( selector ) ) {
> |        this.selector = selector;
> |        this.context = document;
> |        selector = document.getElementsByTagName( selector );
> |        return jQuery.merge( this, selector );
> |
> |      // HANDLE: $(expr, $(...))
> |      } else if ( !context || context.jquery ) {
> |        return (context || rootjQuery).find( selector );
> |
> |      // HANDLE: $(expr, context)
> |      // (which is just equivalent to: $(context).find(expr)
> |      } else {
> |        return jQuery( context ).find( selector );
> |      }
> |
> |    // HANDLE: $(function)
> |    // Shortcut for document ready
> |    } else if ( jQuery.isFunction( selector ) ) {
> |      return rootjQuery.ready( selector );
> |    }
> |
> |    if (selector.selector !== undefined) {
> |      this.selector = selector.selector;
> |      this.context = selector.context;
> |    }
> |
> |    return jQuery.makeArray( selector, this );
> |  },
>
> No for loops in that method, but a combined total of 21 if and else
> statements over 104 SLOC. That is the entry point for most jQuery
> programs and it is one of the simpler and more clearly defined methods.
> --
> Garrett
> comp.lang.javascript FAQ:http://jibbering.com/faq/

Garrett.

Thanks for taking the time to reply.

I tend to agree that many GUIs are not as purely object-oriented as
their marketing teams say they are.

WPF is a good example. I've written several blog posts about design
flaws in WPF[1], and how it allows permiscuous access to effectively
global objects. What is most interesting is that WPF's dependency
change propagation subsystem actually doesn't like random ranges to
global objects, and doing so brings the system to its knees. The
Visual Studio 2010 product team quickly "discovered" this [2]. I also
discuss RIA models on my blog, at least once (that I can remember),
disecting a particular "architecture" I did not like because it had no
way to handle partial failure, or fail gracefully [3]. I also wrote a
blog post about how to design data presentation controls in a modular
fashion, but never really got around to explaining the OO solution of
converting a dynamic behavior problem into a dynamic relationship
participation problem [4]

[1] http://z-bo.tumblr.com/post/113891179/wpf-design-flaws-part-1
[2] http://blogs.msdn.com/visualstudio/archive/2010/03/02/wpf-in-visual-studio-2010-part-2-performance-tuning.aspx
[3] http://z-bo.tumblr.com/post/246854981/what-is-sofea-what-is-soui
[4] http://z-bo.tumblr.com/post/378279345/re-gridview-with-variable-number-of-columns