Hi Jake,

Thank you for the feedback! You raise some very important concerns and
tradeoffs in the design of the API. My short answer is that most of
the aspects you raised comes out of the goal of the library being in
creating a dynamic-aspect-oriented framework and arose from the API
evolved to solve real problem I encountered when developing and using
the API, but I'll go into more detail, provide use cases, and you can
judge whether there are better solutions to the problems!

Comments (KM>) inline....


On Oct 12, 5:19 pm, Jake Verbaten <rayn...@gmail.com> wrote:
> I have no (big) problems with reading coffeescript, i didnt look at your
> compiled coffeescript (being forced to read that would be murderous rage).
>
> Let's take a look at your example, I've replaced your example with my own
> mixin method (pd.mixin <https://github.com/Raynos/pd#pd.mixin>)
>
> // use pd to make example simple :https://github.com/Raynos/pd
> pd.extendNatives();
>
> var SuperStar = {
>     constructor: function _construct() {
>         this.fans = [];
>     },
>     addFan: function _addFan(fan) {
>         this.fans.push(fan);
>         return this;
>     },
>     getFans: function _getFans() {
>         return this.fans;    
>     }
>
> };
>
> var RockStar = {};
> pd.mixin(RockStar, SuperStar);
>
> // yes Object.prototype.new -https://github.com/Raynos/pd#pd.extendNatives
> // is awesome
> var rockstar1 = RockStar.new();
>
> var Fan = {};
> var fan1 = Fan.new(), fan2 = Fan.new();
> rockstar1.addFan(fan1).addFan(fan2);
> console.log(rockstar1.getFans());
>
> Live Example <http://jsfiddle.net/nJbXW/1/>
>

KM> I've looked at your library and examples. Unfortunately, I
actually updated the Rockstar example in the README (https://
github.com/kmalakoff/mixin) after posting it here to demonstrate the
dynamic nature of the proposed system (basically dynamically adding/
removing mixins to instances on the fly). Also, the example was design
to demonstrate the API in a concise way, not to provide an advanced
use case to justify the purpose of the library (classic disconnect
between real-world problems and examples). I believe the problem you
are trying to address is improving the OO nature of Javascript,
whereas, the library I am proposing is trying to address a slightly
different problem space that could be described as "dynamic aspect-
oriented programming". In other words, allowing the library user to
respond dynamically to situations and importantly, give them a
convention for cleaning up.

In some situations, what I propose is unnecessary/overkill and in some
situations it fits the bill (but of course, there will always be
different ways to solve the same problem) - I included the
subscriptions mixin as a more advanced example. I'll try to explain
these design considerations in responding to your points below.


> Now let's take a moment to go back to the API methods you've shown in your
> example.
>
> *Mixin.registerMixin *
>
> Why would you want to register a mixin by string name? A mixin should just
> be an object.

KM> Originally I was using objects. The problem I ran into was that I
was using CommonJS that required a path to the object so when I
packaged the library and sample mixins I needed to 1) find a way to
provide users the flexibility to pick and choose which mixins they use
and 2) to not force a specific directory and file structure for them
but let them choose how they lay things out. The answer I came up with
was "named loose coupling" but if there is a better solution, I'm
happy to apply it - just let me know.

KM> Use case: one user doesn't use CommonJS and all of their mixins
are in the global namespace; another users uses CommonJS and layouts
out their mixin files in "vendor", and a different user puts other
people's mixins under "vendor/mixin" and their own mixins in a lib
folder: "lib/my_mixins"

>
> *Mixin.initialize*
>
> The object you "register" has properties like it's name (why should it have
> a name, just use the object reference)
> It also has an initialize method, why can't that live on the object (my
> personal preference is using `.constructor`)

KM> Naming conventions aside, there are few reasons for this
initialize and destroy being outside the object actually being mixed
in:

1) The library is designed to flatten an OO hierarchy using aspects
("aspect" was another name I was considering for the library instead
of "mixin") and each aspect can be mixed in and out by the library
user when they need. Each time the mixin or mixout happens, the mixin
has an opportunity to initialize and cleanup. For example, in much of
my code, I use Backbone.Events and jQuery so I bind and unbind events
on the fly when mixin in and out.

2) I decoupled the initialize method and put it outside the object was
to avoid clobbering between mixins and to not have a fixed new/destroy
call order, but something on-the-fly and dynamic.

KM> Use cases: in the subscriptions mixin, an Observor can dynamically
upgrade an object to have the Subscriber mixin so if their one is
destroyed, they automatically cleanup their links to one another. So a
Subscriber doesn't need to know beforehand that it will become a
subscriber and not all instances of the subscriber class need this
functionality and so the cleanup code is only the ones that actually
subscribed to something during their lifetime (not all instances of
the same "class").

