This is part 2. In Part 1, I explained the reasons as to why we chose to use Parsley in our projects.
In Part 3, we will look at a basic Injection Example.
In this note, I will explain the basic concepts of Parsley, in the next article we will look at a specific example.
What is Parsley?
Parsley is a framework that helps you write decoupled Flex/Flash/AIR applications written in ActionScript3. Note that I specifically did not include MVC (Model-View-Controller) in the description. The reason for excluding MVC in the description is that Parsley is not aimed towards any specific pattern including MVC. Parsley is a framework that helps you decouple your application. What this translates to is that your Classes are less tied to a specific implementation and to each other. This promotes re-usability and it makes it much easier to test individually. Also it's easier to work in teams, because when a particular person is working in a Class, he/she should only worry about what that Class is supposed to do, and not about a particular implementation that might depend on what other are working on. You can more easily work in parallel when you write decoupled components and Classes.This is a list of Parsley's main features, extracted directly from Parsley's website:
- Flexible IOC Container: Supports configuration with AS3 Metadata, MXML, XML files, ActionScript
- Dependency Injection: Injection by type or id - for constructors, methods or properties
- Decoupled Bindings: Bindings where source and target are fully decoupled, based on a publish/subscribe mechanism
- Messaging Framework: Fully decoupled senders and receivers, can serve as a basis for MVC architectures
- Dynamic View Wiring: Easily wire Flex components to objects declared in the container
- Advanced container features: Asynchronously initializing objects, object lifecycle, modular configuration contexts
- Integration with Flex Modules: Allows configuration to be loaded and unloaded alongside Flex Modules
- Localization: Integrates with Flex ResourceManager for Flex Applications, contains its own Localization Framework for Flash Applications
- Extensibility: Easily create your own configuration tags, a single implementation can be used as AS3 Metadata, MXML or XML tag
Parsley's Basics
One of the great things about Parsley is that it's not "intrusive". What I mean with not "intrusive" is that you do not need to extend any of Parsley's classes at all to use Parsley's features. So it is fairly easy to take components that use Parsley and without having to remove most of the tags, they will either work with another framework of without a framework at all. Many things are accomplished in Parsley by using simple Metatags that will be ignored if nothing is there to interpret them. Of course, you can extend Parsley's Classes if you wish to add more features or modify features if you like.Another important aspect is that it doesn't force you into any particular pattern. It is primarily a decoupling framework. You can follow an MVC pattern, or any other decoupling pattern that you want. MVC is the buzzword now, but someone will come up with something "better", and if you are stuck into something specific, well you are... stuck. Parsley is pretty abstract. Some people don't like this, but I most certainly do. I strongly believe that following patterns is good, until they start getting in the way of accomplishing your original goal. No pattern is perfect, all patterns will have their cons, and if their cons really start killing your productivity, it's time to revise your patterns. Don't just follow them to the book because that's HOW you are supposed to do it. Patterns should not be unchangeable rules. If your project does not fit well into a specific pattern, then use a different one or modify it so that it fits well. Just coordinate the changes to the pattern with the rest of the team.
Some key concepts and how they relate to Parsley:
Managed Objects. Parsley will only manage objects that you specifically instruct it to do so. It will not manage anything without being told to do so. Non-view components (those that are not added to the stage) are managed by using the ContextBuilder. View component's (those that are added to the stage through the addChild() method are managed by including the Configure tag. Parsley manages the complete lifecycle of objects that where added through the ContextBuilder. Parsley will automatically create new instances as needed and will destroy old instances when they are not needed. If the class that you want Parsley to manage requires parameters to be sent to the constructor, Parsley can also do that. Generally speaking, Parsley removes (destroys) objects when the context that they belong to is destroyed, and the context itself is also destroyed automatically when the object that created the context is removed (unless it is specifically instructed not to do so).
Context. If you are coming from Cairngorm 2, there is a reasonable chance that you wished you had this in Cairngorm. A context in Parsley is somewhat similar to the concept of scope of class. Objects within the same context can "see" each other, and are available while the context exists. They can be shared among any other managed object within the same context. Context, like scopes, can be nested, just like you nest curly brackets { } in AS3 to control scope. The interesting thing about the way Parsley implement's the context is that the context is automatically and dynamically wired to the View. In other words, once a component creates a context, any view child of that container can participate in that same context. This also means that you can easily have and manage nested contexts, multi-level contexts, or sub-context, or more private context, however you like to call them.
Dynamic View Wiring. This is a key-point of how Parsley glues objects together. By default, Parsley's contexts are associated with the view hierarchy. View-children of the component, or any of its children, can participate in the same context. This is applied to the whole view hierarchy. The great thing about this is that you don't need to have two hierarchies (one for Parsley and one for the view), it's all tied to one, the view, which you have to use if you use Flash/Flex. So things work like you would expect with very little additional configuration, and it's all part of the same thought process. This also applies to Modules. If a Module is loaded and added as a view-child, it participates as part of the context its parent belongs to, all done automatically. The dynamic view wiring model extends through the children of the children of the children, etc... If you are wondering if you can control the context more manually, the answer is yes, you can, but you don't have to.
Dependency Injection. Dependency Injection is a concept in which you assign (inject) objects into other objects. The idea is to keep classes from having to go reach and fetch anything that they might need, which would tie them to a specific structure or implementation. So rather than it reaching for its dependencies, you feed the dependencies to it. This is great because the class can be used for many different things. A simple example is Flex's Lists component. The List component doesn't go and get its data, you have to assign (inject) its data to it, through its dataProvider property. This allows the List to be used many times with different data. If this is great, what is the problem? Well, since you have to feed the data, you need to carry it around in your views and that ties that view to that data and that implementation. Also, some of your views may not have a need for specific data yet they will have to carry it around because one of their children might need it. This is one of the reasons why some developers like Global Variables, they help you avoid having to carry data around, although they are generally speaking considered a bad idea and bad programming practice. Dependency Injection is not limited to data, that's just an example. Let's say that rather than carrying data around, you decide to request the data from a service every time you need it. Well, that does mean you will be making a lot of (possibly unnecessary) service calls. So you would have to go and setup the service everywhere you need to. So you decide that you want to setup the service once and use it everywhere, well then you should inject it into your views so they can use it. Simple, right? Well, so now rather than hauling your data around, you are doing the same with the Service. Is there a solution without using Global Variables? YES! Parsley can manage Dependency Injection for you. That way Parsley carries your objects and injects them where ever you need them. You can easily add new features. BTW, locally cashing data in the client side is one of the things I really like about web applications done in Flex/Flash. If you have already fetched some data from some service, you really should not have to go fetch it again because you are in a different view that uses the exact same data.
Inversion of Control (IOC): Is a principle that promotes decoupling of an application. It's called Inversion of control because the flow of control is inverted from traditional procedural programming. It's commonly associated with the Hollywood (or most auditioning) principle: "Don't call us, we will call you." In standard procedural programming, you call methods/functions, and expect an immediate action and response, and then you make your next call, and expect the same, and so on. Under IOC, that's not the case. You request something to be done, and when it's done, you will be notified that it's done, you no longer have control of when exactly things will happen. Flash in itself follows the IOC principle simply because it is highly event driven; Parsley helps you keep things that way. The main goal derived from IOC is that you write highly specialized classes that should make little or no assumptions of what other classes do. This makes it much easier to test and to reuse your classes, also you can swap a Class and no changes would be required to any other parts of your application. For example, using IOC you could write an app that writes to a local storage, and when the save is complete it notifies the user that the save is complete. By using IOC you could simply swap one Class, and now the application can write to the local storage, contact a remote service, wait for an answer from the service and when all is done, notify the user that the save was successful after the service replied. All this and not have to change any other Class, everything continues to work as it did before. That's because the original implementation using IOC, regardless of the save been local, the system was still expecting to be notified when the save was complete, and not assumed it would be taken care of immediately. Essentially, you are using Asynchronous Communication. It is much easier to extend and add new functionality in the future if you are using the IOC principle. The drawback to IOC is that creating sequences of tasks is more involved. The good news is that with Spicelib you also have Tasks Groups that allow you to create sequences more easily, and still follow IOC principles.
Singletons: Parsley's docs sometimes use the term singleton. Singleton is essentially a single instance of a class. What Parsley's docs generally refer to as a singleton is a single instance of the class within a specific context, and not the common use of singleton that it's a single instance within the whole application.
Reflection: This term is used often in the docs, and used later in the series, but what does it mean? Reflection is the capability of a computer program to be able to examine itself and potentially use that information to change it's behavior at runtime. The keyword is "runtime" because normally the compiler and linker inspect, and link the code together, but with Reflection, at runtime you can check what methods exist and call them without them being explicitly called at compile time. Reflection is a great feature of Flash and ActionScript. In Parsley terms: Reflection means that Parsley can read and inspect the classes you tell it to, and call methods, read and assign properties of those classes without that being explicitly coded in your app. Reflection is what actually allows Parsley to do it's job. Through reflection, Parsley can know that you want to have a particular instance of some object assigned to a property of another class and do framework managed dependency injection for example.
Ok, we have gone through some of the basic concepts that are needed to get a good grasp of what Parsley does and how it works. In the next article we will start with some examples.
(Edited November 12, 2010 to add Reflection to the list of Key Concepts)
Great introduction, but it's not that easy to understand all the points if you don't have a big dev background. I guess most of the difficult points will be cleared in next posts.
ReplyDeleteNow looking forward for the first real examples and concrete stuff :)
Thanks Jahz,
ReplyDeleteYeah, I wanted it to be informative and useful to someone with a big dev background, yet be understandable by someone new to IOC. It's hard to hit both. But you are right, it does assume you have Flex development experience. But the examples are simple enough that you should catch on quickly, and it will make more sense shortly.
Very Informative....getting more and more interested while reading this stuff....Thanx for sharing
ReplyDeleteArt is science made clear.
ReplyDelete- Wilson Mizner
man, can nobody explain this stuff clearly and straightforwardly? losing hope...
ReplyDelete