Mendix 3.3.0 has been released

We are proud to announce that version 3.3.0 of the Mendix technology has been released. It contains about six new features, eleven improvements of existing features and twenty-six fixes. Below we describe the highlights of these changes.

The batch translate and replace dialogs now support exporting and importing translatable texts to and from Excel. This makes it possible for an external party to translate application texts without Modeler access. Another often requested feature for these dialogs is to be able to see where texts appear in the model. The occurrences of each text are now shown in an extra grid from which you can also open the corresponding documents. Finally, you can edit texts in a pop-up which makes it possible to enter line breaks in translations.

Export and import translations to and from Excel

Export and import translations to and from Excel

With version control you can revert local changes that were made since the last commit. But what if the changes have already been committed? In version 3.3.0 you can ‘reverse merge’ committed changes into your local copy of the project. This goal of reverse merge is to undo the effects of a selected revision in the history. Afterwards, your local project will look like the changes never happened; if you ‘reverse merge’ the adding of a form, the form will be deleted locally. Just like when you are doing a normal merge, conflicts can arise. In the example, if later commits change the added form, the reverse merge will result in a conflict. After resolving any problems, you can commit the results to the repository.

Undo committed changes with reverse merge

Undo committed changes with reverse merge

Other improvements are

  • support for the import statement in WSDL,
  • asynchronous generation of CSV and Excel exports (with a progress bar), and
  • more control over the tab order.

For the complete list of changes see the release notes in the support portal.

Keep your data safe

Domain model changes lead to updates of the database. For example, when you add an entity to a domain model, a table is automatically created in the database the next time that you deploy your project. Creating attributes in the model leads to columns in the database and associations lead to link tables. Deleting elements from the domain model result in database altering (DDL) commands that, when executed, will delete tables and columns. As explained in an earlier tech-tip, you should not edit the database by hand.

In Mendix 3.0 and above, entities, associations and attributes are internally identified by a unique number instead of a name. This helps us to keep track of creates, renames and deletes much better than in version 2.5. It does have some consequences of which you need to be aware:

  1. If you delete an entity called ‘Customer’ and then create an entity with the exact same name, DDL commands will be generated that delete the customer table! So if you accidentally delete an entity, do not create a new entity with the same name but use ‘Undo’ or the version control ‘Revert change’ feature to get it back. This will give you back the entity with the same unique identifier and data will be retained.
  2. When importing a new version of an App Store module, you get the option to replace an existing module. Please use this option if you want to retain the data that the module manages. The replace option performs a name-based synchronization of the unique identifiers of the imported module with the existing module. In short, do not delete a module and then add a new version but replace it instead.
  3. If you want to move an entity to another module, you should not delete the entity and re-create it in the other module; use the ‘Move to’ feature instead. You can find this feature in the context-menu of an entity. The move will also move associations and convert them to cross-module associations or the other way around if necessary, all while retaining data in the database.

The common theme of this post is that deleting domain model elements or whole modules will delete all corresponding data in the database, even if you re-create something with the same name. Use one of the offered alternatives to keep data intact and check the DDL commands when deploying to an environment with valuable data!

Time For Change: Recognizing When Your Current Ride Becomes Too Sloppy

Do you recognize the feeling that something has to change? Starting subconsciously and barely noticeable, but becoming louder and louder up to the point you simply cannot ignore it any longer. Whether “the itch” is about the place you are living in, about your current job or about the way you relate to people close to you; certain aspects of life should change once in a while, however scary and complicated change might seem. While problems like these are most apparent for ‘the big things’ in your personal life (and these are also the most daring ones to change), this also holds for other areas.

To code or not to code

When I went to university in 2001 I learned to program in Java. My first encounter with programming gave me a somewhat mixed feeling. While I like solving puzzles, learning to program was a bumpy road. After the first two courses I was quite sure software development would not be my first choice to pursue a career in.

Nevertheless, I somehow found myself working as a software developer in 2007. Although I had become more proficient in programming during the later years of my study, I still was not certain whether this was the career path I should follow. This changed quite quickly at the highly inspiring environment of a start-up with a bunch of young, intelligent people (among whom a couple of very bright programmers). Learning was easy and fun in this environment and I really started to like to program. Moreover, I realized programming has much more to do with language than I thought and less with highly technical aspects than I assumed (whatever ‘technical’ really is). I have always had a great interest in languages, so ‘coding’ turned out to be a better fit than I thought.

