« [Tip] Easily navigate to Desktop from 'Open file' dialog | Main | [Gotcha!] Cascading deletes »

March 07, 2006

[Article] Managing graphics in modules (and other thoughts)

by David Workman
Data Mosaic

Picture_10 This tip is in response to a thread in the servoy forum regarding developing Servoy solutions using modules. In addition to Bob's best practice's tutorial on modules, there is a lot of good comments in this thread for things to watch out for and how other developers are doing things. Quite useful information.

Developing with modules is a great way to compartmentalize your solution so that multiple developers can work on the solution at the same time. This the major reason we started using modules. We soon found out that modules are also great for organizing a solution. By their very nature, if you don't have good naming conventions or a good design in mind for your solution then you will shortly be in a lot of trouble. The kind of trouble all of us FileMaker developers in a former life are famous for....

Additional module advantages I have found:

  • the process of thinking through your solution to divide up into modules helps your design
  • the unique naming constraints that modules enforce on you make you develop with a strict naming convention
  • the ability to encapsulate specific functionalities and work flows into a module gives you a high degree of solution/code flexibility and reuse

All of the above can be accomplished without using modules but we all tend to be lazy or slip on occasion and name a form "spaghetti_land_101". Once this happens you are off the track and plummeting towards a land of no rewind. Put several developers on the same project and all of a sudden you have deal with a very scientifically researched formula:

big_f_ing_headache_for_dave = solutionSize x developerNumber x lazinessConstant x communicationFailureConstant x egoConstant x randomBrainFarts

If I haven't made myself clear so far: read up on modules, learn how to use them, and save yourself a world of hurt. Almost a requirement if your solution is of any major size and has multiple developers working on it.

Now we can get to the topic at hand. Managing graphics when you have lots of modules hasn't been addressed anywhere. Here's my <brain dump>. Enjoy.

Approach #1

Let's say you use 50 graphic files for your UI. Not out of the ordinary if you are doing something like this screen and have rollover images for all of your buttons:

Picture_2_1

Say I have this solution divided up into 10 modules and 5 of those have user interface screens. The most direct way to manage your graphics would be to put all 50 of your graphics in each module and call it a day. This is by far the easiest to manage as a developer.

The first downside of this approach is that your solution now has 250 (5 modules x 50 graphics files) files that have to be loaded by the client the first time. And this number grows for each module you add to your solution. 20 modules and all of a sudden you have a 15 minutes download. This doesn't make for a great first impression with a user.

Secondly, your solution is now a beast in size. Instead of a 400K file you could easily be exporting solution files 5G in size. Not so easy emailing those sumo babies around. Also, importing and exporting your whole solution takes a long time.

Summary: if you don't use a whole lot of graphics and/or don't have a high number of modules that use graphics -- this is the way to go. Because then you don't have to go through the pain of...

Approach #2

Let's talk for a moment about the modular structure used to build the screen shot above:

Picture_7_1

Each box represents a module or modules. The basic idea to come away from with this is that we use a "shell" module to combine all other modules -- business logic, utility, graphics, etc. Besides organizing everything, the shell module coordinates login/security and navigation for the business logic modules. Here is how the main screen of the shell module is constructed:

Picture_6

Sections (3), (4) and (5) are tabless tab panels. (3) has the navigation list. When you click on a navigation item, tab panels (4) and (5) are filled with forms from a business logic module. Since all form names in a solution have to be unique, this is simply a matter of specifying the form names in the navigation record and then loading them into the tab panels using the addTab('formName') function. Restricting access to certain forms then is simply a matter of not showing a navigation record unless a user has sufficient privileges. Quite elegant in terms of organizing a lot of modules.

There is a lot more I could say on this subject but let me get back to the subject at hand: dealing with graphics with all of these modules. As you can see, I have now put all of my graphics in one module (or more if we are using a purchased graphics kit -- this way we can individually lock the module with purchased graphics separately from other modules).

This graphics module is then included as a module in any other module that uses the graphics. In spite of this, when everything if combined into the final solution, only one instance of the graphics module is present. In a sense, Servoy "flattens" multiple instances of modules when everything gets put together. This is a good thing.

At this point, everything is great -- one graphics module for all other modules means I am only using one instance of a graphic throughout the entire solution. So if I have 20 modules and my graphics module has 50 graphics, the final solution only has 50 graphics. Good stuff eh? That is the theory -- now I just wished it worked exactly like this in practice!

A big note on making this system work: when you export a module that uses a graphics module, you MUST export the graphics module with the module in question. It would be really cool if you could just export the business logic module, import it into the shell module (which already has the graphics module included), and have the business logic module "see" the graphics module that is already in place.

Unfortunately, if you export a module that has references to graphics in another module and you don't include that other module -- all references are wiped out. If this one thing were fixed by Servoy, I wouldn't be writing such a lengthy treatise on this subject.

A major side affect (problem) to having to export the graphics module each and every time a parent module is exported is that you end up with a gazillion versions of your graphics module in the repository:

