Sunday, June 15, 2008

How to choose the best programming language

Inspired by a new blog-article "Best programming language" there are some more open points to discuss on how to choose the best programming language for life, universe and everything. Let me give 5 of them.

First things first: Is choosing the right language even remote possible? And if so, how can it be done? Well, to set things clear let's have a real-world-example: Which (spoken) language shall I learn to succeed at most? If it's only a matter of understanding and talking to the most people this would be chinese. Do you achieve your goals with that? Most probably not.

Why wise selection is necessary

You can speak with one billion people in case you choose to learn chinese, but you could not read this blog (in case you prefered learning chinese before learning english). And how many people in your neighbourhood do speak chinese? Is it worth learning (under respect of this argument)?

Choosing a programming language too depends on many factors which you have to name and select with care. You want to show the best performance in programming (be it in programming-speed, stability, scalability ...), here is how:

5. Complexity of setup is not counting for evaluation

So, setting up an environment to evaluate the new programming language will last one to two hours (or even more)? Be honest: Setting up a testing environment for two hours is more easy than living with a not at all appropriate programming language for the next 6 month on a eight-hour-per-day-working-base in your new project. And of course you have to think about administration workload later on (which too reflects in evaluation, of course), but there are tools, workflows etc. which, done right, may help you to get rid of this point. Test the availability of tools, too.

4. The most hyped language may not be the best to choose

What is a hype (spoken in language selection)? Well, there is a new language out in the market. All people talk how easy and neat it is to work with it. Pretty cool so far. The drawback is that these languages are not widely "broadcasted" out there, mostly information is sparse on both the language and the usage/projects done with it. Of course you may use it, but be sure not to see things through rose-colored glasses.

3. Programming for fun is one, doing a project the other thing

Think of team-working, releasing, "changing one little bit might affect many others (and how can I prevent/check this)". This will help a great lot in case the project gets bigger and you will have to hire new people.

2. Prototyping and "getting things done (as fast as possible)" is not your daily work

Of course, most bosses and clients want to see what you do as fast as possible. They are more eager to compare your work with their business plan than to hear "no, we are setting up servers/software/configurations - please stand by". But on the long trail, as a programmer, you only can win if your work is profound and, in best case, solves problem other peoples like your bosses and clients do not even think of now. Test your desired language(s) if they fulfill your own personal claims on that regard, then test the language if it serves well in a programmers team and client-centric manner.

1. A fool with a tool is still a fool

Do not blame the programming language if you run in first problems (at first sight). Search for other ways if your goal cannot be reached with your first shot. Use Google to find new ways and thoughts (a good test to show if enough people using it / documentation on how to use it is out there, too). And even if you used the language for some years and think that the new project does not fit to it, give it a try on Google/the community. There are other people who might help you to solve a brain-nut-problem, sometimes on-the fly.

Not sure what langauge to choose now?

Watch out! There are a couple of languages on the market. And there is no easy answer to this question, if someone provides you with an easy answer, be most careful! Evaluate some languages, program some more in the languages that reach the "inner circle" for you and never forget the old but true saying: Use the right tool at the right time.


Other "Thoughts on" and "how to" articles:
Related posts:

Labels: , , , , , , , ,

 

Sunday, August 12, 2007

10 thoughts on successful server programming

What defines succesful server software and how can it be programmed?

How to program server software successfully

Everyone uses server software nowadays, at least in the internet, but most time people are not aware of it. Therefore "successful" server software is boring. Not the technology or the creation process itself, but server software is succesful when it behaves boring. Or, in other words, it simply works. Most times you do not know it's there and if it behaves as it should one tends not to see it.

So at first, a definition of "server software" would be helpful. Server software(s) are programs that do not run on your computer directly. Results of input are computed on another peace of hardware but then the results are shown in your own program (or internet browser, this very page you are reading is nothing else than a computed result from the servers of blogspot.com).

But how are programs prepared to work in the daily server world? Just a few (apparently obvious) thoughts to achieve this goal.