It’s not all peachy

Java was my first programming language and Java was also the language of the Mendix Server Runtime, my foremost programming domain. There was a lot to like about this language, certainly during that time. Java has static typing, object orientation, garbage collection and much more nifty features. However, working intensively with a language for five years inevitably confronts one with its limitations. At first these only seemed minor imperfections, or perhaps there was a neat solution that I had not learnt yet, but after a while more and more frustrations arose and a persistent voice in the back of my head started saying “time for change, time for change, time for change”.

One of my main frustrations was Java’s verbosity and related to that its lack of functional constructs. Reading code takes a lot of time. Studies of software maintainers have shown that approximately 50% of their time is spent in the process of understanding the code that they are to maintain (Fjeldstad & Hamlen, 1983; Standish, 1984). I felt we could be so much more productive if our code would become more concise and we could express ourselves in a more powerful way.

Sort out the mess

To illustrate the above, consider the following example: in Mendix, when a retrieval request for certain objects is received in the server runtime, the sort parameters are filtered for virtual attributes. Virtual attributes consist of computed values which the database cannot sort on. These sort parameters are removed before issuing a database request.

One way to accomplish this task is to iterate the map entries, pick the non-virtual attributes and put them into a new map:

Map<String,SortDirection> filteredMap = Maps.newHashMap();
for(Entry<String,SortDirection> entry : sort.entrySet())
{
    AttributePath attributePath = parsePath(entityName, entry.getKey());
    if(!attributePath.getAttribute().isVirtual())
        filteredMap.put(entry.getKey(), entry.getValue());
 }

Seems pretty standard…and is, when you are used to Java. However, the explicit iteration over the original map and having to use put methods on the filtered map is not very clean and quite verbose.

These redundant explicit actions can be avoided by taking a more functional approach. The following code example uses the guava library from Google (which is very useful by the way) to attempt a functional implementation:

Map<String,SortDirection> filteredMap = Maps.filterKeys(sort, new Predicate<String>()
{
    @Override
    public boolean apply(String path)
    {
        AttributePath attributePath = parsePath(entityName, path);
        return !attributePath.getAttribute().isVirtual();
    }
});

This approach is much better, as no explicit iteration and no put methods are needed anymore. The syntax, however, is awful. The anonymous class declaration is way too verbose and makes the code barely more readable than the previous attempt.

This is one of the many examples where I felt limited in how I could express myself in Java. A lot of these cases could profit from a concise functional syntax. Besides the need for more functional constructions, bloated code due to verbose constructors and get/set methods and the lack of tuples also made me longing for a new language.

Time for change

At some point you will recognize your sloppy old car is just not good enough anymore and an upgrade to a more modern model is in order. In my case Java was this sloppy old car and I felt the time had come to start investigating other options. The results of this investigation will be the topic of my next blog post.

What are your experiences with the programming languages you have used for a long time? Did you feel the urge to change language after a while? What triggered this desire for another language? Interested in hearing your thoughts!

————————–

Fjeldstad, R. & Hamlen, W. (1983). “Application program maintenance-report to to our respondents”. Tutorial on Software Maintenance, 13-27. Parikh, G. & Zvegintzov, N. (Eds.). IEEE Computer Soc. Press.

Standish, T. (1984). “An essay on software reuse”. IEEE Transactions on Software Engineering SE-10 (5), 494-497.

Photo by Gill Steenvoorde

To keep selected or not to keep selected: that is the preference

Today we want to highlight a feature that has a bit of history: “Keep active document selected in project explorer.”

Part of the preferences dialog (Edit > Preferences)

If checked, the document you are editing is always selected in the project explorer. If it is not checked, the project explorer is not updated but you can still quickly find the current document by explicitly clicking a toolbar button.

Should the project explorer follow the active document? If not, you can jump to it using the 'Select Active Document' button.

During the finalization of version 3.0.0 we found that people can be divided into two camps: people who love it when the project explorer is always in sync and people who are annoyed by it. After trying out different defaults, we decided to make it a preference in the final version of 3.0.0. Now you get to decide!

Sprintr 1.5 has been released!

Dear sprintr user,

