Upselling for Software Companies

Upselling is a good way to develop and sell more goods when you have a product that already works. For example, if you have a simple version of a product, you could easily develop another one with more features and sell it for a higher price. Thinking in a more general way, you could develop a product that complements the one you currently have and sell both as a package.

This is what big companies do, by the way. For example, Adobe had a big success with Photoshop. When this happened, they started buying and developing other products to complement their flagship product. Nowadays, they have a suite of products for designers that sells for thousands of dollars, instead of the hundreds of dollars they could charge for Photoshop alone.

Microsoft also did this very well with Office. They started with a simple word processor and spreadsheet, then created a complete suite of office applications with complementing functionality. The Office suite is nowadays so popular that it is capable of driving other product lines made for consumers and small businesses.

While this seems to be a game dominated by big companies, upselling can be a great idea for smaller companies too. You just need to be creative and willing to expand the reach of the products you already have.

Complementary Products

As a first step, look at what could possibly complement your product. Develop something to satisfy that need and offer the combined products as a package. This is a way to test and improve the loyalty of your customer base. Loyal customers will be very pleased with the additional functionality you provide, and the fact that they can get more of their needs from a single, trusted source.

This will also benefit new customers and drive more customer acquisition. If you expand your offerings, new customers will have even more reasons to buy one of your main products, since they will collective provide more functionality, even if at a higher price point. Think, for example, of the case of a small company that buys the whole Microsoft Office package just because they need Excel and Access. They might not really care about presentations, but the fact that the additional functionality is there just serve to reinforce the need for the whole package, instead of the single applications.

Another trick software companies use is to offer only the whole package, with high associated price, instead of the separate products. This works well if you have a product that is so dominant that people wouldn’t consider to buy from other suppliers. Customers end up never buying a single copy of Microsoft Word, because they are usually forced to buy the whole Office package instead.

Conclusion

There are many ways to apply the ideas of upselling to software companies. We already see many of these tactics being applied by the big players. Small companies, however, can also benefit by using these methods to improve their profitability and drive the development of new innovative products.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • HackerNews
  • Reddit
  • StumbleUpon
  • Twitter

A Short Introduction to Prolog

Prolog is a language that tries to apply ideas from logic to the task of programming. Here is a short guide to some of the features of the language. It can be used as a starting point for further exploration.

Installing

There are several implementations of Prolog, so you first need to decide what is the best suited for your situation. If you never used Prolog, probably the easiest way to start is installing SWI-Prolog, a free source implementation that is widely used. There are versions for all major operating systems, including Linux, Windows, and Mac OS X.

In my system, SWI Prolog installs a binary at

/opt/local/bin/swipl

Once you run the executable using a terminal window, you will get a prompt. Then you can type something like:

A is 1 + 1.
A = 2.

Here, “is” is a keyword that unifies the result of 1 + 1 with the free variable A. When you type enter, the line is executed and the result A = 2 is printed.

Notice that in the example above I talked about unification, instead of assignment. A particularity of Prolog is that unification, the process of finding a “matching” parameter for an argument, is the main mechanism for attributing values.

For a single variable, unification is the temporary binding of a value, based on the context where the variable occurs. A single variable can unify to one or more values during the execution of a program. Unlike assignment, a unification cannot be undone in the same clause unless bracktrack occurs.

Clauses

Prolog is a logic language. Expressions have a logical meaning, and the result of any expression is a boolean value. The basic difference of a language like Prolog to procedural languages is that we need to get used to translate procedural code into the required logical style. Logical expressions used by prolog are by necessity more declarative than an equivalent program written in C, for example.

The basic unit of a Prolog program is a clause. A clause is a single statement with an antecedent and a possibly empty set of consequents. Logic theory calls a statement like this a Horn clause. Thus, one can say

descendent(A, C) :- descendent(A, B), descendent(B, C).

This clause is just stating that a way of somebody being a descendent of another is to be a descendent of a descendent. This can also be explained as saying that “descendent” is a transitive relation. The rule above is true for any transitive relation.

Notice that variables always start with an upper-case letter. Constants, on the other hand, start with a lower-case letter. So, if we add the following information:

descendent(john, mary).
descendent(mary, james).

Prolog will be able to deduct, according to the rule above, that “james” is a descendent of “john”. Relations such as the last two presented above are called facts, because they are just stating our current knowedge — we already know that Mary is a descendant of John and that James descends from Mary.

