Servoy Tutorial Photo Credit: angus clyne via Compfight
This Servoy Tutorial is a discussion about encapsulation and best practices. We have been given new abilities in Servoy Developer to use encapsulation with forms, relations, and even value-lists, but do we know what we are supposed to do with this capability?
For those of you that read my Servoy tutorials on object-oriented programming, you would have learned a lot about encapsulation with objects. In the Servoy tutorials, we learned how to build an object with private variables and private functions, which are not accessible to outside users. We also learned how to expose public functions, like an api, so that users could access them. Basically, we hid the things we did not want users to touch, keeping them private, and only exposed those things we wanted them to interact with, in a public interface. This is encapsulation, with respect to an object.
So what does that have to do with forms, relations and value-lists? Well, everything; its exactly the same idea. The problem is, that instead of doing things the right way, we cheat, and because it works for now, we think its good enough. What am I talking about? I am talking about calling another forms methods, accessing its dataproviders, foundset, elements or controller, from some other part of the system. Just because you can see it in the “Solution Explorer” view, does not mean it is okay for you to use it. For example, using “forms.someForm.someMethod()” breaks encapsulation, and creates all kinds of problems for you down the line. It is generally considered a very bad thing to do and indicative of poor architecture.
There are lots of reasons why you should never call another forms method (or anything else). For one, another developer could change something in that method, unaware that you are using it from somewhere else (how would he know). Because you are tightly coupled to that method, your reliance on it will fail. If you do this a lot, and keep breaking encapsulation, you end up with a Big ball of mud. Furthermore, it is extremely bad architecture to do things like this. You need to design your system for modularity, encapsulating your code into a well designed interface, effectively hiding information, and exposing only a layered design (like MVC, commonJS, etc.). The value is to simplify development and maintenance, allowing individual sections to be modified, without breaking other code that is using it from somewhere else. Basically, its how you build software today.
A Big Ball of Mud is a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle. These systems show unmistakable signs of unregulated growth, and repeated, expedient repair. Information is shared promiscuously among distant elements of the system, often to the point where nearly all the important information becomes global or duplicated. The overall structure of the system may never have been well defined. If it was, it may have eroded beyond recognition. Programmers with a shred of architectural sensibility shun these quagmires. – Brian Foote and Joseph Yoder
So stop breaking encapsulation! Don’t high-jack another form’s methods, value-list, or a relation. The original developer that wrote the code on that form, or created the value-list, did so for a specific purpose, and never expected anyone to call it from somewhere else. If they had, they would have exposed it as part of a public interface and made sure that it was designed to be used in that manner. The golden rule is “If its not yours, don’t touch it”. The good news is, Servoy provides all the tools you need, to implement a proper architecture, preserve encapsulation, and design a sustainable and modular system.
Lets get down to business and take a look at the tools we now have in Servoy to control encapsulation and build a better design. Once we understand how they work, then we can move on to a more practical discussion on how to implement an architecture that achieves that.
Servoy provides us with encapsulation properties on forms, relations, and value-lists. Let’s take a quick look at each property and see exactly what it does.
First, we have some new properties that allow us to control encapsulation on a form. Lets go through each one and see what it does.
Value-lists work similar to the form properties. As you would imagine, public means accessible from everywhere, and module scope means only for use in the module that they are created in. However, if accessed from somewhere else, you get a build marker, but they will still function properly.
Just like form properties, relations can be public, hidden from code completion in scripting, or only accessible to the module they were created in. They still work if accessed from somewhere else, but you get the build marker.
The JSDoc tags are very important. They allow you to specify which methods will be public, and which are private. Private methods will appear red in the “Solution Explorer”, while public methods appear in green.
This is what a properly encapsulated form should look like. Notice that very few of the methods on this form are accessible from anywhere else, without generating build markers. Effectively only two methods (in green) are available for public access.
Okay, I wanted to make one final point on the new Servoy properties. You may be wondering why Servoy generates build makers to indicate that something is private and not accessible, but still allows the call to function. The reason is that too many of the programs out there have been breaking encapsulation rules, and would cease to function if they were upgraded to the latest Servoy. So, the build markers are generated, reminding you of the poor implementation, but everything continues to work as currently implemented.
At this point, we should understand that we need to have everything set to @private, and only expose a select few @public methods, relations, or value-lists, that other areas of the system can access. We have to do this with conscious effort and be judicious about it. Think of it like this; nothing should be exposed to the other parts of the system, with the exception of a single access point that controls and routes access; this is your interface. Probably the best way to do that is with a single object or function that acts a router, verifying that incoming calls contain the proper parameters, forwarding them to the local private function, and returning the result. Here’s a quick look at how both of these scenarios could work.
Here is an example of using a single public method to route calls to local private methods.
/**
* @public
*
* @param {String} eventName
* @param {Array} [aEventArgs]
*/
function eventHandler(eventName, aEventArgs){
switch (eventName) {
case "EVENT_1":
return eventMethod_1(aEventArgs);
case "EVENT_2":
return eventMethod_2(aEventArgs);
case "EVENT_3":
return eventMethod_3(aEventArgs);
case "EVENT_4":
return eventMethod_4(aEventArgs);
default:
return false;
}
}
Here is an example of using an object to route calls to local private methods.
/**
* @private
* The object map for routing
*/
var EventHandler = {
EVENT_1: function(aEventArgs){
// Check all parameters are good
return eventMethod_1(aEventArgs);
},
EVENT_2: function(aEventArgs){
// Check all parameters are good
return eventMethod_2(aEventArgs);
},
EVENT_3: function(aEventArgs){
// Check all parameters are good
return eventMethod_3(aEventArgs);
},
EVENT_4: function(aEventArgs){
// Check all parameters are good
return eventMethod_4(aEventArgs);
}
};
/**
* @public
* This actually routes the incoming calls using the object
*
* @param {String} [eventName]
* @param {Array} [aEventArgs]
*/
function eventHandler(eventName, aEventArgs){
EventHandler[eventName](aEventArgs);
}
So that is an overview of the new Servoy properties that will assist you in preserving encapsulation and building a modular system with better architecture. The new Servoy will gently warn you where you have broken the rules, giving you a chance to clean things up, and bring them under control. You should also take the time to learn more about designing loosely coupled systems with modern design principles, like MVC, commonJS, requireJS, and AMD.
That concludes this Servoy tutorial. In the next Servoy tutorial, we are going to build upon what we learned here, and build a real example using an event-driven architecture that further demonstrates encapsulation and loose coupling.
This is a Servoy tutorial on how to optimize code performance. A while back, I had…
This is an object-oriented Servoy tutorial on how to use an object as a cache in…
This is an object-oriented Servoy tutorial on how to use function memoization with Servoy. Function memoization…
This is an object-oriented Servoy tutorial on how to use object-oriented programming in Servoy. Javascript’s core…
This is an object-oriented Servoy tutorial on how to use inheritance patterns in Servoy. I use…
This is an object-oriented Servoy tutorial on how to use prototypal inheritance in Servoy. When…