Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1] 2
Print
Author Topic: Bulky Modules  (Read 25569 times)
saad
Sr. Member
****
Posts: 65


View Profile Email
« on: June 06, 2015, 10:03:04 »

In context of a REST based server multicore app (node.js, express.js), the application under progress is getting bulky and complex because of too many operations involved within each module and since all these operations are related to this single entity (database entity) it doesn't feel intuitive to split them out into several submodules, (besides I've several modules already for other entities).

Starting with 4 CRUD operations (GET, POST, PUT, DELETE), for each there's an AsyncCommand with it's associated AsyncProxy. Adding PATCH support will add another couple.

On top of that some modules may require file upload, although the operation is redirected right from the RouterMediator and piped towards S3Module (Amazon S3 file storage) but then the sender module itself will require S3ResultCommand to handle results (4 kinds of results), or in other words every other module supports different actions/names and therefore requires a Command to handle those results.

Any additional requirement may force another couple of Async Command/Proxy into the module.

Every CRUD AsyncCommand (triggered from the view/RouterMediator/Router), triggers asyncAction of it's associated AsyncProxy, that pools the connection, gathers params from the body, headers, queryString etc., executes SQL, calls the the result/fault within the Proxy, releases the connection there and then responds back to the AsyncCommand so it could shuttle the results to the View layer (browser output).

So even combing above operations into fewer actors will make those actors bulky, plus there could be content negotiations factors that would require me to have different SQL calls in each actor, so I'd rather keep actors following SingleResponsibility Principle.

No problem with the View Layer though, it's pretty lightweight, a single actor ResponderMediator just listens for two notifications (RESULT/FAULT) fired from each AsyncCommands which it then outputs to the browser via Responder component.

In essence REST requirements involving several operations around each entity/resource is requiring me to have several commands and proxies for the related module and I'm not finding a way out of it.
« Last Edit: June 06, 2015, 10:18:27 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: June 08, 2015, 06:35:50 »

Hi Saad,

I know all this makes sense to you within the context of the work you've done. But if you could draw us a diagram of the modules and their message flow as well as a diagrams of the individual modules, it would make things a lot clearer.

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #2 on: June 08, 2015, 04:02:00 »

I've recognized following patterns while working with PureMVC and also enforced some rules on top of that in my projects.

  • Actors have very focused responsibilities
  • Modules have very focused goals

For #1, besides design I also determine by Lines of Code, an average is 65-125 LOC, anything goes beyond is a sign that design needs revision and usually gets solved by brining in another reusable actor.

For #2, If there are too many actors and module is getting bulky, that means the module needs further decomposition, therefore it gets split into another reusable module. On an average usually 3-5 Actors/Commands per module.

Under REST application I'm finding #2 hard to implement as there are too many operations just for a single entity, ending up with 9 Commands in this case. I reduced the clutter at least for the eye by moving the crud based operations into a separate folder (crud) for each module and here's the diagram. (9 Commands in red)
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: June 09, 2015, 01:46:48 »

Hi Saad,

I agree with your precepts for decomposition of actors and modules. However, I think the explosion of classes in your current design is probably due to the literal mapping of your application's actors to the REST interface you are exposing to the client.

For instance, having a separate command and proxy pair for list/detail/insert/update/delete seems a bit excessive. Usually I have one Proxy for a data source and perform all operations from it. A single command could look at the incoming request and determine which methods to call on the Proxy.

I see you're using AsyncCommand/AsyncProxy. Not my favorite implementation. I like the "Formal Request" architecture (which I describe in the Advanced Model Topics section of the PureMVC book) better.

The essence of that architecture is having a "Request" object which is submitted to a Proxy, via a method like MyProxy.submitRequest( request:IRequest ). That request tells it the operation the caller (usually an ICommand) wishes to invoke. And it also has a callback function (courtesy of extending PureMVC Observer) that lets the result come back asynchronously to the caller. This will work with a SimpleCommand and Proxy.