Prolog implementations generaly separate statements available for a program into two kinds of files. Database files store a set of facts. It is not hard to see that such database files have a lot in common with traditional databases: they represent a set of relations, and each fact can be viewed as a database record. You can already see that Prolog provides a really nice representation for data using the basic mechanisms of the language.

Then, another set of files can be used to create queries and general rules that will apply to the data. This is where the “programmatic” part of your code will be stored. Some implementations let you mix facts and rules as necessary.

Recursion and Conditional Behavior

Recursive clauses are the main technique that Prolog uses to support repetitive behavior. However, to control recursion one needs some kind of conditional selection. Prolog implements conditionals through unification and backtrack.

Unification, as hinted above, is the process of matching an argument to a set of logical variables. The form of the variables can be used by Prolog to determine the best matching. For example, this is the standard way of working with lists:

size([], 0).
size([A|B], X) :- size(B, Y), X is Y + 1.

The above definitions use matching to answer a question about the size of a list. A list in Prolog is represented by elements enclosed in square brackets. The notation [A|B] means that A is the first element (the head) of the list, and B is the list of remaining elements (the tail). The notation [] represents the empty list. Thus, the rules above present two cases: an empty list and a list that has a head and a tail. If Prolog can match the list with one of the cases, then the corresponding rule is executed.

To use this example, type the two clauses above in a file, say listsize.pl. Then, in the Prolog prompt, use the command

consult(listsize).

You can now ask questions based on these rules:

size([1,2,3], S).
S = 3.

Notice that the first clause works just by unification: When an empty list is found as the first argument, the variable passed as the second argument is matched to 0, therefore a solution is immediately available.

When the second clause is used, however, Prolog applies a recursive call to determine the size of the tail, then adds 1 to that value in order to determine the size of the list. When this happens, all variables have an assigned value and a solution is returned.

Prolog can use the process above to compute not only one, but several solutions for a query, if more than one exists. For example, if we know the facts

employee(john, company1).
employee(mary, company1).

Then we can enter the following question

employee(X, company1).

In that case, there are multiple answers. Prolog, by default, will return one answer at a time. Each time a user can type the “;” character and receive a new solution. Another option could be to collect all solutions in a list, for example, before displaying them.

Conclusion

This is just a short tutorial on the features of Prolog. The language provides a lot more, but you can use the information above as a starting point. Above all, Prolog is a nice tool to play with algorithms that would be too complicated to use in more traditional languages. It is a great way to have fun and learn a different paradigm for computation.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • HackerNews
  • Reddit
  • StumbleUpon
  • Twitter

RAII is Overrated

In most discussions of the advantages of C++, an item that is frequently raised is the support for automatic destruction. This mechanism, which is used to reclaim resources used by a single object at the end of its scope, is the basis for a programming style popularly known among C++ users as RAII (resource acquisition is initialization).

The main point of this article is to show that, while RAII is a useful idiom in a complex language such as C++, it really doesn’t provide much help in other, simpler languages. Even in C, which is a lower level language, the automatic destruction mechanism doesn’t provide much that couldn’t be supported by the programmer itself, sometimes with less surprises and higher performance.

Is Automatic Destruction Necessary?

The first issue that needs to be answered is if automatic destruction is a necessary feature in general. One of the ways we can answer this questions is looking at the decisions made by the designers of more recent languages. This may not give us a complete answer, but it shows at least an indication of usefulness for a particular feature.

In fact, there are many languages such as Java, Python, Javascript, and Rubi that don’t have an idiom for RAII. Moreover, among the communities of users for these languages there is no feeling that there is a particular need to add such a feature. This includes both older languages such as Smalltalk as well as languages more recent than C++, such as Javascript.

The main reason most languages don’t require a RAII idiom is that they don’t need to manage memory manually. Memory is the single most common resource guarded by C++ classes, a resource that needs to be released every time an object is discarded.

Another reason for having automatic destruction in C++ is that is provides a decentralized way to manage resources for any number of classes. Compared to C, a C++ program needs to define a lot more user defined data types (classes) in order to do its work. The interaction between features such as the STL and the inheritance mechanism require that a lot of classes be created to represent programmatic concepts — no wonder why C++ programs feel the need to have a mechanism for cleaning up the resulting mess.

Disadvantages of Destructors

One of the problems with automatic destructors in C++ is that they require a lot of run-time overhead. Every object in every class needs to call a destructor, even if it does nothing (which is often the case). It is true that an optimized compiler can eliminate the call to the destructor in some cases. However, when we have virtual destructors this becomes very difficult, since the compiler has no way to know exactly what destructor will be called through the virtual table.