10 thoughts on successful server programming
  1. Be aware that a server program or script is not comparable with software running on your computer at home. Server software has to run self-sufficient to a high degree.
  2. Think of an appropriate logging to relieve later-on forensic fault diagnostics. Better to log too much than nothing, users who access your server will do this in ways you never thought of while programming it. And there is a good chance that you need to narrow down what exactly happened.
  3. Use all features your programming language provides to write solid software. If exception handling is available, use it. Finally-blocks to clean up your code? Definitely. And there is much more you can utilize, from assertions to the usage of complete testing systems etc.
  4. In any case avoid memory leaks. If you program C / C++ be very careful, but even if you use Java / .NET or scripting languages this may get an issue for long running server software (just assume that a collection of data in Java / .NET will only get longer and longer and never shorter).
  5. When you use external resources (i.e. databases, networks or file systems) be aware that they may fail. The least should be an explanative error message for your users. The best would be an email notification to the administrator and a retry / recover of the failing system automatically (to a second database, for example). The parts in programming I need to rely on external resources are the parts I spend the most time developing them, create fallbacks for or even use logging at most.
  6. Try to get the configuration as precise as possible. The configuration(s) of your systems are the base your software is running on, keep it as simple as possible and as complex as necessary. To ease your way changing your configuration later on simply follow an old saying from Antoine de Saint Exupery: "Perfection is reached not when there is nothing left to add, but when there is nothing left to take away."
  7. If possible try to set up a test system. If you do not have a spare server for that, do it on your own (development) computer. The moment you notice erratical behaviour is the moment where you do not want to mess around setting up a system to replay and find the error.
  8. Make Backups. Nobody wants backup but everyone cries for recovery. Do not forget that you write server software and, in case something bad happened, you have to be up and running as fast as possible. Backups may help to recover fast, then you got time to search for the problem.
  9. If you follow all these steps do not forget that "releasing" has other implications for server software. The good news is that you may not need to release client-software on hundreds or thounsands of computers. The bad news is that you might have to take your server down to release new program(part)s and believe it or not: Users don't like that ;-) . So releasing should be as fast and stable as possible. Best would be that it is rollback-able to an older (working) release.
  10. Alas, there is one very unpopular thought left: Document it. Start documenting the structure (i.e. involved server machines, a top-down documentation of the different modules/parts of your software etc.) and the programming code inline itself. There are many guides and tools out there that help you get your documentation right, search and follow the ones that help you most here.
Though this all sounds pretty obvious it is astounding that you nearly never see systems that follow all this tips. Even if you want to you may not be able to follow all of them because of restrictions from the outer world (timelines, new "prio zero" features needed yesterday etc.). But often it helps just to keep them in mind in your daily work and introduce them eventually. And now, happy server-software-coding!

Labels: , , , , ,

 

Monday, May 28, 2007

Thoughts on successful exception handling

In the last article, a (very) brief introduction to the benefits of exceptions, we saw that exception handling may produce more efficient and stable code. The example was kept simple enough to provide an operation breakdown on how exceptions basically work. This article will explain how exceptions may be used for greater benefits, how programs and program parts get more stable using exception handling and how exceptions and parts of the programming efficiently interact with error handling and each other.

Why exceptions?

As stated before, many coding efforts directly flow into error handling in general. In case a simple "or die" expression is not enough when an error occurs ("or die" just stops processing of the program-code at once), exception handling provides useful mechanisms to write code that may handle the erroneous behaviour or helps finding the cause of it.

Following the IPO principle, errors in programs or program parts do occur because of a flaw in programming or incorrect input to the program / program part. Assuming we only take a single method call retrieving parameters, the following conditions which result in wrong output can be classified:
  • The parameters given to the method are not well defined (i.e. are wrong or empty / null where they must not be)
  • The "constellation" of the parameter values are not expected in the given way by the method (because if parameter "a" has a certain value, "b" must not be of another certain value)
  • The caller of the method simply calls it in an improper way (i.e. the environmental conditions are not correct, needed resources are not allocated yet etc.)
  • The method allocates external resources (i.e. open connections, file handles etc.) and does not free them (thus leading to an invalid internal state of the program, the operating system or other components like databases)
  • The method relies on external resources (i.e. file system, database etc.) which are not available at the moment they are needed
  • The method and therefor it's programming trusts on an internal state that is not correct (i.e. corrupt data/instances needed to compute the result)
  • The method contains a programming error
