February 21, 2006

Ajax

Filed under: Web development — Dimitris Giannitsaros @ 23:45

These days I’m doing some Ajax stuff, mainly for fun but also getting familiar with the various libraries and frameworks that exist (certainly check out Prototype if you’re interested).

It’s interesting how using Ajax in a few carefully selected parts of an application, can completely change the experience (the hard thing is identifying these parts).

February 13, 2006

Windows installer

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 18:38

I have decided to create an installer (windows only) for Magna CRM. This will install a web server (apache or lighthttpd) and a completely pre-configured environment (prefilled Access database and configuration files).

There are 2 reasons to do this:

  1. Offer an extremely easy way to install the trial. Right now you must know of things like web server, document root, Access / MySQL / SQL Server, permissions etc. in order to run the web based installer. With a Windows installer you’ll only have to press Next 4-5 times and maybe fill in 1-2 fields.
  2. Offer this as a permanent solution for very small businesses. There are thousands of small businesses out there with 1-10 employees and no IT department. These could take advantage of the easy installation procedure without having to ask a 3rd party to install it.

Although this doesn’t look especially hard, there are many things to research: If the Apache / lighthttpd licenses allow redistribution, if the web server will be installed as a service (better overall but Xp/2000 only), how updates will be handled and what installer to use (I’ve used NSIS in the past but I am not sure its scripting language will be up to it - maybe I’ll have to check InnoSetup). Moreover this will create an extra step when releasing a new version but I hope to integrate this procedure in my current build process.

December 6, 2005

View mode

Filed under: Web development — Dimitris Giannitsaros @ 21:11

I am wondering if view mode is necessary in web apps and specifically ones with a lot of data manipulation (e.g. CRM software). Forms could show up in edit mode (assuming the user has enough rights) completely bypassing view mode. On the other hand, reading data in text-boxes can be tiresome.

A somewhat nice solution is going into edit mode after double clicking a field (like Flickr does for titles and descriptions). But then again theirs are not full blown, complicated forms. Moreover I recently found Tim Taylor’s site where he displays his work on this front (in place editing).

The truth is it’s too late to even consider doing something like that for Magna (plus I’m not sure it’s a better approach). However I’ll certainly research this more in the future. In the meantime, if you happen to know any application (with many forms) using in place editing, please mail me or leave a comment here.

November 14, 2005

Internationalization (i18n)

Filed under: PHP, Web development — Dimitris Giannitsaros @ 10:42

In order to offer localized versions of an application, there are two things to be taken care for:

  • Internationalization (i18n): this is more development centric and it’s all about designing your application to support translations, foreign character sets, timezones, different number / currency / date formats etc.
  • Localization (L10n): using the mechanism provided by i18n, this includes the actual translation and settings for a new language.

On this article I focus mainly on the translation part of the i18n process, although many other subjects are touched.

There are two approaches for translating strings:

  • Using a function to wrap your strings in your code. I call this the “gettext” approach (also check PHP gettext support). Of course it’s not the only tool that offers this functionality, but it supports many languages and it’s open source.
  • Using constants or variables instead of strings in your code. One or more language files contain the actual strings and these files are included by your application.

Lets see some general facts on these two approaches:

The “gettext” approach:

  • Is more complex.
  • Is suitable for large projects with thousands of strings.
  • Allows strings to be stored in a DataBase or an efficient data structure.
  • May utilize a special translating program.
  • May offer a better management of deprecated and changed strings.
  • Offers better domain management (think of domains as logical areas of the application e.g. the administrator’s area, the user’s area etc)

The “language file” approach:

  • Is significantly simpler.
  • Is better for smaller projects.
  • Stores strings in text files, so editing is easy for anyone.
  • Doesn’t force any good habits upon you, so you have to be careful.

I’ve used both approaches in web and desktop applications (most notably Cheez, a free image cataloguing tool, currently translated in 17 languages). The “language file” approach is my favorite, so what follows is some advice on using this approach:


Language scope

For multiuser applications, you must consider whether all users will have the same language (so language is a system setting) or each user will choose his language of choice (so language is a user setting).