This week, we deployed the 1.5 version of sprintr. We applied several performance improvements and introduced some small but significant usability improvements. Image popups have been enhanced and the like button now switches to ‘Unlike’ after liking. Furthermore we solved several long standing and difficult to reproduce bugs. For users of our mobile iPhone app, please update as soon as an update is available.

What’s next? The upcoming sprintr update will introduce a revamp of the styling and navigation of sprintr and will more closely integrate with our other products.

So, stay tuned!

The sprintr team.

Encouraging best practices with Test, Acceptance and Production

Mendix tries to stimulate best practices for development. One of these best practices is having different environments for development, testing, acceptance and production.

You need a very stable application, but you also need to develop new features very quickly. The Cloud Portal allows you to do both by offering either two or three online environments for each of your applications:

  • Test (optional)
  • Acceptance
  • Production

The idea behind this scheme is this: Production is the environment your end-users are accessing (https://yourapp.mendixcloud.com). This should always be online.

This application has an Acceptance and a Production environment

While you are developing new features you will do that in the Development environment with the integrated web server in the Mendix Business Modeler (http://localhost:8080/).

When you feel confident that your features work you can transport the application to the Test environment. (https://yourapp-test.mendixcloud.com). Your QA team can then unleash their testing procedures.

When the new changes have been thoroughly tested, you will probably want to move them to Acceptance (https://yourapp-accp.mendixcloud.com). Your client or an external party can then verify that the new version conforms to the expectations. Then, when the new features have been accepted, you can notify your users and transport the new version to Production.

In the Cloud Portal, this is easier than ever before. No more fiddling around with terminals, no more ssh keys, just fire up your web browser and point it to https://cloud.mendix.com/. We’d like you to try out The Mendix Platform!

The Sprintr Like Button; Tales of a 16 fold performance gain.

Everyone likes to like. And everybody likes speed. However, in sprintr, the like feature turned out the be the enemy of speed. In the next sprintr deployment, we will increase the speed of loading the messages by 400% and finally add an unlike button as well. Compared to the first like button implementation, messages in sprintr are now loaded 16 times faster. In this post we will explain how we achieved to gain this performance improvement. Your Mendix app might profit from these mechanisms as well!

TL;DR

In Sprintr we gained a 16 times performance improvement in loading a messages by using the following, general applicable techniques:

  • Remove all (!) virtual attributes and replace them with object events, custom widgets or security.
  • Introduce visiblity-by-security to show or hide attributes based on Xpath constraints
  • Apply data denormalization; uses multiple copies of an object to simplify security.  

Virtual attributes: Caught by reality

Image 1 - Naive Message model

Image 1 displays the Sprintr domain model concerning the message and like mechanism. Likes are stored in the Like entity, that connects a Message with a User. If a connection can be made from a Message through a Like to an User, the user has liked the message. Pretty straightforward.

In the original model, the caption of the like button is implemented using a virtual attribute. The attached microflow searches for a like that uses both the currentUser and the current Message. If such an object was found, the microflow returns ‘Unlike’. Otherwise, it seems that the user hasn’t liked the message yet, so we return ‘Like’. As a special case, if the current user is the composer of the message, an empty caption is returned since an user should not be able to like his/ her own comment.

Sadly, virtual attributes are costly in terms of performance when retrieved in large amounts, so the message walls started to become quite slow. The sluggishness of virtual attributes is primarily caused by the fact that they are re-evaluated on each retrieve. So for every message that is ever retrieved, the database performs an additional query that needs to join the user, message and like tables. This becomes expensive if done thousands of times.

Furthermore virtual attributes render database retrieval schemas useless. Normally the client requests only the attributes of an entity that it needs at that moment. A datagrid with 3 columns of an attribute with 20 attributes will only fetch 3 attributes from the database. However, when there is a virtual attribute the core pre-fetches all attributes of an object; they might be needed by the microflow of the virtual attribute. So instead of selecting just a few attributes, all attributes are retrieved from the database and sent to the client as soon as a single virtual attribute exists in an entity. In Sprintr, the message wall became about four times slower and consumed three times more bandwidth when the virtual attributes were added to the model.

Generally speaking, one should avoid virtual attributes wherever possible. Especially if they are used in larger datasets such as grids or graphs, or when the calculation itself is expensive. In my experience, 80% of the virtual attributes used in an arbitrary model can be easily avoided. Many virtual attributes just combine some other attributes and can easily be rendered client-side by the Format String widget as well (see this this post for an explanation). Other attributes can be calculated during a commit event or by using an update microflow that is triggered in the right places. Although this introduces some extra complexity, performance will greatly benefit.

Two cases of virtual attributes are hard to factor out: Attributes that depend on the current time (for example: “message posted 4 hours ago“) and attributes than somehow depend on the current user, such as the caption of the like button in Sprintr. In Sprintr, we solved the ‘ago’ issue by doing that calculation client side, using the Format String widget.

Security to the rescue

The like button caption is trickier to optimize. But we were finally able to factor out this virtual attribute by introducing a dedicated access rule on the attribute. To display the ‘like’ button, the value of the caption attribute is fixed to ‘Like’ in the domain model. The visibility of that caption can then be defined by assigning the following security constraint to the attribute:

[not(Sprintr.Like_Message/Sprintr.Like/Sprintr.Like_User='[%CurrentUser%]‘)]
[Sprintr.Message_Composer != '[%CurrentUser%]‘]

Or, in plain english: You are only allowed to see ‘Like’ if you did not like the message yet and you are not the composer of the message.

The advantage of this approach is that it is way faster than using virtual attributes, as the security will translate into efficient SQL joins and will not result in additional queries. Furthermore no like-state-synchronization needs to be modeled since security is always applied. This solution removes the bandwidth overhead of virtual attributes and it is multiple times faster, at least four times.

This visibility-by-security approach allowed us to toggle the visibility of several attributes in an efficient way and has been applied to several other message mechanisms as well; a conditional edit button, the vote status of ideas and the voted/not-voted status of polls. However, this approach makes the number of security rules grow rapidly, we ended up with 11 rules on a single entity.

This approach becomes tricky when the visibility of sensitive data needs to be governed by complex security rules; not only the condition needs to be expressed, but the general rules for the message as a whole needs to be repeated for this attribute as well. Since the basic message security in Sprintr is quite complex, the new rules became complex as well (a message can be visible because you are someone’s colleague, a project participant or a feedback submitter and all cases have their own edge cases). In the end, about 109 lines of security XPath were defined on messages, and querying the dashboard messages took about 3 seconds. Which, in my opinion, is actually surprisingly fast given the amount of data and the complexity of the query. But there must be a way to do better.

Data Denormalization: More data, more speed!

So we experimented with a method used by many web-scale frameworks; data denormalization. The thought behind this is that by copying all the user related data for each user, we can simplify the security. So, a single message no longer exists once in the database, but there is a copy for each user that can read the message. First results showed that this approach allowed to load messages 4 times faster. So, what did we do?

Image 2 - Denormalized messages

Basically, we added an additional entity, MessageProxy, to our domain model. This message proxy contains an association to an user and to a message. Upon every change or submit of a message, we create/update a message proxy for every user able to read the message. This introduces a lot of administrative logic when users join/leave a project et cetera, but as a result our security became as simple as ‘You are allowed to read a message proxy if it is yours or you are allowed to read a message if you have a message proxy of that message’.

In the rendering, each message is a combination of a proxy and its related message; common attributes such as timestamps are stored on the message, but user-specific data such as the like/unlike button caption is stored on the proxy and can easily be updated when the user votes.

This approach does have its downsides; message might take up a 100 times more space in the database (if many users can read it) and writes are much slower. When changing a message it might be needed to update 100 proxy objects as well. Regarding the storage issue, we can afford to not really care. It is not that much data in the end, especially compared to document or file uploads. The slower write issue would slow the UI responsiveness, but that can easily be solved by performing the message updates asynchronously in the background (using the community commons functions executeMicroflowAsync or executeMicroflowInBatches). Only the message proxy of the current user is updated synchronously, otherwise he would still see the previous proxy version.

Data Denormalization resulted in another 400% performance boost in loading messages (in fact, even more as the model grew more complex in the meantime) as it severely simplifies security.

Errors with multiple locations

One of the advantages of having a visual model and no source code is that there is less room for errors. There is no need to match braces or add forgotten semi-colons while drawing your microflow. Of course, errors can still be made and the Modeler constantly checks your model and reports the results in the error list.

For some errors it is not clear which model element is to blame. Take for example the following error message:

The grid of the pop-up form must contain a ‘Select’ button.

What might the cause of this error be? Either you forgot to add a ‘Select’ button to the grid or you selected the wrong form as the pop-up form of the reference set selector ‘Add’ button. If you double click the error, it will take you to the pop-up form where you can add a ‘Select’ button. But if that was not the problem you can also right-click the error and jump to the ‘Add’ button and fix things there.

An error with two locations

An error with two locations

So the next time you end up at the wrong location when double clicking an error, be sure to check whether there are alternative locations to jump to!

Version control without source code

Most software is defined in source code. Not so with Mendix. The most important part of every Mendix project is its model, which contains the domain model definition, forms, and business logic for a Mendix application. This model is interpreted and executed by the Mendix Runtime, resulting in working software.

Version control for developing applications in Mendix is based on Subversion. Subversion has excellent support for text-based diffing and merging, which is used for project resources such as Java actions and theme files. However, since we chose a binary file format for the model file, we cannot use Subversion’s text-based merge algorithm to merge changes between different revisions of the model.

That is why we created our own merge algorithm for the model. The model can be seen as a gigantic tree structure starting with the project as the root node that contains modules, which in turn contain folders and documents. The tree goes all the way down to model elements such as attributes and microflow activities. Therefore, our merge algorithm is tree-based and merges changes between different versions of such trees.

The merge algorithm takes three model trees as its input: the base tree, and two changed trees, called ‘head’ and ‘mine’. This is called a three-way merge algorithm. The first step of the algorithm is to calculate the changes between base and head and those between base and mine. Then it attempts to merge those two lists of changes into one that can be applied to base to yield the merged tree. If it encounters conflicting changes, conflict markers are placed at those locations in the resulting tree. The following image shows an example of a tree merge.

An example tree merge showing how two sets of changes to a base tree are merged.

An example tree merge. Head changed object B, while mine moved B below C and added D. The merged tree contains all of those changes.

The merge algorithm begins by scanning the project structure (modules, folders, and documents) for changes. It detects additions, moves, deletes, and edits. Edits are detected by comparing a hash of the contents between base and the changed tree. This is done to speed up the merge process; unchanged documents do not need to be processed further. If conflicting changes are detected between head and mine, those items are marked as tree-conflicted.

If a document’s contents have changed in both head and mine, then those changes need to be merged. This is done in much the same way as the project structure is merged. Additions, moves, deletes, and edits to both head and mine are detected and attempted to be merged into a single list of changes. If conflicting changes are detected, conflict markers are added.

One advantage of using a tree-based merge algorithm as opposed to a text-based one is this: In text-based merge, when one person moves a block of text while the other modifies it, a conflict will arise. In our tree-based merge algorithm we can merge those changes because we can track a node even though it has been moved. Every node in the model has a unique identifier so that all nodes can be distinguished from each other. If you only have source code, you can not have a unique identifier for text blocks. You could try to use a hash for this, but that changes as soon as the source code changes.

Another advantage is that we have full control of the merge algorithm. We don’t want our users to have to solve a bunch of textual conflicts in the “source code” of their visual models. We present the conflicts visually in a list, allowing users to navigate to the conflicted area in their visual model. The user can use the conflict information in the list to decide how to resolve the merge conflict.

Conflicts represented in the Mendix Business Modeler

In short, our version control feature builds on Subversion and improves on its text-based merge algorithm for changes to the model. Since Mendix models are not text-based like most software source code is, we can use a tree-based merge algorithm that allows more changes to be merged, resulting in fewer conflicts and therefore faster development.

Introducing the new Mendix Tech Blog

Welcome to the new Mendix Tech Blog! We are adding new categories to the blog and we changed its name. The categories are:

  • Techtips: general tips for working with Mendix on a daily basis.
  • R&D: Over the years our own developers and sysops have gained opinions on technology that are worth sharing. Interesting stuff!
  • Advanced Mendix: We have quite a lot of advanced use cases of Mendix projects, such as setting up the Mendix Runtime on obscure operating systems or implementing custom request handlers. You will find scenarios of that kind here.
  • Release Announcements: Between all the time spent solving tickets we also manage to release new versions of the Platform, Cloud Portal and Sprintr.

We hope you will enjoy our new blog and we are looking forward to your comments!