>
> *Mixin.in*
>
> Yes you need that, but why can't this just be `Mixin`.

KM> I agree that it is not really an optimal decision for the most
used function in the library, but I made this decision mainly because
of API symmetry with Mixin.out but also to try to cleanly define
namespaces and have everything hang off of one root called Mixin. Of
course, the root could also be the mixin function itself.

> Also why are you mixin it into instances of classes instead of the classes
> themself. That's just rage. A mixin should be done on a class not on every
> instance

KM> Same answer as to the difference between OO and dynamic aspect-
oriented programming and why there is an initialize/destroy not in the
actual object. You wouldt need to buy into the use cases for dynamic
aspect composition over OO hierachy where each instance may have
different compositions, nor the need to cleanup after each mixin.
KM> Use case: on-the-fly I adapt Knockout dependent observables
handlers based on the actual type of object being observed. To the
library user, they are just creating a handler, but behind the scenes
the handler is being adapted and cleaned up in a custom way with
different dynamic mixins based on what is actually being observed.

>
> *Mixin.instanceData
>
> *Why? Seriously, what's wrong with `this.fans = []` why must I store some
> data in your framework.

KM> This was a decision to avoid property clashes among independent
mixin library writers. It quickly became apparent that if the system
is generalized and people independently write mixins, there will be an
increased probability that their properties will clash. Of course,
this doesn't *force* anyone to do anything, it just provides a
mechanism for avoiding property clashes if a mixin author believes
there is a high risk.

Use case: you write a mixin for superstars and I write a mixin for
building ventilation management. We both want to use a property called
fans = []

Thats verbose and frustrating.
KM> There is also a shorter version of the API Mixin.iD()

>
> *Mixin.out*
>
> Sorry, what. Why would you ever want to remove a mixin?

KM> This function is the way you invoke destroy on a specific mixin
(eg. the symmetry between Mixin.in <-> Mixin.out). I could have called
it Mixin.destroy, but given that you and mixin and mixout, the naming
seemed more self-evident and internally consistent. Also, in my own
code, I use one of three life cycle models: "classes" that require no
cleanup, new/clone/destroy or new/retain/release so Mixin.out is
mainly useful for the last two, but you can cleanup a mixin manually
in any case by calling Mixin.out on any instances (for example, those
that don't follow one of the final two conventions).

KM> Use case: you can mixin (Mixin.in) a specific set of user
interface elements to a view, bind their jQuery events, etc; then
remove and unbind them (Mixin.out) when the user chooses a sub menu,
and then mix them back in when they return (Mixin.in), and finally
when your view is destroyed at the end of its lifetime, clean up
(Mixin.out).


> Now basically, You have a lot of over engineered useless methods on your
> library.
>
> I'm sure there are "some reasons" why they exist but I dont think these
> reasons are _any good_. Your going to have to convince people that they
> exist
> for a good reason.

KM> I'm not sure if my use cases have convinced you of the benefits of
dynamic aspect-oriented programming. I think your criticisms really
"hit many nails on the head" and properly raise the question of is
this library over-engineered or at the right level of complexity given
the problems it is designed to solve. I've been using it for 3 months
on my personal project so I don't have the perspective and am a little
enamored by the power and flexibility of the library, but (going back
to the nails) - I might be in a situation of "a man with a hammer sees
every problem as a nail"...many cases do not require this full
functionality, but since it is here, I'm using it generally for
classic Javascript mixins in addition to dynamic aspect-oriented
programming.

>
> Normally the place where you "convince" people these methods have a real
> purpose is in your (non-existant) documentation.

KM> I think you can say "sparse", but "non-existant" is a little
strong ;-)   Personally, I prefer to look at tests for examples on how
to use a library so I really put my focus there and tried to draw the
user in the readme to use the tests as reference, but I have also
tried to provide various forms of documentation (1) the tests folder
has both unit and integration tests (2) there is the README itself (3)
there is a docs folder with the project (4) there is my blog:
http://braincode.tumblr.com/ and (5) I set up an examples project
(https://github.com/kmalakoff/examples-kmalakoff). What do people
prefer in terms of documentation anyways?

I really appreciate this feedback. Hopefully, I have been able to
explain the goals of the library and the use cases it is trying to
address. Are you convinced? Either way, I would really like to
understand why or why not.

Cheers,

Kevin

-- 
To view archived discussions from the original JSMentors Mailman list: 
http://www.mail-archive.com/jsmentors@jsmentors.com/

To search via a non-Google archive, visit here: 
http://www.mail-archive.com/jsmentors@googlegroups.com/

To unsubscribe from this group, send email to
jsmentors+unsubscr...@googlegroups.com

Reply via email to