I described the basic premise in code here:
http://forums.puremvc.org/index.php?topic=1955.msg8724#msg8724

You'd want a more advanced request that could have a type and other parameters probably. That example just triggers a static call and gets the result back. It also uses AsyncToken (a Flex-ism) that ensures the Proxy gets the result of the call. Whatever methodology you're using in JS in your AsyncProxy would be used there. It has nothing to do with the communication between the command and the proxy.

I'm willing to bet you could have a single command figure out the type of request to generate, then submit it to a single proxy to get the work done and return the result. Your router would simply need to send the right notification to the command containing the information about the REST path, so that the Command could determine the appropriate request type to create. With a single submitRequest() method on the Proxy, it would mean you don't have a big switch in that Command calling different Proxy methods, so it shouldn't be very large. Nor should the Proxy really. It would need a method for each of list/detail/insert/update/delete, but its handling of the response would be similar.

The command would then trigger different notifications based on the response it gets back, which might mean a Command and/or Mediators answer, that end of things - handling of the result - will vary based on your app. But the collapsing of the commands for initiating a call into one, and the collapsing of the separate proxies for every kind of call by way of the formal request object with built-in callback should get this under control without pushing too hard at the upper limits of your #1 decomposition rule.
« Last Edit: June 09, 2015, 02:21:48 by puremvc » Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #4 on: June 15, 2015, 05:28:51 »

Hi Cliff,

I apologize for not been able to respond earlier as I've been completely slammed, but I read the response, been pondering, also looked up the book reference and I understand the points mentioned here too, but here's something which led to this structure and I'd explain more with the help of your quote.

It would need a method for each of list/detail/insert/update/delete, but its handling of the response would be similar.

It's basically the handling of the response that's different for each of the actors. for instance.

  • GET /products -> 200 OK [] (Array)
  • GET /products/:id -> 200 OK {} (Object) or 404 Not Found
  • POST -> 201 Created
  • PUT /products/:id -> 200 OK or 204 No Content
  • Delete /products/:id -> 200 OK or 204 No Content

And there's more to the REST specifications not covered here, for instance content negotiation factors or decorating the result with the link of the newly created resource in the response headers for POST commands.

So it's very different, unique and detailed post-async or post result/fault responsibilities for each kind of request that are the reasons behind separate AsyncProxies with their dedicated roles.

Initially I did combine 1) List and 2) Detail and tried with a single actor but due to async nature of node.js itself (callback for everything) it was turning into a Fat proxy and from there I split up things and assigned single responsibility/role to each actor.

SideNote:

With reference to AsyncCommand, PureMVC book referred to it as
muddle the responsibilities of the Command, making it implicitly involved in the persistence mechanism by implementing Responder and handling ResultEvents and FaultEvents

I agree and I could have Proxy send notifications (RESULT/FAULT) after result decoration but it's because of the nature of node.js and following simplicity measures that employed AsyncCommand.

node.js runs under a single process (shared/single memory space for all users) and in order to serve multiple users, a new instance of proxy has to be created for each request in a command, i.e. no registration of proxies in StartupCommand, since all actions within the proxy are async so a single instance can't be used for another request while it's asyncAction is in progress.

Then for it to be able to send notifications for result/fault it needed facade registration with a unique name (Proxy.NAME + request.id) and then has to be removed at the end to release memory, so a dedicated command was required for that. I could create another method within the proxy that remove itself from facade at the end, but then re-using the same command that instantiated it seemed more intuitive for removal, so that's how a dedicated pair concept came into existence.

Later on, I simplified things, for each request a new AsyncProxy instance gets instantiated but without repeatable facade registrations and removals, it performs it's asyncActions, parses results, decorates it, and then it responds back to it's paired AsyncCommand for sending notification. AsyncCommand frees up a bit from having to register and remove proxies from facade. By handling result parsing/decoration within the AsyncProxy and responding to AsyncCommand for notification only, I hope that avoids the muddle while also keeping the AsyncCommands thin.