When a system has a large number of objects with virtual destructors, which is a common case on object oriented systems, the result is that destructors are called all the time for no good reason.

A more subtle problem with the RAII idiom is that, while it solves some of the issues of resource management, it doesn’t address the most difficult cases. The only instance where RAII works well is when objects are allocated in the stack. For these allocations, destructors are guaranteed to be called at the end of the scope, even if an exception happens before the end of the scope is reached.

However, C++ has two more memory allocation models: static-allocated and heap-allocated memory. Static memory can be a problem for the implementation of the singleton pattern. It is well known that objects created on static memory will not be destructed correctly. Even when they may be destructed, there are no guarantees. Therefore, static allocation of objects should be dealt with special care, and destructors cannot be of much help in this case.

The other, much more important case of memory allocation is heap-based allocation. It is important because in an object oriented language the objects use have distinct life times. Therefore, one should be able to allocate them and pass references around until they are not needed anymore. The standard way of doing this is allocating memory on the heap and returning that memory to the pool only when the object is done.

Now, the problem with heap allocated memory is that destructors will be of no help in that case. They will not be called automatically when an object is not needed. If a programmer doesn’t take care of cleaning heap-allocated memory, it will just leak when no more references to it exist in memory.

To avoid this, programmers are required to call delete (or delete[]) to make sure that the object is properly cleaned. Thus, programmers are ultimately the ones responsible for this difficult task. If you think of the implementation in terms of C (and other lower level code), in this case the destructor is just a function that needs to be called in the object. There is nothing special in it other then the syntax, which uses the keyword delete.

In fact, the destructor itself is a non-impressive function, with some serious drawbacks. First, it receives no arguments and returns no value. So, for example, there is no way to signal an error condition other than throwing an exception. And we already know that a destructor shouldn’t throw exceptions, which means that it cannot do anything very reliably.

What this amounts to is a system that is far less powerful than necessary to maintain a first class object oriented system.

Conclusion

RAII is preached by some as the most important feature of C++ for resource handling. However, as we have seen above, it has lots of problems that make it much less appealing than initially thought.

For example, destructors work well only when the memory class used by the object is stack based. Other allocation classes will result in memory leaks and in manual work for programmers.

Even the work performed on behalf of stack allocated objects is nothing more than syntactic sugar. While tedious, it is not hard to add a matching clean up procedure at the end of the scope where an object is used, when necessary. If no exceptions are used in code (which is a common case even on C++), this is all one needs to have correct programs.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • HackerNews
  • Reddit
  • StumbleUpon
  • Twitter

Readability Advantages of C over C++

C++ is a language that was created to improve some of the features and use cases of the C language, in order to make it easier to use for application development (instead of system programming, the main area dominated by C). One of the perceived problems in C is the lack of support for object oriented features that are so common on the development of desktop applications. For example, C lacks the concept of a type that encapsulates code and data. While it is possible to program in an object oriented style in C, it is somewhat cumbersome to use such a style.

In order to make C easier to use, C++ designers added a number of features that would be more appealing to programmers. Inheritance was one of them, used to support object oriented features. Overridden methods were also added to improve object oriented programs.

C++ also added some features that can be considered syntactic sugar for already supported operations. For example, operators can be overloaded, so that many math operations, and even punctuation such as “,” can be overloaded by programmers. Normal functions can also be overloaded, by providing versions that differ on the number and type of arguments.

Later on, C++ added templates to fix a problem with the language’s type system. With templates, it is possible to instantiate a class based on one or more types. This allows for the creation of containers, such as the ones found in the STL. Vectors, maps, and multimaps can all be created by adding a type as a parameter for template instantiation.

Consequences

Although C++ designers succeeded in creating a language with support for most object oriented features, there are a lot of unintended consequences of the way many of these features were introduced.

Unlike C, in C++ it is difficult to understand, by just looking at the code being written, what will be really executed at run time. This has always been a problem with object oriented languages due to polymorphism. However, the problems have been compounded by the liberal use of overloading features in C++ programs.

Clearly, in C it is possible to write convoluted programs (especially if one wants to use the preprocessor). However, in general one just has variable declarations, function declarations, function calls, and simple expressions (such as mathematical and logical expressions). Maybe the results of a function call may not be completely understood by the programmer, but from the syntactical point of view it is easy to figure out what is going on in the program.

And, to put it clearly, the problem is not that the function or class is doing something we don’t know. The problem is mostly in trying to figure out what is happening in a given line of code. In C is very easy to figure out what is being called (up to macros): just read the manual for the functions being used and you will have a good idea of what is being executed.