Looking at the points above reveals that only the last two arguments deal with programming faults in our method, the other five describe errors that depend on the usage or environmental states the method runs in. So while exception handling can help to identify purely written code while development, it often is used to keep the code up and running correctly in productive systems.

How exception handling is done (right).

Using exception handling is as simple as that: If you write a method and you are able to handle the behaviour without breaking the flow of your code or stressing external logic through "workarounds", you do not need exceptions at that place. The time you wonder about how you may "get this check of a variable/state into an if-then-else" - construct or you rely on methods or (external) resources which may throw exceptions of their own it's another part of the story.

Before your code gets overly complicated throw an exception. You then surely can determine the place where the exception will be thrown and, because of try-catch - blocks, you always have a defined place where your exception and the execution of your code will lead to.

And you cannot handle every error, better: exceptional behaviour, at the place it (immediately) occurs. If you write a method that, say, reads some file content and returns it as a string, and you do not exactly know from which routines this method will be called in the future, then you should let pass or (re)throw the input/output exception as it occurs in your method. What good is it to return an empty/null string if an error happens? Firstly, you will have to check for a null pointer reference anyway, otherwise the surrounding code will not work properly either. Most times checking for a null reference is as verbose as catching an exception. On the other hand, if you don't throw an exception, does returning an empty (not null-) string mean that an error occured or that the file was "empty"?

Take your time and rethink if the method where the error happens really has all informations to react accordingly or handle that error. Else (or if you are not sure how to handle this kind of exceptional behaviour at that place) throw an exception.

And never forget: If you decide to throw an exception, be as precise about the error as you can be. If your language accepts an error message to pass with the exception, make it as accurate as possible. If the language allows to specify different exceptions or even subclass exceptions, be as precise in selecting the type of the exception as possible.

Somewhere ... by and beyond exeptions?

Do not listen to people who argue that exceptions are (time-)expensive. Firstly they are right, no argument needed. But the benefit of clear, more stable and readable code leaves enough time for you to optimize your algorithms on other places more needed. Remember that exceptions represent "exceptional behaviour", they represent erronous states which only happen in special erronous cases. Ordinary spoken: If you do not throw exceptions to just simply leave a loop or code block you will be fine on the performance side of life.

And there are a couple of open points and additional benefits introducing concepts like exceptions. Some of them, more or less tightly married with exceptions, are thingies like stacktraces where you can follow the whole way of the exception through the complete code (in most languages introducing exceptions), finally-blocks and (in a certain way) assertions and closures. But handling these issues would blast this article.

Alas, one controversially discussed exception technique, the so called checked exceptions of the programming language Java, should at least be mentioned here to round off.

Checked exceptions are exceptions you have to catch or, via definition, throw up to the next ("calling") instance. A method, for instance, that does not want to catch the exception on it's own has to declare that the exception which then has to be catched from the caller of the method by default - if not, the compiler will not compile the code. This is a very controversial issue within the (Java-) community because the need to catch checked exceptions naturally leads to more programming overhead. But again, the compiler tells you that the programmer of the method wanted you to explicitely respect that this kind of exception(s) may occur - and you have to deal with it. Integration might be tough, but at least you know about the possible exceptions without consulting the documentation simply by compiling your code. I, personally, had my difficulties accepting this feature, but at least the advantages had beaten the "programming verbosity" pants off for me and I think you will love this feature as it follows your way in larger projects.

So, go on throwing exceptions, and may the catch be with you!

Labels: , ,

 

Saturday, January 27, 2007

How to successful log in programming

In a previous article, "Thoughts on successful logging", I wrote about why and how logging is done and, rudimentarily, about best practices in logging. This article now shows how successful logging can be done: Where and what should be logged and how the impact of logging on the overall performance (meaning: usage of resources and time to interpret log-messages) can be optimized.