So in summary, each request fires it's notification, for which Controller instantiates a new Command, and that command in turns instantiates a new proxy, calls asyncAction on it, the proxy then pools the connection, executes the SQL, decorates the results first within it's own result/fault handler, and then responds back to the Command for RESULT/FAULT notifications. All of this is happening in parallel/sequence for all the requests. These new instances of AsyncCommand/AsyncProxy pairs for each request is basically making it possible to serve several different user requests under a single process environment but then at the same time exploding the module.
« Last Edit: June 16, 2015, 09:21:28 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: June 16, 2015, 12:35:59 »

Still, you could implement the formal request and use SimpleCommand and Proxy. The Proxy classes could possibly be simplified intto a single, more generic one by having the Request class determine the HTTP method GET/POST/PUT/DELETE and the URL base, but you supply the final node like :id in the constructor.

Then as I mentioned before,
The command would then trigger different notifications based on the response it gets back, which might mean a Command and/or Mediators answer, that end of things - handling of the result - will vary based on your app.

-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #6 on: June 23, 2015, 01:27:56 »

Hi Cliff,

It's awesome and much better now. Took the Formal Request route, not only the modules are compact now but actors are thin and manageable as well.

Using a SimpleCommand and a Proxy, although the environment is node.js but adopted few things from Flex paradigms, for instance common.DatabaseObject (RemoteObject in Flex) which itself now is a highly reusable actor across all modules, accepts the QueryRequest/Observer (sql + values + request/response objects), returns the token on which Proxy sets itself as a Responder. DatabaseObject then pools the connection, executes the SQL and returns result/fault via token.responder to the Proxy.

Model got reduced to a single proxy that just populates the sql string and values array of QueryRequest, and notifies the command on result/fault. Further View tier (Router) is handling result decoration as per the REST specs for the client.

Thanks a lot for your great support.
« Last Edit: June 23, 2015, 01:51:49 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #7 on: June 24, 2015, 07:34:11 »

Hey Saad,

Glad to hear the refactor worked out for you. It's always nice when you can chop a few heads off the complexity beast :)

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #8 on: October 06, 2015, 07:43:12 »

Hello Cliff,

Formal Request pattern has been amazing. A single command with a single proxy and some advanced type of ServiceRequest (added property requestType) while utilizing a highly reusable helper object (like RemoteObject, DatabaseObject etc.), not only turned controller into a thin controller but a thin proxy as well. Single Invoker/Responder principle worked a ton.

I saw the same great principle getting implemented in The Advanced View Topics in "ActionScript Developers Guide to PureMVC" under Managing Pop Ups. Deep stuff.

"A Proxy retrieves the data from a service and a pop up retrieves it from the user; that is the only difference."

Controller, Model and Popups are very much under control :) but when I've several view/components in an app (let's say Header, nav and their associated pages, login and profile panels and several others), I see explosion of mediator and viewComponent classes.

An idea is to divide viewComponents across different cores while reusing the Model Tier (Chap-8 Advanced Model Topics), and maybe have the nav in the shell with management of add/remove pages but classes of associated views/pages in different cores. Any thoughts on that please.
« Last Edit: October 07, 2015, 05:34:42 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #9 on: October 08, 2015, 09:04:14 »

...when I've several view/components in an app (let's say Header, nav and their associated pages, login and profile panels and several others), I see explosion of mediator and viewComponent classes.

The rules of thumb for factoring view components down into smaller and smaller units is the same regardless of framework usage. Don't build god objects. Break it down. Remember that reuse is a by-product of this process, not the goal or the arbitrating factor in the decision to decompose further. The goal is make each component simple enough to be able to do its function clearly so that when someone needs to modify it, it's an easy task, and no cycles are spent trying to understand how everything is wired up. The component should expose an api of properties and events that make it obvious what its external dependencies are and what things about its state it will communicate to the rest of the app.