Picture_8

This is due to the fact that a new version is created every time a parent module is imported into the repository. If you have five parent modules that are getting exported/imported a lot they will all be on version 10 and the graphics module will be on version 50.

This is where the kicker happens: sometimes an ANOMALY occurs in the graphics module on import. I call it an ANOMALY because after hours of testing, we still haven't figured out the exact situations or reasons for the ANOMALY to happen. I can only tell you what the anomaly is: at some point you will notice that your graphics module contains multiple versions of the same graphic. This is the screen shot of the media window for version #53 of the graphics module:

Picture_9

As you can see, there aren't 53 versions of each graphic nor is each graphic duplicated the same number of times. This would be the definition of a Servoy ANOMALY in case you haven't followed anything else I've said so far in this article :)

This unfortunately gets us back to the problem experienced with method #1 of dealing with graphics: ending up with a solution with a ton of duplicated graphics. The result so far in our experience is not near as extreme as where we'd be by using method #1 but this particular solution is of 800K now and it is largely due to this graphics module.

The solution seems easy: go delete all but one of the duplicate graphics in the graphics module. Try that and you will spend the next three months reconnecting all of your graphics throughout your solution! It turns out that if you have an object in your solution that has a graphic property, Servoy associates the graphic reference by ID, not by the graphic name.

Somewhere in the process of importing/exporting modules, passing them among multiple developers and uploading to the main server -- graphics references start to multiply. It may look like the same graphic in name but the reference is to a duplicate version. The how and the why -- a huge mystery. There is one side effect that crops up as a result on occasion: one graphic will go missing. *Poof*. You'll do an export of a module you've been working on and import it to the main server and a random graphic will be missing on the server version. For lack of a better reason I think Servoy gets so confused it has to relieve stress by pissing the developer off in a minor but nagging way :)

If you are up for dealing with some of the weirdness associated with this method, it will result in a smaller solution size in the end. Not as small as you'd expect in theory unfortunately but certainly worth the effort.

Postscript

Troy and myself finally got pissed off enough over this issue that we sat down one afternoon and figured out the Servoy repository table relationships. As a result, we now have a bunch of SQL statements that you can apply directly to the servoy repository database that you can use to find all references to duplicate copies of a graphic and reset to connect to a single instance of the graphic. We'll gladly share this knowledge if someone wants. Or for a slight fee, we'll "flatten" out your graphics module and solution references for you. It's quite a detailed process -- not for the faint of heart.

</brain dump>. Hope this is helpful!

| Posted by David Workman on March 7, 2006 at 12:03 PM in Articles | Permalink

Comments

Hi,

Very nice article!

About the problems you have been having I can tell you we are really working hard on correcting them. The problem is that Servoy grew from a single-solution paradigm to a paradigm with modules, and since this was a feature that was not in the design from the start there are several (tricky) problems with image (and other element) references.

The Servoy 3.0 design philosophy will be rather different and more compatible with multiple developers. However it also a big change, so it will take a little while before it is complete.

The basic idea is that all references to elements will be by a universally unique identifier (UUID) which will allow you completely delete and reimport a module without losing any image references. We're prerty far with this, so it should be available sometime relatively soon.

Finally for multiple developer compatibility the workflow and repository are going to change quite a bit. The idea is that a solution is developed in a single repository (instead of a local repository for every developer). When a developer wants to make changes he/she can "check out" a certain release of the solution, make some changes, and in the end check it back in. This allows for bigger logical changes. Release numbers will refer to unique versions; a fixed release number will never change again. These changes will allow for reliable version control with reliable merging of changes, and multiple developers working on the same solution at the same time. This is a major change so, so it'll be a while before it is complete.

Together these changes will solve the problems you are having and allow you to really use modules for the reasons you listed under "additional module advantages"; because actually these are the primary advantages of modules! It will also allow you to work on a single solution or module with multiple developers.

Greetings,
Sebastiaan van Erk
Servoy

Posted by: Sebastiaan van Erk | Mar 9, 2006 5:01:40 AM

Sebastiaan,

Thanks for the insights and details on the module roadmap. Sounds really good!

One request: the ability to "replace" a graphic in a UUID slot (or specify the UUID). Currently you can only import and delete and the IDs are incremented as a result. With the ability to replace in your new system, we could change the "skin" of our solutions/templates simply by switching out a graphics module with another graphics module.

- David

Posted by: David Workman | Mar 9, 2006 8:03:49 AM

Wow! This is good stuff. We've been taking the lazy approacy of importing our graphics all over the place, but a graphics module "sounds" like the right idea.

I'm also happy to hear about Sebastiaan description of hte multi-developer changes they are making. Currently, we have 3 developers working on the same project and we are either using the Prairie Dog Technique (pop your head above the cube and say "hey, i'm working on form ---, nobody else work in that one"). Or sometimes were able to break the work between us into modules.....but better multi-developer system will be nice.

Posted by: Scott Butler | May 19, 2006 8:56:15 PM

Post a comment