Where and what to log or: What happens if logging goes wrong.

The simple answers to these two questions "Where?" and "What?" would be: Log everywhere, log all, then you have all the informations about your program in your log at any time. But most times, alas, there are no simple answers in life (or especially: in programming) and following these two answers will result in a couple of problems:
  1. The log will explode with log messages, finding crucial messages will become difficult.
  2. The log will get verbose because one incident raising a log condition might be logged more often than once (see below for an explanation).
  3. The verbosity might be misleading. This can be the case when one incident is logged in different places in the code and therefore seems to deliver different meanings (at first sight).
  4. Logging methods will be called more often than actually necessary and (thereby) increase the size of memory usage / log files etc. .
  5. Gathering the informations more often than needed for the log message (i.e. retrieving additional informations, concating the message from them ...) and calling the log method will decrease the overall performance of the program or of parts of it.
Taking these problems serious and pondering a little about them will reveal that successful logging also demands a certain programming style, namely the kind that allows programmers to put the logging lines onto the right place. So let's first talk about the "where" to log, finding this answer will additionally help to clear how to log, seen from a programmers point of view.



A first example: Where to log or not to log. That is not the question.

Logging is like error (exception) handling: If you do it in the wrong place, you get too much or, alternatively, too less information. So the question you have to ask yourself is: Am I in a state of "misbehaviour" (or success) at this point that justifies a log message and - even more important - do I have all informations in this place to produce a log message I can read and am sure what exactly happened? Remember: The moment you do not work on the program every day you should be able to interpret the log message in a couple of seconds, too.

Let us assume we have methods openFile() and createFile() which return a file handle if the file could be opened / created or null if this is not possible. Then, owning a file handle we have the following methods on it: fileHandle.readContent(), fileHandle.writeContent() and fileHandle.deleteFile(). We then want to write the methods emptyFile() and moveFile(). The pseudo.code for this might look like:

function fileHandle prepareFile(String fileName) {
fileHandle = openFile(fileName);
if(fileHandle == null) {
logError("Cannot open a file.");
fileHandle = createFile(fileName);
if(fileHandle == null) {
logError("Cannot open a file.");
}
return null;
}
// Eventually do some additional action here which justifies this method
return fileHandle;
}

function boolean emptyFile(String emptyFileName) {
fileHandle = prepareFile(emptyFileName);
if(fileHandle!=null) {
fileHandle.writeContent("");
fileHandle.close();
return true;
}
return false;
}

function boolean moveFile(String source, String destination) {
sourceFileHandle = prepareFile(source);
destinationFileHandle = prepareFile(destination);
if(sourceFileHandle==null || destinationFileHandle==null) {
return false;
}
else {
destinationFileHandle.writeContent(sourceFileHandle.readContent());
sourceFileHandle.deleteFile();
sourceFileHandle.close();
destinationFileHandle.close();
return true;
}
}
Obviously, this code will also produce misbehaviour (just look at the moveFile() - method and imagine what will happen if the source file cannot be opened). But moreover the log messages will not help you finding an error. At first, you only get the message "Cannot open file." - which file? But only changing the log line to logError("Cannot open file " + fileName + "."); will not do the trick either, though it is a lot better.

That obviously is because you can call one of the methods (emptyFile() or moveFile() ) and always only get the same log message. You do not exactly know where the error happened. The method prepareFile() is not the right place to log the message because it has not all informations needed ("am I emptying or moving a file?") to create a significant conclusion of the error that happened. The scope of the method prepareFile() is not suffice to log enough information to be precise.

Let us rewrite the methods for the sake of better logging:

function fileHandle prepareFile(String fileName) {
fileHandle = openFile(fileName);
if(fileHandle == null) {
fileHandle = createFile(fileName);
// Do not log here - this would be verbose!
return null;
}
// Eventually do some additional action here which justifies this method
return fileHandle;
}

function boolean emptyFile(String emptyFileName) {
fileHandle = prepareFile(emptyFileName);
if(fileHandle==null) {
logError("emptyFile: File " + emptyFile + "could not be prepared.");
return false;
}
else {
fileHandle.writeContent("");
fileHandle.close();
return true;
}
}

