tag:robotlegs.tenderapp.com,2009-10-18:/discussions/problems/222-lighter-faster-workflow-for-robotlegs-might-be-betterRobotlegs: Discussion 2018-10-18T16:35:20Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T08:19:06Z2015-10-19T23:47:53ZLighter & Faster workflow for robotlegs: might be better?<div><p>I am likely to be shot down by the SoC gods for this, however I
really like this method you have outlined.</p>
<p>I in fact am using this exact method in several of my personal
projects at the moment. I use the viewMap in the context to map my
views directly. I then have models directly injected into the
views. This way I can then bind to properties on my model / proxy
without being forced to wrap a single proxy variable in a VO simply
so I can bind to it.</p>
<p>I do use commands still for some of the larger calls and calls
with no particular owner. I try to group all functionality that
directly involves that Model/Proxy inside of there and if there are
any methods that dont strictly belong to that proxy or to any other
proxy ill make a command for it. It just seems to make sense for
me. I also like to use commands for async processes that could be
fired multiple times such as calls to the server.</p>
<p>For me personally, this method works. It brings a nice level of
separation (in my head anyways) but at the same time isnt so
verbose that it makes me feel like the framework is bogging me down
forcing me to jump through hoops to get a simple thing done.</p>
<p>I have to thank the RobotLegs team for doing such a great job
when constructing the framework, allowing this level of flexibility
to modify it as you choose!</p></div>mike.canntag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T10:04:26Z2010-11-24T10:04:26ZLighter & Faster workflow for robotlegs: might be better?<div><p>Injecting into views?? Yikes! Now your views are coupled to your
application logic. Really views shouldn't care what the model API
is, they should only care how to do their view stuff.</p>
<p>Where I think we differ is that us SoC disciples (who will call
on our gods to unleash a plague of frogs on you later) believe it's
faster and easier to work with code that does just one thing and is
decoupled from other classes as far as possible.</p>
<p>When, later, you change that model API, you'd have to change ALL
the views it's injected into. Or you're fighting with legacy code
because you can't change it because the change would be too labour
intensive.</p>
<p>And it's really not very easy to do TDD that way ... but if
you're not on that bus either then I guess that doesn't matter.</p>
<p>But... if it works then it works. And if there's one thing
robotlegs isn't, it's prescriptive. Proceed with caution though...
and keep some painkillers handy.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T10:43:45Z2015-10-19T23:47:54ZLighter & Faster workflow for robotlegs: might be better?<div><p>Haha I didnt think the gods would look too kindly on this :P</p>
<p>I think the method that webdesignporto is talking about means
that the skin has no knowledge about the model / proxy itself and
so there is a sepparation there between the presentation part of
the view and model itself. In his method (and mine) the view
components in effect become the mediators taking on the responsibly
of view to application communication in addition to providing the
data for the presentation to function.</p>
<p>As for TDD, well you know me Stray, I havent yet worried about
that world (I intend to soon tho I promise!) and I suspect you
would be correct it may make things harder to test.</p>
<p>For me the last year or so has been a journey through design
patterns trying to find the one that is the best fit for the way I
like to work. This is simply the latest iteration, should I
suddenly, or more likely, over a period of time find a situation
where this method breaks down ill look for a better way of doing
things.</p>
<p>I guess im just a big-headed programmer who needs to make the
mistake himself to see the right way :P</p></div>mike.canntag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T10:57:36Z2010-11-24T10:57:36ZLighter & Faster workflow for robotlegs: might be better?<div><blockquote>
<p>the view components in effect become the mediators taking on the
responsibly of view to application communication in addition to
providing the data for the presentation to function.</p>
</blockquote>
<p>Your poor views! So many responsibilities! The should be
contacting their union and demanding a pay rise.</p>
<p>It's fine to have to bash your own head :)</p>
<p>What you're really doing is using less framework. It's DI +
signals + signalCommandMap.</p>
<p>I can see that in games, cutting out the middle man might be
useful in terms of speed increase for the user. But... can you at
least use an injected Signal or SignalBus and stop injecting those
models into the views? If you use a request-and-response signal
then you're only bound to the signal's signature and not the model
itself.</p>
<p>Oh.. I just had an idea for a blog post. Nice one!</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T11:20:18Z2010-11-24T11:20:18ZLighter & Faster workflow for robotlegs: might be better?<div><p>@Stray: The problem I'm having is this:</p>
<p>My component dispatch the loginSignal. Mediator catches and
redispatches the same loginSignal, but this one is the injected
one. So in this is already I repetition that I don't really
need!<br>
Then when the injected loginSignal is dispatched the command
logingCommand catches it, in it is inserted the loginVO, that
contain the email, password and rememberMe. Then the loginCommand
call the login method on the authorization model class. Then the
authorization model dispatch the event loginSuccess. The
loginMediator catches it and edit the component.</p>
<p>This is really really sick! xD</p>
<p>The way I'm thinking to do is:<br>
The skin listen for user interraction. Then dispatch events to the
component. The component make some business login and then access
the authorization.login(loginVO). Then when the model updates
notify the user...</p>
<p>That is a lot faster and easier to change!</p>
<p>Imagine in the first case I want to change the login method to
loginMeNow.<br>
1) change signal variables name in the view, mediator, context and
signal class name;<br>
2) The name of the method in the model;<br>
3) The loginVO to loginMeNOwVO;<br>
4) Command name to loginMeNowCommand;<br>
5) The method I call on model from command;<br>
5) change the signal that model dispatches;<br>
maybe more..</p>
<p>In my approach you have to change:<br>
1) The method name to loginMeNow on the authorization;<br>
2) change the value object like in the old way;<br>
3) change the method I call on the view;<br>
4) change the signal that model dispatches;</p>
<p>I think you don't want to compare the time and the attention you
need in order to change just this thing. Then to add another method
on the model and to call it you would need to create a new signal,
command, map the signal to command and a lot of sick things! no
dry, just a lot of unusefull repetition...</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T11:22:16Z2010-11-24T11:22:16ZLighter & Faster workflow for robotlegs: might be better?<div><p>@Mike Cann: Yes that's right the skin is just mxml and do not
have any business logic. Read my last comment..</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T11:25:24Z2015-10-19T23:47:54ZLighter & Faster workflow for robotlegs: might be better?<div><p>Ha! My views like the added responsibly it allows them to have
all the data they need to make the view look pretty and update
automatically thanks to [bindable], they are also able to have a
word with the model if they need to make a quick change.</p>
<p>Well I am using less of the framework I suppose however the
framework is essentail for mapping the views, commands and proxys
and performing the automatic injection magic that glues it all
together.</p>
<p>Cutting out the middleman just gets me there a little faster.
SignalBus eh? Yes I would certainty like to hear more about
this!</p></div>mike.canntag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T11:36:23Z2010-11-24T11:36:23ZLighter & Faster workflow for robotlegs: might be better?<div><p>Can you explain how is the workflow is in your application, or
just an example of it?</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T11:39:09Z2015-10-19T23:47:54ZLighter & Faster workflow for robotlegs: might be better?<div><p>@webdesignporto I think this is where you and I differ
slightly.</p>
<p>With respect to your login example I may be tempted to use a
command or service in this instance.</p>
<p>What I think you are suggesting is to remove the "eventBus" type
architecture altogether and just have whatever needs to listen for
the "loginSuccess" signal on the model. The problem I see with this
is that now anything else that needs to listen for a "loginSuccess"
now has to have a reference to the "LoginModel" or whatever its
called.</p>
<p>What I personally would do was have the "LoginModel" or perhaps
"LoginService" dispatch an appication level event/signal to the
eventBus which can then be picked up by the view/mediator or
whatever else needs to know about this.</p>
<p>I agree with you however that verboseness is 'sick' however
sometimes you have to make the trade between spaghetti and
verboseness.</p></div>mike.canntag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T12:01:52Z2010-11-24T12:01:52ZLighter & Faster workflow for robotlegs: might be better?<div><p>I create the VO in the mediator.</p>
<p>So the view dispatches a login(username, password) signal.</p>
<p>The mediator creates the loginVO(username, password)</p>
<p>I use events still for my in-application communication in some
instances, signals in others. So - the mediator dispatches the
LoginEvent.LOGIN_REQUESTED and a command picks that up, passes it
to the service and away we go.</p>
<p>I don't think that's gross... if I needed to change my VO I'd
have to change it only in 2 places - the mediator and the service.
(And my tests, but that's why I use support class wrappers around
VOs etc used by the test.)</p>
<p>If an object is created someplace and used someplace else, I
don't see how you can get away from that?</p>
<p>I also think that verboseness is 'sick' - but I think I'm using
it in a different sense of the word!</p>
<p>The point of separation of application logic and view logic is
that your view and application can then be varied separately. If
you don't mind that your layers are coupled together in ways that
mean that you can't change the application without also changing
the view then that's not going to be important to you.</p>
<p>It really all depends on the scale and purpose of your app...
the size of the team etc.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T12:08:44Z2010-11-24T12:08:44ZLighter & Faster workflow for robotlegs: might be better?<div><p>The mediator in order to listen for the signal dispached by the
model must have a reference to the injected signal; so no much
diference anyway... or I'm missing something?</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T12:33:32Z2010-11-24T12:33:32ZLighter & Faster workflow for robotlegs: might be better?<div><p>It's not listening to the model - it's listening to the
view.</p>
<p>But also - yes, there is a <em>huge</em> difference between
injecting a signal into your mediator (which I do do) and injecting
into your view.</p>
<p>Injecting the model in the view is horrible coupling - the view
is coupled to the model.</p>
<p>Injecting a signal that is wired to the model into the view is a
much cleaner approach - now the view is only coupled to a signal,
and as long as something is on the other end of the signal it
doesn't care what that is.</p>
<p>But - the view still relies on an external player to be
viable.</p>
<p>With the mediator in place, the view can be totally self
contained. It can be developed and tested in isolation. Any changes
affecting the application can be dealt with in the mediator.</p>
<p>Lots of small classes that all have a clear responsibility -
it's more testable and each class can be developed and then closed.
The focus of each class is smaller, and so it follows that the
focus of the developer is smaller while writing that code. It's an
approach that helps to dilute the complexity of app development by
breaking it into chunks which have very low complexity.</p>
<p>But.. if what you're really talking about is the presentation
model pattern, then I think it's accepted by those who use it to
use a 2 layer system: mxml/PM</p>
<p>The big gain is injecting the signal not the model.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T12:51:52Z2010-11-24T12:51:52ZLighter & Faster workflow for robotlegs: might be better?<div><p>But my view is the skin. The component is like a controller in
the mvc.</p>
<p>What is tight to what in my app:</p>
<p>My way: the component is tight to a model and a skin, but I can
still change the models and skins.</p>
<p>Your way: the mediator is tight to the view;</p>
<p>Then, my component is tight to a model;<br>
Your mediator is tight to a signal, if you use signals of course. I
don't even remember how it was using events. Your's is less tight,
but you must put a lot of signals for each method on the
model..</p>
<p>So if my model method name changes your signal must change
too.<br>
If I add a new mehod on the model, you must add a new signal.</p>
<p>And yes, the only thing I think is better in your approach is
that you can test parts quite easier...</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T13:06:09Z2010-11-24T13:06:09ZLighter & Faster workflow for robotlegs: might be better?<div><p>My views/mediators have no coupling at all to the model API. If
a signal is injected then it's created elsewhere and injected into
both the mediator and the model (not always through [Inject] -
sometimes just a setter). My mediator is coupled to the signal, and
the view of course. That's kind of the point of mediators - there's
no way to have zero coupling, so isolating it in known places is
good.</p>
<p>I don't have a lot of signals on the models - they mostly would
just have 'updated' and pass a VO of current state.</p>
<p>It's not really about better / worse (and I really was only
responding to your question which asked whether your approach was
sound - perhaps you only wanted confirmations and not challenges?)
- it's about what's appropriate for the journey you're on. If
you're building an app in a few days or a week then you can get
away with all sorts of things that would be traps on a year-long
project. If you have multiple developers you need a different
approach to if it's just yourself.</p>
<p>Ok - so your view is the skin, and your PM is what you're
calling 'view' previously. PM (as I understand it - I never use it)
uses signals dispatched by the PM, and updates through
bindings.</p>
<p>Why does more classes == bad? A lot of Uncle Bob's refactorings
result in more code, not less code, but the code is easier to
change and follow.</p>
<p>It all depends what you think your bottle neck is. For me,
typing and making classes is never, ever my bottle neck. It is
always <em>thinking</em> that is the hard part. And really
following the Single Responsibility Principle massively reduces the
amount of thinking I have to do in each class - and I spend most of
my time writing the app, not architecting it.</p>
<p>Perhaps you are just quicker at thinking than me!</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T13:48:52Z2015-10-19T23:47:54ZLighter & Faster workflow for robotlegs: might be better?<div><p>Oh Stray is so good! She almost has me converted from my wicked
ways but not quite yet.</p>
<p>I dont think any sane coder would disagree with the theory
behind the Single Responsibility Principle however getting to that
nirvana may unacceptable trade offs be it in production or
performance time.</p>
<p>I suppose time will tell if my 'shortcuts' will end up biting me
in the behind :P</p></div>mike.canntag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T16:11:13Z2010-11-24T16:11:13ZLighter & Faster workflow for robotlegs: might be better?<div><p>In my case I have this:</p>
<p>ListsModel<br>
-getListsForUser(userKey) -getListsForCurrentUser()
-deleteList(listKey) -addNewList(listVO) -deleteList(listKey)</p>
<p>Then I must make a signal and command for each method. To change
it, is really painfull and to wrap my mind like this is too much
for me.<br>
skin-<em>>component-</em>>mediator-<em>>command->model->service->server->service->parser->service->model-</em>>mediator->component->skin</p>
<p>thinking that all -*> are based on signals/events... it's ust
too hard. I've already done it, and not really usefull for me. It
is decoupling everything.</p>
<p>I think is possible to do, but is too rigid, what i mean with
this is that to make changes you have to change a lot of
code...</p>
<p>I would like to know what other downsides might have my approach
in large apps?</p></div>webdesignportotag:robotlegs.tenderapp.com,2009-10-18:Comment/39564622010-11-24T23:53:49Z2010-11-24T23:53:49ZLighter & Faster workflow for robotlegs: might be better?<div><p>I just built my simple framework..<br>
I will test on it and I will make you know how it woks. Inspired
from robotlegs, a lot! xD</p>
<p>package ***{<br></p>
<pre>
<code>import flash.display.DisplayObjectContainer;
import flash.events.Event;
import org.swiftsuspenders.Injector;
import org.swiftsuspenders.Reflector;
public class Context{
protected var _targets:Array = [];
protected var _injector:Injector;
protected var _reflector:Reflector;
protected var _injectionsMap:InjectionsMap;
public function Context(){
_injector = new Injector();
_reflector = new Reflector();
_injectionsMap = new InjectionsMap();
_injector.mapValue(Injector, _injector);
_injector.mapValue(Reflector, _reflector);
_injector.mapValue(InjectionsMap, _injectionsMap);
_injector.injectInto(_injectionsMap);
startup();
}
public function startup():void{
// override in your context
}
public function mapComponent(component:*):void{
_injectionsMap.add(component);
}
public function mapModel(model:*):void{
mapSingleton(model);
}
public function mapSingleton(whenAskedFor : Class, named : String = ""):void{
_injector.mapSingleton(whenAskedFor, named);
}
public function mapSingletonOf(whenAskedFor:Class, useSingletonOf:Class, named:String = ""):*{
return _injector.mapSingletonOf(whenAskedFor, useSingletonOf, named);
}
public function set addTarget(value:DisplayObjectContainer):void{
_targets.push(value);
value.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, true, 0, true);
}
protected function addedToStageHandler(event:Event):void{
_injectionsMap.injectInto(event.target);
}
}</code>
</pre>
<p>}</p>
<p>AND</p>
<p>package ***{<br></p>
<pre>
<code>import org.swiftsuspenders.Injector;
import org.swiftsuspenders.Reflector;
public class InjectionsMap{
[Inject]
public var injector:Injector;
[Inject]
public var reflector:Reflector;
protected var _mappedComponents:Array = [];
public function InjectionsMap(){}
public function add(component:Class):void{
var i:int = 0;
for(; i < _mappedComponents.length; i++){
if(reflector.getFQCN(component) == _mappedComponents[i]){
return;
}
}
trace('Will inject into, when added: ' + reflector.getFQCN(component));
_mappedComponents.push(reflector.getFQCN(component));
}
public function injectInto(component:*):void{
var i:int = 0;
for(; i < _mappedComponents.length; i++){
if(reflector.getFQCN(component) == _mappedComponents[i]){
trace('Injecting into: ' + reflector.getFQCN(component));
injector.injectInto(component);
}
}
}
}</code>
</pre>
<p>}</p>
<p>----- end of the framework ---- MainContext.as<br>
override public function startup():void{<br></p>
<pre>
<code> // components
mapComponent(LoginComponent);
mapComponent(WorldComponent);
// models
mapModel(AuthorizationModel);
mapModel(AccountModel);
mapModel(WindowModel);
// signals
}</code>
</pre>
<p>fast and easy! (:</p></div>webdesignporto