Saturday, October 8, 2011

Principles to follow while coding

Simplicity leads to better code.
Keep-It-Simple-Stupid (KISS)

Don’t optimize prematurely.
It is much better to get the design of your code right and leave performance improvement as a separate task requiring separate skills,

Interfaces promote flexibility of design.
Interfaces enable us to define the contract without regard to the underlying implementation. Because of this, they give us flexibility in our design by facilitating pluggability of implementation.

All production code should be covered by automated unit and functional tests.
Modern development practices demand that our software be rigorously united and functionally tested to ensure the ongoing integrity of the code. In keeping with this approach, after defining the interface, but before defining any concrete implementation, we translate our functional requirements into test cases, ensuring that every assumption has been covered and confirmed.

This approach, also known as test-driven development (TDD), forces us to concentrate on the contract, the published behavior, of our classes, rather than the implementation.

Assertions are a developer’s best friend.
 Check for null pointers; assert that objects are in the correct state at the start of a method, and so on.

COM

COM is totally independent of location because objects are registered in the operating system with their location.  

Now with DCOM, you can distribute your application across a network, such as your company intranet without extra code writing. And finally COM+, in the Windows 2000 OS, is the latest incarnation of COM that adds COM functionality into the operating system and provides advanced functionality, such as the Microsoft Transaction Server (MTS) and Dynamic HTML (DHTML) and other Web services.

How does this happen and what do we mean by the client and server? The client is defined by where the functionality of the server or object is needed. Thus the client calls the server to get the required functionality using the COM architecture. The server or object is defined by where the COM developer puts his/her work. COM servers can be either DLLs or EXEs. The server provides one or more objects for the client and also provides the relationship or hierarchy of the internal object functionality.

Clients view objects as black boxes that provide the functionality they require. Clients communicate with objects through interfaces, and objects, or servers, can handle more than one interface. COM interfaces are a set of related methods or functions. An interface does not describe the implementation underneath, giving the developer the option of changing how something is accomplished without having to change the whole application. Interfaces cannot be changed after they have been published. Because COM defines a standard for in memory layout of interfaces, the objects are compiler and language neutral, meaning objects can communicate without having to be written in the same language. Interfaces help with versioning and updating of objects, in that a developer can place the new functionality of an updated version in a new interface. Newer clients can query for the newer interface and use it if present, but still function with the older functionality.

Law of Demeter

Source: 
http://en.wikipedia.org/wiki/Law_of_Demeter

The Law of Demeter (LoD), or Principle of Least Knowledge, is a simple design style for developing software, particularly object-oriented programs. In this general form, the LoD is a more specific case of the Low Coupling Principle.
Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
Each unit should only talk to its friends; don't talk to strangers.
Only talk to your immediate friends.
More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:
  1. O itself
  2. M's parameters
  3. any objects created/instantiated within M
  4. O's direct component objects
  5. a global variable, accessible by O, in the scope of M
The advantage of following the Law of Demeter is that the resulting software tends to be more maintainable and adaptable. Since objects are less dependent on the internal structure of other objects, object containers can be changed without reworking their callers.
A disadvantage of the Law of Demeter is that it sometimes requires writing a large number of small “wrapper” methods (sometimes referred to as Demeter Transmogrifiers) to propagate method calls to the components

UI Concepts

A user interface is well designed when the program behaves exactly how the user thought it would.

A user interface is well designed when the program model conforms to the user model.

A new user who sits down to use a program does not come with a completely blank slate. They have some expectations of how they think the program is going to work. This is called the user model: it is their mental understanding of what the program will do for them.

The program, too, has a model, only this one is encoded in bits and will be faithfully executed by the CPU. This is called the program model, and it is The Law. Nothing short of electrical storms and cosmic rays can convince a CPU to disobey the program model.

