There’s a Tool for That - TinyPNG.org
But one thing is as easy as pie: keep your images file sizes small.
Enter TinyPNG.org. A service that trims a lot of fat from your PNG images without a noticeable difference in quality.
Let’s see an example:
The Squirro logo, as saved by Photoshop CS6, 20.6 kilobytes
Now the same image, optimised with TinyPNG.org, 9.7 kilobytes
Thats a 53% reduction, and I can’t see a difference. Can you?
There are other tools out there. OptiPNG and pngcrush both reduce the above Photoshop image by about 13%. While these clearly can’t keep up with size reduction, both are open-source and command line tools. You can easily include them in scripts and applications. For example you can automatically optimise all of the png files that your users upload. With TinyPNG this is not feasible, as you have to go to their site and optimise them manually.
Its also important to understand that TinyPNG reduces the numbers of colours in your image. So there may be cases where an optimised image looks worse. But I yet have to see such an example.
So, go ahead and speed up your site. Run all of your sites PNG’s through TinyPNG.org. It’s easy & free, but don’t forget to donate and keep panda George happy.
What tools are you using to reduce your file sizes? Do you know of a tool that can beat TinyPNG?
Customization within Multi-Tenant Platforms
Using a cloud-based multi-tenant architecture for your software product works great. Every one of your customers is served from a single installation. Upgrades are simpler to perform compared to an on-premise operation model. It might even be the case that only a single version of your software is installed in your entire environment.
It all looks great. Then one day the whole team meets to plan the next iteration of the product. The conversation could start like this: “Good job guys pushing out the new release yesterday! It’s fantastic to use our new search functionality. Let’s release it to beta users next week. And to paying customers at the end of the month.”
As outlined in the beginning of this article using a multi-tenant platform is beneficial from an operators point of view. However, the price one has to pay lies in the increased complexity. The same installation will need to be customized in terms of branding, work flow, or even access control. At Squirro we are building exactly such a multi-tenant platform to serve all of our customers. In order to e.g. customize a certain work flow there is a central service which allows configuration values to be stored in an efficient and hierarchical manner.
What works great is to exploit the fact that configuration values can be the same for a set of users. You can for example define which logo to show in your front end web application for all users of a single customer. For storage and maintenance reasons you are better off to not store this information for every user individually. However, the hierarchical nature of the system still accounts for the fact that a single user might have a different need. In the picture below you can see how configuration values are organized. At the very top there is always a default entry for any configuration value that is stored within the system. Below that users can be grouped into tenants and groups. At the bottom level a value can be present for a single user.
As our architecture is based on independent HTTP services the configuration values stored on persistent storage are exposed via a RESTful interface. Any module that needs to fetch values from the configuration service uses our Python client library. It abstracts away all the boiler plate HTTP calls and the corresponding error handling routines. Moreover, the library contains a time-based cache which expires cached entries after a given time period. Such a design makes sure that on one hand the service is not contacted on every request to get the same configuration value. On the other hand a time based cache makes sure that updated values on stable storage get propagated eventually.
So let us walk through an example and see how things look in actual Python code. The goal is to query the configuration service to check whether the improved search functionality is enabled for a particular user. First we import our client library and create a new client. Then we can query the service and make sure that configuration values are stored within an in-memory cache of the current process.
The code example above shows how to get the default value which is used as a feature switch. But now the hierarchy of the system allows us to store values for all users of an tenant. Or we can fine tune the setting for an individual user. In the code example below it is shown that the new search functionality has been enabled for a particular software engineer who is currently testing the new feature. All the other members of the team get the value which is defined for the tenant.
There are many use cases for the usage of a configuration service within a multi-tenant environment. The scenario of work flow customization has been highlighted above. Taking advantage of the hierarchical nature of configuration values is crucial to make such a service scale and be used throughout a multi-tenant platform.
Writing a Responsive Application with Backbone.js
The original concept for this came from Pierre Spring of Nelmio. We have since extended it, so the blame for the weirder parts belong to us, not Nelmio.
Challenge of Responsive Design
Responsive Web Design aims to build one web site for all device types and sizes. This is usually accomplished using media queries that check for the screen size. At Squirro we believe that this is great but not enough. It’s necessary to also adjust the behavior or feature set per platform.
Just a simple example from Squirro for that. The settings are split in various sections. On the desktop we show a navigation with the sections on the left and then the actual settings on the right. On mobile we need to provide that navigation first as a full page view. Then on clicking we show the actual settings, again using the full page.
It’s probably possible to do that with pure CSS but separating the implementations makes the implementation cleaner.
What follows is a code-level description for how we implemented this.
As a first step we decide on page load which edition we want to use. Yes, that prevents us from going textbook responsive as we don’t re-render on window resize. But in our opinion the problem we want to solve is really not browser window resizing but device adaption.
This is a simplified snippet from our
As you can see we use three different RequireJS entry files for the different editions:
The main job of those entry files is configuring the RequireJS paths. That’s the main approach we use to decide which views, controllers and templates get used for the respective devices.
As an example, this is an extract of how it looks inside
As you can see we load separate views, controllers and templates based on device type. We sometimes overwrite the path for a full folder (controllers) and sometimes on a per-file basis (views and templates).
After setting up the paths the job goes to
app-common.js to initialize the application itself.
That file basically looks like this:
Because of the RequireJS path setup the page view will now be loaded in a device-specific way.
To make sure we can re-use code, we usually inherit from a base class. For the sharing example there can be a
BaseShareView which the individual device-specific views inherit from. That base class at
views/base/Share.jslooks something like the following:
The actual desktop view then simply inherits from this base view and extends it where needed:
The final ingredient to get this to work was proper setup of the r.js building tool. To get that to work we parse the individual entry files (such as
app-desktop.js) and replicate the path setup in the build configuration file.
So far this has enabled us to replicate the web site relatively easily to the various device types. We’re constantly tuning the setup to make it more maintainable and reduce duplications as much as we can.
Unfortunately there’s no comment section here but you can contact me on Twitter (@pneff) if you have feedback or questions.