function boolean moveFile(String source, String destination) {
sourceFileHandle = prepareFile(source);
if(sourceFileHandle==null) {
logError("moveFile: Cannot prepare source file " + source + ".");
return false;
}
destinationFileHandle = prepareFile(destination);
if(destinationFileHandle==null) {
logError("moveFile: Cannot prepare destination file " + destination + ".");
sourceFileHandler.close();
return false;
}
destinationFileHandle.writeContent(sourceFileHandle.readContent());
sourceFileHandle.deleteFile();
sourceFileHandle.close();
destinationFileHandle.close();
return true;
}
As you can see, two things happened: Firstly, the logging will create better error messages, that kind you really know what happened. And secondly, more astonishing, the error handling improved. This, clearly, is based on the fact that logging and error-handling often go hand-in-hand (and you surely could do better code using exception handling and finally blocks). Or, asked in an other way: Why does anybody in 90 percent of all cases want to log? Yes: In case errors happened.

The improvement, of course, has it's price too: We needed an additional five lines to accomplish it. But this should only show one thing: Next time you think of the whereabouts of logging, simply think of the whereabouts of error-handling.


What to log.

The answer of the "where to log" already gave some answers to the "what to log" question. Errors, better said exceptional behaviour of the code (or the state of the program) surely is worth to be logged. As listet in the previous article, the purpose of logging changes as the programming work changes too. From simple checks if the program code works as desired to maintainance of the program, i.e. performance logging and logging of the proper (or improper) working of complete modules. This kind of logging should be added from the beginning on too, to a certain degree. It helps you to better understand your code at develop time and maintain the program later on in one big shot. Only make sure that verbosity will not be an issue at any time.

This can be achieved in quite a few ways and always depends on the functional blocks you want to monitor with logging. Let us assume you want to watch the processing time of a page created by your web application. A good idea would be to define a maximum time you allow the page to be rendered. Log only if this time-limit is exceeded, this way your log will only get flooded in case the program works too slow. In other cases, when performance is not an issue, try to get the basic conditions on how logging is useful (like "used time" while logging the performance) and follow them, this will keep your log slim and dandy.


Logging: A conclusion.

Let us conclude with a list of "best practices" for logging. These points merely are explained in the article and summarized in the following six points:
  1. Try to formulate your logging messages that way that you can quickly recall the cause for the logging only by reading the message.
  2. Treat logging like error (or success) handling: Find the right place for your logging message that has all informations you want to know. Improving the error/exceptional code handling will naturally create the places you can log easy and good. Don't log at every opportunity.
  3. Often, less is more. Try to concentrate on vital log messages and avoid verbosity.
  4. Sometimes, more is more. Think of the life-cycle of your program not only the time you code it, your program will go productive and certain logging messages (i.e. performance logging for memory or speed or database usage etc.) can too be very useful later on.
  5. Use a logging (logging-API or Framework, self-written logging) that has different on-and-offswitchable log levels ("debug", "info", "error", "fatal") and is able to log into a kind of persistence layer, be it files, databases or something similar. The moment your program goes productive you will love this option for latter error analysis.
  6. Use a logging (API, Framework, self-written) that interferes as little as possible with the rest of your code. It must not use too much resources or be overcomplex to use. Anyway, it should be able to be configured at run-time, i.e. switching debug-levels on or off, switching file logging on or off etc. .
So, happy logging! And might the information be with you... .

Labels: , ,

 

Saturday, December 09, 2006

Thoughts on successful logging

Dealing with logging the last days, again, I thought it would be time to b-log about it too. So let us dive into the questions why programmers log, how programmers log and what the best and worst practices are on how to log.


Why logging?

Nearly every program and nearly every programmer does logging. And because of that, the purpose of logging changes through the lifecycle of a program.