Let's look at another example. In Microsoft Word (and most word processors), when you put a picture in your document, the picture is actually embedded in the same file as the document itself. You can create the picture, drag it into the document, then delete the original picture file, but the picture will still remain in the document.
Now, HTML doesn't let you do this. HTML documents must store their pictures in a separate file. If you take a user who is used to word processors and doesn't know anything about HTML, then sit them down in front of a nice WYSIWYG HTML editor like Microsoft FrontPage, they will almost certainly think that the picture is going to be stored in the file. 

Call this user model inertia, if you will. So, we have an unhappy conflict of user model (the picture will be embedded) versus program model (the picture must be in a separate file), and the UI is bound to cause problems.

Thursday, January 20, 2011

Qt translations working



Qt minimizes the performance cost of using translations by translating the phrases for each window as they are created. In most applications the main window is created just once. Dialogs are often created once and then shown and hidden as required. Once the initial translation has taken place there is no further runtime overhead for the translated windows. Only those windows that are created, destroyed and subsequently created will have a translation performance cost.
Translation files consist of all the user-visible text and Ctrl key accelerators in an application and translations of that text. Translation files are created as follows:
1.      Run lupdate initially to generate the first set of .ts translation source files with all the user-visible text but no translations.
2.      The .ts files are given to the translator who adds translations using Qt Linguist. Qt Linguist takes care of any changed or deleted source text.
3.      Run lupdate to incorporate any new text added to the application. lupdate synchronizes the user-visible text from the application with the translations; it does not destroy any data.
4.      Steps 2 and 3 are repeated as often as necessary.
5.      When a release of the application is needed lrelease is run to read the .ts files and produce the .qm files used by the application at runtime. The QM file format is a compact binary format that is used by the localized application. 
For lupdate to work successfully, it must know which translation files to produce. The files are simply listed in the application's .pro Qt project file, for example:
    TRANSLATIONS    =           tt2_fr.ts \
                                              tt2_nl.ts
