On Saturday, November 18, 2017 at 9:20:31 AM UTC-6, Edward K. Ream wrote:

On Saturday, November 18, 2017 at 6:58:46 AM UTC-6, vitalije wrote:
>
> Your questions and suggestions are excellent, and show deep understanding 
> of the code.  However, I think the present code, even with its flaws, is 
> slightly preferable. YMMV.
>

I truly appreciate such questions.  They challenge me to reconsider my 
normal way of thinking.

*tl;dr:* Read the summary

When I awoke this morning I had several addition thoughts.

1. The DRY principle can lead one astray by suggesting that we group 
statements together that have no other purpose than they *happen to be 
shared* in various, possibly unrelated, pieces of code.

The great Glenford J. Meyers warned of this kind of code sharing in various 
writings, including his 1978 book, Composite/Structured design. Used copies 
of this book are still available for about $5. This was before any language 
had classes!  Nowadays I suspect that most people learn design from 
studying existing classes, but I wonder how well the principles of 
designing classes are understood.

Meyers advocated that all code have the strongest possible "binding 
strength". The top two he called "functional" and "informational" 
strength.  The weakest form of binding is "coincidental" strength. An 
example is code that just happens to be shared in several places.  

Here are some quotes. In these quotes "module" could mean either a python 
module or class or function.

Page 35: A *functional strength module* that performs a single specific 
function.

Page 36: It is often the case that a program constructed with 
functional-strength modules still does not have a maximally independent 
structure...The *informational strength module*...[hides] some concept, 
data structure or resource within a single module.

Imo, hiding details is the master design principle behind program design. *We 
want various classes to know as little as possible about all other classes.* 
All will be well when this is true. We must avoid cross-class dependencies 
whenever possible.

So this is one reason why I am leery of having the plugins manager handle 
settings.  It creates a cross-class dependency.

2. There is exactly one method that handles every Leo command. Each of 
these methods has full and complete responsibility for *all* aspects of the 
command's implementation. This responsibility can not really be delegated. 
In the present discussion, c.open and c.openRecentFile are the command 
handlers.

*From a design standpoint, it really doesn't matter how complicated these 
methods are.* If we can devise *well designed* helpers that simplify the 
code then all the better.  But those helpers must have 
functional/informational binding strength.  And we don't want to pollute 
any other class with details best handled squarely by the command handlers.

3. The last reason I resist the notion of putting code into the plugins 
manager is that there arises the possibility that the plugins manager will 
call the settings-related code too often.  I'm not sure what that 
possibility is, *and that's exactly the point*. I don't want to create any 
kind of hidden dependency or assumption between the plugins manager class 
and various Leo commands.  *Far better*, imo, to duplicate the required 
code in c.open and c.openRecentFile.  Even if initially I haven't covered 
all the bases, the proper solution is to deal with the complexity in 
whatever command handler is created or found.

4. Thinking about these issues suggests refactoring k.registerCommand into 
two pieces.  The new k.registerCommand would reject, with a warning, any 
attempt to set a binding. This warning is necessary because we don't want 
to break existing code and we want to provide a clear migration path to the 
new code.

At present, several pieces of code *legitimately* set the binding, 
including the mod_scripting plugin and the code that creates the Open With 
menu.  The solution would be to have these call a *new* method, say 
k.setBindingForCommand.  Details are fuzzy, but I think the refactoring 
makes sense.  It will greatly simplify k.registerCommand in the typical 
usage.

5. The question about binding wrappers got me thinking about the IPython 
traitlets module, <https://github.com/ipython/traitlets> and the 
simplification it brings to their code.  One result of this pattern is that 
few (no?) jupyter/ipython classes have ctors!  Most ivars can be defined as 
class ivars.

Leo is not going to use anything like traitlets, for several reasons.  Most 
importantly, it would be too big a change in the code base for way too 
little gain.  Still, it's good to think of what might have been...

*Summary*

Leo's design is sound, flexible and robust because:

1. Classes knows nothing about any other class.

2. There is a single *command method* for each Leo command, and that method 
is responsible for *all* implementation details of the command.  Each 
command method knows *everything* about the implementation of the command, 
and *no other code anywhere knows anything about such details*.

This is likely the clearest summary Leo's design that I have ever devised.  
Many thanks for the inspiration to create it.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to leo-editor+unsubscr...@googlegroups.com.
To post to this group, send email to leo-editor@googlegroups.com.
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to