The same rules apply to both cases, but you’ll need to make some design decisions based on that.

Single file vs. many files

It’s better to use a single file instead of many files. If this is becoming a really big file, maybe you should check the “gettext” approach. Exception: if your application supports plug-ins (e.g. user created stuff), make sure you provide a mechanism where each plug-in has its own language file (preferably a single file per plug-in). You don’t want to litter your core language file with strings specific to plug-ins.

For an example of why multiple files can get out of hand check osCommerce, which uses about 80 files per language in many directories. Moreover each plug-in is allowed to have many language files, making things even worse. Note: Other than this inconvenience, osCommerce is a very good and popular shopping cart solution.

Images

Handling localized images can be a bit tricky. You have at least 3 options:

  • All images have the same name, but are placed in different directories (/english/, /greek/, /german/). Your code uses the right directory based on a string included in the language file.
  • Images have different names, using a standard prefix / suffix (icon_delete_ENGLISH.png, icon_delete_GREEK.png).
  • Images can have any name as long as it’s defined in the language file with the rest resource strings. Your code loads images using the appropriate string. Of course it’s a good idea to use a naming convention for images (e.g. a suffix).

Personally I prefer the 3rd option. This way your code doesn’t do anything different than for normal strings, plus translators know what images must be changed just by looking the language file.

Other i18n settings

Be careful what i18n settings go into the language file. This can be a problem especially for web applications, where users can be anywhere in the world.

Many projects I’ve seen put things like the date / number / currency formats and timezone in the language file. It’s much better to have these as user settings: just because a user prefers a specific language e.g. Greek or German, it doesn’t mean he’s currently based in Greece or Germany.

Of course, which settings should go in the language file and which are made available as a user setting depends a lot on what your application does, what kind of users it has etc.


Charset

If your application supports Unicode you probably need only one charset (e.g. UTF-8), so you can skip this paragraph.

Charset is very important for two reasons: a) It allows users to correctly view localized characters. b) It allows users to correctly enter (and store) localized characters. The first thing that comes to mind is to put charset in the language file.

This is usually good enough, but has a small problem: Imagine your web application currently supports English. Inside your language file you’ve set a variable for the charset (e.g. $charset=”ISO-8859-1″) which you use for defining the charset of the html files. Imagine a Greek installs your software and tries to use it. Although he knows English, he would also like to insert data in Greek. Since you have tied the charset (ISO-8859-1) with the interface language (English) he can’t! If he could change the charset to “ISO-8859-7″ he would be able to enter and view Greek text (and of course the English strings of the UI would be displayed correctly).

I am not arguing that it’s always the right thing to offer charset as a user setting. Just remember that the language file’s purpose is to have the localized resource strings, without interfering with the way the application works.

Good resource strings