This is how a simple main() function of a Qt application begins.
    int main( int argc, char **argv )
    {
        QApplication app( argc, argv );
 
        QTranslator translator( 0 );
        translator.load( "tt1_la", "." );
        app.installTranslator( &translator );
               …………
 
Line by Line Walk-through
 QTranslator translator( 0 );
Creates a QTranslator object without a parent.
        translator.load( "tt1_la", "." );
Tries to load a file called tt1_la.qm (the .qm file extension is implicit) that contains Latin translations for the source texts used in the program. No error will occur if the file is not found.
        app.installTranslator( &translator );
 
Adds the translations from tt1_la.qm to the pool of translations used by the program.
        QPushButton hello( QPushButton::tr("Hello world!"), 0 );
Creates a push button that displays "Hello world!". If tt1_la.qm was found and contains a translation for "Hello world!", the translation appears; if not, the source text appears.
 
For a translation-aware application a translator object is created, a translation is loaded and the translator object installed into the application.
    int main( int argc, char **argv )
    {
        QApplication app( argc, argv );
 
        QTranslator translator( 0 );
        translator.load( QString("tt2_") + QTextCodec::locale(), "." );
        app.installTranslator( &translator );
               …………
 
In production applications a more flexible approach, for example, loading translations according to locale, might be more appropriate. If the .ts files are all named according to a convention such as appname_locale, e.g. tt2_fr, tt2_de etc, then the code above will load the current locale's translation at runtime.
If there is no translation file for the current locale the application will fall back to using the original source text.

C++ namespaces and the using namespace statement can confuse lupdate. It will interpret MyClass::tr() as meaning just that, not as MyNamespace::MyClass::tr(), even if MyClass is defined in theMyNamespace namespace. Runtime translation of these strings will fail because of that.


Natually, it would be preferable to show "6 occurrences replaced" with an 's', and "1 occurrence replaced" with no 's'. Some developers solve this problem through code that looks like this:
    tr("%1 item%2 replaced").arg(count)
                            .arg(count == 1 ? "" : "s");
This approach works for languages like English that form their plural using 's', but as soon as we try to translate the application to languages like Arabic, Chinese, German, Hebrew, or Japanese (to name just a few), this breaks in a horrible way.
Developers who are slightly more sympathetic might write code that looks more like this:
    QString message;
    if (count == 1) {
        message = tr("%1 item replaced").arg(count);
    } else {
        message = tr("%1 items replaced").arg(count);
    }
This code is definitely more internationalization-friendly, but it still makes two assumptions about the target language:
  • It assumes that the target language has two grammatical numbers (singular and plural).
  • It assumes that the plural form should be used in the "n = 0" case (e.g., "0 items").
These assumptions hold for many of the world's languages, including Dutch, English, Finnish, Greek, Hebrew, Hindi, Mongolian, Swahili, Turkish, and Zulu, but there are many languages out there for which they don't.
Case in point: In French and Brazilian Portuguese (but not international Portuguese, interestingly enough), the singular form is used in conjunction with 0 (e.g., "0 maison", not "0 maisons"), breaking assumption 2. In Polish, there are three grammatical numbers:
  • Singular: n = 1
  • Paucal: n = 2--4, 22--24, 32--34, 42--44, ...
  • Plural: n = 0, 5--21, 25--31, 35--41, ...
For example, the Polish word dom ("house") has the paucal form domy and the plural form domów. The table below shows the rendition of "n house(s)" in English, French, and Polish for different values of n.

Qt 4.2 includes a QObject::tr() overload that will make it very easy to write "plural-aware" internationalized applications. This new overload has the following signature:
    QString tr(const char *text, const char *comment, int n);
Depending on the value of n, the tr() function will return a different translation, with the correct grammatical number for the target language. Also, any occurrence of "%n" is replaced with n's value. For example:
    tr("%n item(s) replaced", "", count);
If a French translation is loaded, this will expand to "0 item remplacé", "1 item remplacé", "2 items remplacés", etc., depending on n's value. And if no translation is loaded, the orignal string is used, with "%n" replaced with count's value (e.g., "6 item(s) replaced").
Qt Linguist and its helper tool lrelease know the specific plural rules for all the languages supported by QLocale. These rules are encoded in the binary .qm file that is generated from the .ts file, so thattr() uses the correct form based on n's value.
These rules are hard-coded in Qt Linguist and lrelease and neither the application developers nor the translators need to understand them.
Considering how easy it is to use the new tr() overload, there should be no excuse(s) anymore for not handling plural forms correctly in Qt applications.
Developers can include information about each translatable string to help translators with the translation process. These are extracted whenlupdate is used to process the source files. The recommended way to add comments is to annotate the tr() calls in your code with comments of the form:
//: ...
or
/*: ... */
Examples:
 //: This name refers to a host name.
 hostNameLabel->setText(tr("Name:"));
 
 /*: This text refers to a C++ code example. */
 QString example = tr("Example");

Additional data can be attached to each translatable message. These are extracted when lupdate is used to process the source files. The recommended way to add meta-data is to annotate the tr() calls in your code with comments of the form:
//=
his can be used to give the message a unique identifier to support tools which need it.
An alternative way to attach meta-data is to use the following syntax:
//~
This can be used to attach meta-data to the message. The field name should consist of a domain prefix (possibly the conventional file extension of the file format the field is inspired by), a hyphen and the actual field name in underscore-delimited notation. For storage in TS files, the field name together with the prefix "extra-" will form an XML element name. The field contents will be XML-escaped, but otherwise appear verbatim as the element's contents. Any number of unique fields can be added to each message.

Example:
 //: This is a comment for the translator.
 //= qtn_foo_bar
 //~ loc-layout_id foo_dialog
 //~ loc-blank False
 //~ magic-stuff This might mean something magic.
 QString text = MyMagicClass::tr("Sim sala bim.");
Meta-data appearing right in front of a magic TRANSLATOR comment applies to the whole TS file.

If the same translatable string is used in different roles within the same translation context, an additional identifying string may be passed in the call to tr(). This optional disambiguation argument is used to distinguish between otherwise identical strings.
Example:

 MyWindow::MyWindow()
 {
     QLabel *senderLabel = new QLabel(tr("Name:"));
     QLabel *recipientLabel = new QLabel(tr("Name:", "recipient"));    ...