In C++, on the other hand, a large number of things can be happening in a single line: an overloaded operator, a type conversion, a template instantiation, an overridden function in one of a dozen of classes, a constructor called in some part of the hierarchy, in some namespace… Who knows? You have to be smart enough to figure out what is going on in each of these cases. As your code base grows, this makes it increasingly hard to understand what is going on.

And this is not even considering issues such as exceptions, which are a huge liability, since you have to check that they will leave your program in a reasonable state at each part of your code.

Conclusion

While C++ provides a lot of helpful features for application programming, these features have a cost. It becomes increasingly difficult to understand what is going on in each line of code, unless the developers are very disciplined.

This also shows a little of the myth surrounding the idea that C++ is better than C for large code bases. While C++ has some features that might be helpful, in general the bigger the C++ code base the harder it is to understand due to these issues.

This is true even for automated tools. It is very difficult to create automatic tools to parse and change C++ (for example, to perform refactoring). In comparison, C is much easier to understand, and one can do a lot with tools such as ctags. It is not a surprise that large scale projects such as the Linux kernel use C without any problem.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • HackerNews
  • Reddit
  • StumbleUpon
  • Twitter

Is C++ Just a Better C?

A lot of money and energy was spent in converting or writing new software in C++ during the 80s and 90s. Even nowadays, when the leading commercial language is Java, there is a lot of effort spent in learning and using C++ in several areas where performance is considered to be an important asset.

However, despite all these efforts after 20 years, C++ is not used to its full extent. Some features such as the STL have become really successful and widely accepted by the industry. On the other hand, other features such as checked exceptions and RTTI have been met with little enthusiasm.

It is necessary to understand what these features have in common and why they were not considered to be so useful as their creators supposed them to be. Especially when such features have been introduced more than a decade ago and are still nowhere near full acceptance.

Duplicate Features

One of the problems of the C++ language is that it has, more than once, introduced features that are difficult to use and/or implement. As a general rule, this is a disadvantage of languages designed by a committee. Some features end up becoming part of the standard document, but they have little support in the real world.

For example, a decade ago the designers of C++ though about the possibility of having templates defined in separate translation units from the ones where the templates are used. The intention is good, since templates take a long time to parse and compile.

However, the big problem with separate compilation of templates, provided by the external template keyword, is that it was never implemented by major compilers. The main justification is that it is a complicated feature to implement. Also, it would require modifications to the current way programmers declare and templates.

The result is that external templates are now viewed as a dead feature, something that might be useful but is not available in any of the major compilers.

Coding Standards

A related problem for C++ is that nobody uses all its features. Due to the fact that there are competing implementation for the same concept (for example, two IO libraries — the old C-base library and a stream object-based library), C++ users have to decide which option to use. This may be done in a case-by-case basis, or even by the use of a coding style.

Big companies such as Google have decide to rule out most of the advanced features found in newer versions of C++. These features include exceptions, multiple inheritance, for example. What this means in practice is that C++ is being used just as a better C, without many of the features that its creators though would be useful.

On close inspection, it seams that C++ is mostly a language designed at two levels: the first level, incorporating the ideas of the day, which change every few years with the desires of researchers. Examples include checked exceptions and run time type information. In the process, lots of incompatible ways of writing the same code are introduced. For example, are you going to use return values or exceptions? Streams or standard buffered I/O? Both have its advantages and disadvantages, so you better know what they are.

In the other hand, there is also a second level dictated by developers, as they decide which subset of the language to use. Since it is not possible to use all the provided features at the same time, one has to selectively use C++ to create new software projects. One of the ways this is done is by adopting a styling convention. In this process, developers rule out a set of features that believe are not productive.

Still, another result of this evolutionary process is that there are some features that people don’t like, but that are not easy to substitute. For example, templates are a pain to create and even to use. However most developers use them because it is the only way to do some things in C++. Somebody else could create better container classes, but that would become a huge problem for compatibility with existing libraries.

Conclusion

C++ is an evolving language. As a consequence many of its features are not well developed. Other features have been rejected by the community as too complex or unsafe to use.

A large part of being a good C++ developer is understanding what are the good and bad parts of the language, and how to take advantage of them when necessary.

Further Reading

The Design and Evolution of C++, by Bjarne Stroustrup is a great book that explain the reasoning for most of the features in C++. It is a must read if you want to understand the initial phase of evolution of the language.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • HackerNews
  • Reddit
  • StumbleUpon
  • Twitter