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.

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.

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.