Since view components are arranged in a hierarchy, the parent view component can and should act like a mediator to its children. PureMVC Mediators are not code-behind constructs intended to push you toward developing "dumb" components. They only provide framework mediation with chosen parts of the display list. Every component doesn't have to be mediated. You might have twenty view components but only three Mediators. The mediator can pass data to its view component, which passes it to its children, and in turn they pass it down to their children. Those grandchildren can send events up the display list that, if need be, eventually make it to  a mediator via the grandparent.

You can even have the view component implement an interface so that it can pass itself along in the event, and the mediator sets data directly on that requesting grandchild component rather than on the component it actually mediates.

A mix of data being passed from a mediator to a component and from there down the display list AND mediators communicating with arbitrary interface-implementing components is good. In the right balance, a mediator can service a lot of components, the data flow in the display list doesn't get too complex, and the mediator's responsibilities aren't overwhelming.

So, decompose your interface, then look for appropriate points to mediate. Find that sweet spot where the display list, the individual components, and the mediators are all at a comfortable level of complexity.

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #10 on: December 06, 2015, 02:28:00 »

Thanks Cliff for the enlightenment and an improved workflow. It's good to learn how Mediator can mediate it's viewComponent as well as it's nested components.

Building on the thread and pushing "View" related discussion a bit, let's say those twenty or more viewComponents are split across modules/cores. The primary purpose is so that different individuals/teams can work independently on assigned viewComponents without the need to access or share the shell's root file (.fla in flash, .xib in iOS etc.).

Just like in the Pipes Demo, the prattler module gets it's own clean slate for development, UI related components, it's own controller and model, and is piped to the shell where it gets added there along with it's Mediator registration.

Please add your gems for a case when we have several complex components like prattler or more distributed across modules and dev teams in a large scale app.

Thanks again.
« Last Edit: December 09, 2015, 10:06:38 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #11 on: December 11, 2015, 12:46:41 »

So, if the Mediator lives in the shell, and you want to mediate a view component that lives in a module, then you need only:

1) Make the view component implement an interface known to both the shell and the module,
2) Send a pipe message to the shell containing the view component to be mediated,
3) Respond in the shell by registering a new instance of the Mediator subclass, giving it the component.

Make sense?

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #12 on: December 14, 2015, 03:58:34 »

Thanks Cliff. The idea was to have parts (complex nested components) of "View" to be developed across modules instead of compressing everything within the shell while also maintaining the hierarchical relationship and mediation in shell.

Thanks again for a very comprehensive discussion on large scale enterprise development under PureMVC.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #13 on: December 14, 2015, 08:13:00 »

Hi Saad,

If I get the gist of your last response, you could message up more than one view component from various modules, and have a Command in the Shell do the insertion of those views into the hierarchy, and mediate one or more of them at that time. Is that more along the lines of what you were thinking? Of course the components would still need to implement interfaces, and expose methods for accepting the children this Command would pass them for assembly.

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #14 on: December 14, 2015, 10:24:52 »

Hi Cliff,

Yes that's exactly what I've been thinking for and thanks for making it more clear and cut.

Further I intend to link domain logic that's reusable across modules under the light of "Reusing the Model Tier" topic from PureMVC book while this complex "View" (in a submodule) can have it's own internal "Controller" and "Model" as well depending upon the need. The shell can further steward this viewComponent after addition and mediator registration etc.

The ultimate objective is to have each "Complex viewComponent" developed from different team members while giving them an independent clean slate (their own small manageable module, scripts, .fla, .xib etc.) to work on and then getting all of those complex viewComponents assembled within the shell as per your guidelines hence leading to less bulky "View" of the shell.
« Last Edit: December 14, 2015, 10:48:43 by saad » Logged
Pages: [1] 2
Print