At first, in "programming mode", logging normaly serves as status output and is used to validate the functioning of the newly written code. The simplest example for this would be a log-line in a block of code that is placed there to prove that the block is called anyway.
Introspection is another important thing at this point: If a programmer is not sure about the variables and values of a program at a certain point, he may simply output the values, the "state" of his program, using a log.
Logging also is useful to show off errors that do not directly occur in the programming code, such as a subsystem (like a database connection) went down etc. To know about these things is vital while programming: You never can be sure that your program works fine and dandy if the environment it works in isn't.

But as the program and the programming code evolves and grows more and more to a productive system, the intention of logging changes. The goal is not to monitor the code precisely any more but rather the modules of a program and their proper functionality. The main task of logging changes to: Survey the duration of operations, their failing or their success. This kind of log-mutation often comes smoothly and not abrupt or as a sheer matter of choice because the newly needed informations are usually already needed while programming, too.


How logging is done.

Logging exists as long as programming itself does. It starts by an ordinary output to the console via "println" and does not even end with high-level logging engines that are retrievable via network connections or external logging-client programs.

It always starts the same way. At first, just a couple of informations are merely printed to the console, after that, a little package is written that fulfills this task. Then, with rising complexity, the informations need to be categorized, otherwise crucial facts are lost in too many log-lines. By the way, logging means to trace the activity of a program over time, so the output has to be preserved in files or databases or repositories of any kind. And what about distributed systems on more than one computer, shouldn't they log to one place so that surveillance of only this log-source is possible? What started fairly simple can get pretty complex over time.

To not reinvent the wheel at this stage, there are a lot of logging APIs out there in the world. But they all boil down to some base functionality:
  • The methods to log are - more or less - simple to call
  • Different log-levels are introduced such as "debug", "trace", "info", "warn", "error", "fatal" so that the importance of a log-line can be classified
  • Most loggings have different channels that can be switched on or of for observations
  • Often, the log output can be canalized into a file or similiar data sinks
Anyway, fulfilling these preconditions do not define a good logging mechanism or API.


Best (and worst) practices doing the logdance.

Inserting a line of code that logs something always arises the same question: Is this correct, at this place, this time? Will this spam the log later on or is it accurately set here?

In first sight it is a good thing to log. If you create a system that will work for some time or reaches a certain degree of complexity it always is good to (at least vaguely) know what the system is doing right now. Or which conditions might have led to a failure of the code. Computer programs are systems that react on user or data and interact with their environment on many different variables and states. To write a program without logging is like having a black box you put input in and expect the correct output to be delivered. But then if something doesn't work proper you only have that black box to look at, without any further information why your program did not work.

But, as mentioned before, logging all and everything will not work out, either. Here are some suggestions on logging successful:
  • Try to log a state or error just once. Log (only) at the end of an action or an error-handling block. This will reduce verbosity and makes the log much more readable.
  • Think about to introduce prefixes to the log messages which will give a hint where the log message is placed in the code. Example: You have a module that parses URLs, so every message might start with "ParseURL:...". This way you directly know where the logging message comes from.
  • Do not only think of the place in the program code where you want to log a message, but consider the environment (variables, states, etc.) to be logged, too. This way it is more easy to recollect not only the place but the circumstances from a log message itself.
  • Keep in mind that the intention of logging will change as the program matures (described above). Sometimes spending 10 seconds more for a log message (i.e. to additionally show variables and states in the message) will greatly pay off later on.
So much for the "where to log" and "when to log", let's determine "how to log". As mentioned before, you can use own code or prebuild logging packages. Anyway logging should be made easy for the programmer (otherwise no one will use it) and treat computer ressources with respect (otherwise it will draw the performance of the program down).

Using prebuild packages is not a bad idea. Many functions that will be needed are available and can be used later on, even if at the start you are not aware that they will be useful. But be careful selecting the logger you want to use: It's use will spread through the whole program and changing it afterwards is nearly impossible. In general the development history of logging packages displays the idea what logging really should achive a little bit: From very simple modules to "all-in-one device suitable for every purpose" loggers, they nowadays return to a k.i.s.s-approach. Doing the log dance? Sure! But keep it simple, fast and easy-to-use, otherwise it will be counterproductive and no one will use it.

This article is continued at "How to successful log in programming"

Labels: ,