Some general guidelines for creating good resource strings:

  • Be careful to use complete sentences as resource strings while coding. Concatenation must be kept to a minimum and special language functions must be used to format strings (printf(), sprintf() for PHP).

    So instead of

    $location . " contains " . $count . " files";

    which needs 2 resource strings and the translator doesn’t see this as a complete sentence, use

    sprintf("%s contains %d files", $location, $count);

    which needs 1 resource string and actually makes sense to the translator.

  • If support for argument ordering is available, use it (PHP has it). So the above example would become:

    sprintf("%1$s contains %2$d files";

    which needs 1 resource string and the translator can change the argument order e.g.

    "%2\$d files are contained by %1\$s"

  • Try to keep related sentences in one resource string. “Command failed. Abort or retry?” should be one resource string, not two.
  • Sometimes it’s best to use different resource strings for the same word / phrase. This is hard to get right, because as a developer you don’t know which words have many different meanings in other languages. One solution is to use a different resource string for all strings. So if your application uses the word “Save” 28 times, then you have 28 different resource strings for “Save”. This can be extra work, both for you and the translator, but guarantees a better translation quality level can be achieved.

    The best solution is somewhere in the middle. This way simple words (”yes”, “no”) can be mapped to a single resource string, while more complex words (”execute”) have a separate resource string for each occurrence.


Resource strings naming convention

Obviously it’s a good idea to have a common prefix for resource strings (e.g. lc_). The rest of the name can be either an increasing number or a description:

$lc_res1
$lc_res2
$lc_res3
$lc_res4

or

$lc_yes
$lc_no
$lc_execute1
$lc_execute2

Although the 2nd group seems much clearer, after about 1000 strings it becomes difficult to think of good descriptive names and you end with things like

$lc_warn_user_after_failed_sql_execution_offer_to_retry

Domains

If you want to logically separate the resource strings based on different areas / parts of your application you may be tempted to use multiple files. I believe it’s always better to keep to one file and just use some comments for domain separation. So you can have:

// Admin area

$lc_admin_res1 = “”;
$lc_admin_res2 = “”;

// User area

$lc_user_res1 = “”;
$lc_user_res2 = “”;

Versioning

This is the single most important advice on this article.

After you release your first public version, you must never again change a resource string. Even if you find a typo or something bad you wrote about your boss or wife.

Both new and changed resource strings go at the end of the file. Moreover it’s good to keep a comment about each version:

// Version 1.0

$lc_yes = “Yed”;
$lc_no = “No”;

// Version 2.0

$lc_yes = “Yes”; // correction
$lc_new = “New”

// Version 3.0
(v3.0 resource strings will go here)

Note that the $lc_yes resource string was corrected in the new version, while the old resource string stayed the same.

There are a number of reasons to uphold this policy:

  1. Translators have a much easier job with new versions. They just go to the end of the file to find new / changed strings. Changed strings are marked with “correction”, so they can find the old translation by searching. No need to use tools like diff, to try and find what has changed between versions.
  2. You can have a single file per language that works for all versions. If you translate the v2.0 file, you can send it to someone using v1.0 and he’ll have no problem.
  3. When you release a new version (e.g. v3.0) you may not want to wait for translators to translate the new strings. So you just copy-paste everything under “Version 3.0″ from the original language file to all other languages files and you’re good to go (so for foreign languages, old strings will remain translated while new strings will be untranslated).

Used images are under a CC license. See here:
1st image, 2nd image, 3rd image, 4th image

I was writing an article on PHP and timezones (promised here), but then I changed my mind and decided to write and publish this one first. The one about timezones will be next.

November 7, 2005

Better error feedback

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 15:38

I use Javascript to give feedback on missing required fields and invalid data (bad numbers, wrong dates, out of range values etc). Before sending user data to the server (where they are validated again of course), a function checks all fields for errors and if any are found, it reports them to the user and sets the focus to the first erroneous field.

So the user would see a javascript alert with something like this:

-Title is missing.
-Start date is missing
-End date is invalid
-Quantity is not a valid number

After clicking OK, focus would move to the “Title” field. The problem here is that the user must remember all other errors or press “Save” again to see the list of remaining errors.

So I did a minor change to the validation functions, so that the erroneous fields’ border color changes to red. This is much better but lets say the user fills the “Title” and hits “Save” again. The title’s border color must be changed back to what it was. The easiest way to do that was to set the border color property to an empty string. This removes the red color and redraws the field using the appropriate CSS. So most checks use this approach:


if (elem.value == '') {
err_txt += ('Missing value\n');
[some irrelevant stuff]
elem.style.borderColor = ‘#aa0000′;
} else {
elem.style.borderColor = ”;
}

I am not sure the empty string is the “correct” way to do this, as the w3c DOM spec doesn’t define what happens in this case, but it works in IE, Mozilla and Opera.

September 25, 2005

Undo in web apps

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 21:27

Undo in web applications is not very popular. Actually, I have used no web app that had extensive undo capabilities. I was reading about this recently somewhere and started thinking if I could make an undo feature for MagnaCRM and how I would go about implementing it. I certainly don’t intend to do it for v1.0 as I already have a full plate.

I think the most difficult operation to undo is a delete, because deleting a record may require deletion of dependant records (e.g. delete an account and you also delete all related contacts). Moreover, instead of deleting from the database you must only flag affected records as deleted. The good thing is that I can offer undo for delete operations easily, since I already have a Recycle Bin feature (deleted records go there and you can undelete them at any time).

Edits seem easier to undo although they could prove to be trickier. You need some kind of auditing mechanism that logs all changes done to records by each user. Then you use that to go back to previous states and you could even offer a redo.

The question that I needed to answer is: should I offer an undo feature that will only undo delete operations or leave it all for next version? I’ll probably do the later, as it will be rather confusing to have an undo button after deleting a record but not after editing it! For v1.0 the Recycle Bin will have to suffice: you can still undelete something even if no convenient undo button is offered.

September 21, 2005

Missing value

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 13:12

Here is an interesting problem:

While using an application you edit a record with the intention to change the value in a drop-down list. Available options are A, B, C and B is currently selected. So you change that to C and save. Now, you change your mind and try to make it B again, but option B is now missing from the available options.

Here is why this happens: the admin has edited the available options for this drop-down list and removed option B. Records using this value still show it, but after selecting a different option there is no need to show it again.

Of course this is way too unfriendly and weird. I could only think of three solutions to this problem:

  1. Do not allow the admin to remove options used by at least one record. The problem here is that if the admin makes a mistake while creating options, there is no way to fix it other than manually editing all records using the particular option.
  2. Make the admin select an option that will take the removed option’s place. E.g. “Remove option B and put option C in all records using it”. This is not always easy: imagine a field “How did you hear about us” with starting options “Internet”, “Magazine”. Now the admin wants to remove “Internet” and add “Internet: ad”, “Internet: web site”, “Internet: search”. He can’t really replace the old option with one of the new three.
  3. Add a small descriptive text to removed values. So the user would see these options: “A”, “B [removed]“, “C”. This way, no one has decided the new value for him and he is informed that option B is now deprecated. He can either select a new value or leave it as is. Moreover the admin has no problems in removing options.

I went with the 3rd solution which, while not super user-friendly, is at least flexible.

September 9, 2005

Tableless design

Filed under: Web development — Dimitris Giannitsaros @ 00:31

When I started MagnaCRM I decided to use a table-less design. I read too many articles about how using tables for positioning is evil (after all, tables should be used for tabular data only) and decided to go along.

I am now coming to regret it. Yes it feels nice to know that every aspect of your layout can be changed through a single CSS file. And yes, I understand it’s the “right” thing to do.

But it started getting on my nerves with the small differences between browsers. As if javascript incompatibilities aren’t enough of an issue. I am considering going back to good old tables. The only thing keeping me, is the flexibility to offer completely different layouts. Then again, with the right dose of tables and CSS I could probably achieve the same level of flexibility.

September 2, 2005

High Performance MySQL

Filed under: General, Web development — Dimitris Giannitsaros @ 17:54

I just finished reading High Performance MySQL for the 2nd time. This book is full of insightful advice plus it’s relatively small (because information is packed). I rarely read IT books more than once, but this one had a lot of things I missed on the first pass.

August 25, 2005

Nifty javascript trick

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 17:57

While using FogBugz I noticed that textareas grow as you type in them. I thought this was quite cool and useful so I tried to mimic it for MagnaCRM.

FogBugz implementation was a little specific to their needs and I needed a more generalized way of doing it. This article was a good guide (it seems FogBugz solution is based on that too) and with some customization I managed to make it work as I wanted.

Of course the hardest part was making it behave nicely on all browsers. Although I am against browser detection techniques (when that’s possible), the code handles IE differently than all other browsers. Opera was a real pain and it’s not working as it should after all (the textarea grows at once to the maximum row number allowed by my script). It’s not really my fault, as Opera should not try so hard to pass as IE if it doesn’t really support the same features. Moreover I haven’t tried it on Safari, as I don’t have a Mac. I hope it handles it well!

Finally I should note that while I thought this would be a 5 minute hack, I ended up spending almost an entire day, trying various ways to achieve the desired effect and browser compatibility…

August 11, 2005

Small choices

Filed under: MagnaCRM, Web development — Dimitris Giannitsaros @ 14:20

Every day, I have to make many small choices while working:

  • Break my coding style sometimes, because in specific cases it looks better
  • Refactor / rewrite something unimportant now vs. later (=never?)
  • Move small features from v1.0 to later and vice versa
  • Fix a bug now vs. putting it in the bug database for later
  • Reorder my todo list, so I can pick an interesting task instead of a boring one.

I know people have strong feelings about many of these subjects and there are tens of articles on what is right or wrong (”always fix bugs before writting new code”, “stick to your coding style” etc). I am no exception and I have read most of these brain washing articles / books.

But sometimes to move forward you have to break the rules.

So I am trying not to press myself too much on things like that. Because I have concluded that it’s not that important. These things I am talking about, are not of great importance, so I can’t believe it will be the end of the world if I break some rules now and then. And if it takes me out of my “coder’s block” (you know: check email, check bloglines, surf here and there, loop), then it’s all for the best.

June 28, 2005

More on Rails

Filed under: Web development — Dimitris Giannitsaros @ 13:59

I can’t spend any more time playing with Rails. It was fun and I have seen enough to know what this is all about and what I am missing. The Ajax tutorial was probably the most exciting one. Wondering if an action should be ajax based? Well just build it and see how it feels. With Rails it’s not like it will take you much time. And it will get better, much better, with things like autocompletion (like Google Suggest) and all other great scripts from script.aculo.us.

Ruby seems OK too, not that I was thrilled. I am not overly excited about any language, but I wonder what would have happened if David Heinemeier Hansson (Rails creator) had chosen a more popular language (e.g. PHP or perl). As it is, Rails is dragging Ruby up, while it should be the other way around.

It’s still early for anyone to know with certainty if Ruby on Rails will get really big. Hosting is a problem right now. There are some hosts supporting Rails (TextDrive, GeekISP, Planet Argon) but nowhere near those offering PHP hosting (virtually all).

On the other hand, the Rails part of the RoR equation, will probably make it, maybe by another language. I was pointed to PHP Cake and there is also Perl on Rails and Subway for Python. And that is good, because as a framework, Rails permits for really rapid development, without sacrificing quality.

June 27, 2005

Learning is fun

Filed under: Web development — Dimitris Giannitsaros @ 23:29

Spend most of the day playing with Rails. Learning a new technology can be addictive and you can have a really good time (if you are into this kind of things). I haven’t done this for some time (more than a year) and it felt quite refreshing. Learning something new, whether good or bad, offers new ways to see things, opens up the mind. I hope I have the time to do it more often, now that I remembered how good it is!

Rails verdict coming soon!

June 26, 2005

Ruby on Rails 2

Filed under: Web development — Dimitris Giannitsaros @ 14:01

I now have about 3 hours of Rails experience! Installation was a breeze, Hello World a no brainer. I followed the “Rolling with Ruby on Rails” tutorial (part I, part II), and I think I can see now why they say you can be very productive with Rails.

Things are still mingled in my mind, but what knowledge I have gained so far follows: Rails enforces the model view controller design, has a strict directory structure and utilizes special naming (e.g. a DB table called tasks and a class called Task are connected). One nice thing is that data lists and CRUD operations (create, retrieve, update, delete) are completely automated (scaffolding) for simple objects (no joins etc).

All these seem a bit restrictive at first and I don’t know what happens if you want to do things differently (though I guess it can be done). But the consequence of these rules is that you can do things extremely fast. Building a simple application (e.g. a phonebook application) can be done in a few hours. You don’t have to build any infrastructure, as this is exactly what Rails provide.

I still have a constant feeling that it can’t be used for “advanced” applications, even though I understand I am mistaken (Basecamp and Backpack are advanced enough).

I will continue experimenting with Rails because:
a) It’s fun
b) It’s different
c) I want to understand it better, so I know what people are talking about
d) I want to see how it integrates with AJAX

June 25, 2005

Ruby on Rails

Filed under: Web development — Dimitris Giannitsaros @ 15:31

I see Ruby on Rails mentioned everywhere. So I decided to have a look, because usually when so many smart people are excited about something, there is good reason. I have never worked with ruby before, so this will be another new for me.

I am installing right now and hope to have my first Hello World program up and running very soon!

Next Page »

Powered by WordPress Theme by H P Nadig