Copy a Linux system over the network, with no intermediate files

I had an old Red Had Linux system I wanted to convert to a Virtual Machine. The typical method recommended by most people is to back up the system, then restore it inside the VM. The problem I had with that is that you end up wasting a lot of time creating an image you don’t need, plus you need a storage device large enough to hold the image which can be accessed from both systems.

My solution was to create the VM with a virtual drive the size I needed. Then use a Knoppix image to initially boot the VM, once you get to a command line, use the commands below.

On the receiving server:

sudo nc -p 2222 -l | dd of=/dev/hda

On the system to be copied:

sudo dd if=/dev/hda | nc 192.168.0.56 2222

If your CPU on each device is faster than the network, you could also gain some speed by piping the data stream through bzip2. E.g. “sudo nc -p 2222 -l | bzip2 -d | dd of=/dev/hda” and “sudo dd if=/dev/hda | bzip2 -c | nc 192.168.0.56 2222”. Whether or not it’s worth it depends on the speed of your CPUs and the speed of your network.

It’s not a requirement that you boot the system being imaged from a CD, nor that you shut down any services. But, if you don’t, it’s possible you might end up with some files that aren’t in a valid state from the application’s point of view. There’s no real method I know of to monitor the progress of the copy, but you can run “fdisk /dev/hda” to verify the copy at least got started. If the copy started OK, then you’ll see partition information the same as on the system being imaged. You can also run “ifconfig” and watch the “RX bytes” field to get an idea of how much data has been transferred, but the counter will eventually overflow and start back at 0.

0x8007232b error when attempting to activate Windows Server 2008

I had just ran into an issue attempting to activate my copy of Windows 2008 Server downloaded from MSDN. The error expands to “DNS Entry not found”, although all networking features work fine. The issue was that it was attempting to validate against an Activation Server rather than Microsoft’s website. The solution was to open “System” in the Control Panel, down at the bottom of that window is a link titled “Change Product Key”. I entered my key from the MSDN website and Windows activated automatically after the key was entered.

The difference between window.setTimeout() and window.setInterval()

From what I’ve seen, the problem most people have with the difference between these two JavaScript functions isn’t knowing what they do, but it’s knowing that they both exist. I’ve seen lots of people constantly call setTimeout() calling the same function over and over where the last line of the function calls setTimeout(), but setInterval() is probably what they really wanted, they just didn’t know it existed. But I’ve also seen lots of code that calls setInterval() to execute a function after a specific delay, and the first thing that function does is call clearInterval(), so they obviously really wanted the functionality of setTimeout(). I guess it’s mostly a result of people finding one thing that gets the job done, and never looking for anything else.

The difference between the two functions is fairly trivial. setTimeout() executes the function only once, unless you call it again; and setInterval() continuously calls the function until clearInterval() is called. The only disadvantage to using setTimeout() when you really wanted the functionality of setInterval is that the time between each call will vary depending on how long it takes your code to execute (and sometimes you actually want that feature). There is some danger in using setInterval() and hoping your code is fast enough to call clearInterval() before the interval time passes. In such a case, the next call is queued and will execute your function any number of times depending on how many times the interval time passed while your code was running.

Programming vs. Engineering vs. Mathematics.

An experiment was conducted in order to study the differences between programmers, engineers, and mathematicians. One programmer, one engineer, and one mathematician were all locked in separate classrooms for one week. Each classroom contained all of the normal things you’d find in a classroom: chalkboard, chalk, desks, etc. In addition to that each classroom contained water, one can of food (enough to feed a person for a week), but no can opener. At the end of the week, they opened the programmer’s door first. The programmer walked out. When they looked in the classroom they saw the can beat to hell, but opened. When they opened the engineer’s door, the engineer walked out. In the classroom were a bunch of equations and diagrams written on the board, one small dent in the can which was all that was required to open it. Lastly they opened the mathematician’s door. No one came out. They looked in and saw the mathematician laying dead on the floor, the can of food untouched, and a long series of equations on the chalkboard. But at the end of the equations was written the phrase: “A solution exists”.

Getting your extension to work with Firefox 3.0

When you develop a Firefox extension you’re required to specify the minimum and maximum versions of Firefox which your extension is known to work with. This is done by specifying a minVersion and maxVersion in the install.rdf file inside your plugin’s archive. Since my ClearSkyPlugin isn’t likely to break in any future version of Firefox, I attempted to bypass the version checking by setting the minVersion to 1.0, and the maxVersion to 9.0.
Of course, today Firefox 3.0 was released and my extension was detected as incompatible. After some twiddling I managed to figure out I had to set the minVersion to 1.0.* to get things to work.

If you’re having trouble getting your downloaded extensions to work, you might just disable extension version checking altogether.

Simple speach example in C#.

This uses reflection to avoid the clerical task of adding a project reference:

System.Type t = System.Type.GetTypeFromProgID("SAPI.SpVoice");
object o = System.Activator.CreateInstance(t);
t.InvokeMember("Speak", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] { "test", 0 });

If you don’t mind adding a reference, then the whole thing can be done in one line:

new SpeechLib.SpVoice().Speak("This is a test", SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);

Beware of System.nanoTime() in Java

The documentation for System.nanoTime() (and the function’s name itself) leads developers to believe it’s a much more accurate timer than anything else Java provides. Depending on which set of documentation you read, it claims to use “the most precise available system timer”. While I can’t speak for any architecture other than x86, I can state that System.nanoTime() is broken for multi-CPU or multi-core x86 systems, and generally unreliable on all x86 systems. The problem lies in the RDTSC instruction which retrieves the number of CPU ticks since the CPU started. On multi-core systems, each core will have its own tick count, and they will not match, so every time your process switches CPUs, you get a different measurement. The issue is compounded by the fact that some power management systems actually alter the CPU’s frequency to save power, which breaks the functionality even on single core, single CPU systems.

In general, do not use System.nanoTime() in any program which you don’t plan to strongly control how it is run, and the environment it is run in.

Implementation of DES in C

Below is an implementation I did of DES back in the early 90’s while I was still in college. It’s one of the first complex C programs I wrote. It served its purpose back in the day, but now more advanced algorithms and APIs have eliminated the need for such things. It’s been heavily optimized, more so than is practical in today’s world, so you probably couldn’t get it to compile even if you wanted to use it. I post it here to reminisce on my programming ability at the time, and to give an example of the complexity/simplicity of implementing an encryption algorithm.

    1 #include <stdio.h>
    2 
    3 static int keyout[17][48];
    4 
    5 void des_init(),lshift(),cypher(),des_encrypt(),des_descrypt();
    6 
    7 void des_init(unsigned char *key){
    8  unsigned char c[28],d[28];
    9  static int pc1[56] = {57,49,41,33,25,17,9,
   10               01,58,50,42,34,26,18,
   11               10,02,59,51,43,35,27,
   12               19,11,03,60,52,44,36,
   13               63,55,47,39,31,23,15,
   14               07,62,54,46,38,30,22,
   15               14,06,61,53,45,37,29,
   16               21,13,05,28,20,12,04};
   17  static int pc2[48] = {14,17,11,24,1,5,
   18               3,28,15,6,21,10,
   19               23,19,12,4,26,8,
   20               16,7,27,20,13,2,
   21               41,52,31,37,47,55,
   22               30,40,51,45,33,48,
   23               44,49,39,56,34,53,
   24               46,42,50,36,29,32};
   25  static int nls[17] = {
   26   0,1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
   27 
   28  static int cd[56],keyb[64];
   29  static int cnt,n=0;
   30  register int i,j;
   31 
   32  for(i=0;i<8;i++) /*Read in key*/
   33   for(j=0;j<8;j++) keyb[n++]=(key[i]>>j&0x01);
   34 
   35  for(i=0;i<56;i++) /*Permuted choice 1*/
   36   cd[i]=keyb[pc1[1]-1];
   37  for(i=0;i<28;i++){
   38   c[i]=cd[i];
   39   d[i]=cd[i+28];
   40  }
   41  for(cnt=1;cnt<=16;cnt++){
   42   for(i=0;i<nls[cnt];i++){
   43    lshift(c); lshift(d);
   44   }
   45   for(i=0;i<28;i++){
   46    cd[i]=c[i];
   47    cd[i+28]=d[i];
   48   }
   49   for(i=0;i<48;i++) /*Permuted Choice 2*/
   50    keyout[cnt][i]=cd[pc2[i]-1];
   51  }
   52 }
   53 
   54 static void lshift(unsigned char shft[]){
   55  register int temp,i;
   56 
   57  temp=shft[0];
   58  for(i=0;i<27;i++) shft[i]=shft[i+1];
   59  shft[27]=temp;
   60 }
   61 
   62 static void cypher(int *r, int cnt, int *fout){
   63  static int expand[48],b[8][6],sout[8],pin[48];
   64  register int i,j;
   65  static int n,row,col,scnt;
   66  static int p[32]={
   67     16,7,20,21,29,12,28,17,1,15,23,26,
   68      5,18,31,10,2,8,24,14,32,27,3,9,
   69     19,13,30,6,22,11,4,25};
   70 
   71  static int   e[48] = {32,1,2,3,4,5,
   72               4,5,6,7,8,9,
   73               8,9,10,11,12,13,
   74               12,13,14,15,16,17,
   75               16,17,18,19,20,21,
   76               20,21,22,23,24,25,
   77               24,25,26,27,28,29,
   78               28,29,30,31,32,1};
   79 
   80  static char s[8][64] = {
   81     14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7, /*s1*/
   82      0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
   83      4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
   84     15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13,
   85     15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10, /*s2*/
   86      3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
   87      0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
   88     13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9,
   89     10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8, /*s3*/
   90     13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
   91     13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
   92      1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12,
   93      7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,/*s4*/
   94     13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
   95     10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
   96      3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14,
   97      2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,/*s5*/
   98     14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
   99      4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
  100     11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3,
  101     12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11, /*s6*/
  102     10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
  103      9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
  104      4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,
  105      4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,/*s7*/
  106     13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
  107      1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
  108      6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12,
  109     13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7, /*s8*/
  110      1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
  111      7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
  112      2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11
  113  };
  114 
  115  for(i=0;i<48;i++) expand[i]=r[e[i]-1]; /*Expansion Function*/
  116  for(i=n=0;i<8;i++) {
  117   for(j=0;j<6;j++,n++) b[i][j]=expand[n]^keyout[cnt][n];
  118  }
  119 
  120  /*Selection functions*/
  121 
  122   for(scnt=n=0;scnt<8;scnt++){
  123    row=(b[scnt][0]<<1)+b[scnt][5];
  124    col=(b[scnt][1]<<3)+(b[scnt][2]<<2)+(b[scnt][3]<<1)+b[scnt][4];
  125    sout[scnt]=s[scnt][(row<<4)+col];
  126    for(i=3;i>=0;i--){
  127     pin[n]=sout[scnt]>>i;
  128     sout[scnt]=sout[scnt]-(pin[n++]<<i);
  129    }
  130   }
  131   for(i=0;i<32;i++) fout[i]=pin[p[i]-1]; /*Permutation Function*/
  132 }
  133 
  134 static int p[64] = {58,50,42,34,26,18,10,2,
  135               60,52,44,36,28,20,12,4,
  136               62,54,46,38,30,22,14,6,
  137               64,56,48,40,32,24,16,8,
  138               5 = {58,50,42,34,26,18,10,2,
  139               60,52,44,36,28,20,12,4,
  140               62,54,46,38,30,22,14,6,
  141               64,56,48,40,32,24,16,8,
  142               57,49,41,33,25,17,9,1,
  143               59,51,43,35,27,19,11,3,
  144               61,53,45,37,29,21,13,5,
  145               63,55,47,39,31,23,15,7};
  146 
  147 static int invp[64]={
  148  40, 8,48,16,56,24,64,32,39, 7,47,15,55,23,63,31,
  149  38, 6,46,14,54,22,62,30,37, 5,45,13,53,21,61,29,
  150  36, 4,44,12,52,20,60,28,35, 3,43,11,51,19,59,27,
  151  34, 2,42,10,50,18,58,26,33, 1,41, 9,49,17,57,25};
  152 
  153 void des_encrypt(unsigned char *input){
  154  static unsigned char out[64];
  155  static int inputb[64],lr[64],l[32],r[32];
  156  static int fn[32];
  157  static int cnt,n;
  158  register int i,j;
  159 
  160  for(i=n=0;i<8;i++)
  161   for(j=0;j<8;j++) inputb[n++]=(input[i]>>j&0x01);
  162 
  163  for(i=0;i<64;i++){ /*Initial Permutation*/
  164   lr[i]=inputb[p[i]-1];
  165   if(i<32) l[i]=lr[i];
  166   else r[i-32]=lr[i];
  167  }
  168  for(cnt=1;cnt<=16;cnt++){ /*Main encryption loop*/
  169   cypher(r,cnt,fn);
  170   for(i=0;i<32;i++){
  171    j=r[i];
  172    r[i]=l[i]^fn[i];
  173    l[i]=j;
  174   }
  175  }
  176  for(i=0;i<32;i++){
  177   lr[i]=r[i];
  178   lr[i+32]=l[i];
  179  }
  180  for(i=0;i<64;i++) out[i]=lr[invp[i]-1]; /*Inverse IP*/
  181 
  182  for(i=1;i<=8;i++)
  183   for(j=1;j<=8;j++) input[i-1]=(input[i-1]<<1)|out[i*8-j];
  184 }
  185 
  186 void des_decrypt(unsigned char *input){
  187  static unsigned char out[64];
  188  static int inputb[64],lr[64],l[32],r[32];
  189  static int fn[32];
  190  static int cnt,rtemp,n;
  191  register int i,j;
  192 
  193  for(i=n=0;i<8;i++)
  194   for(j=0;j<8;j++) inputb[n++]=(input[i]>>j&0x01);
  195 
  196  for(i=0;i<64;i++){ /*Initial Permutation*/
  197   lr[i]=inputb[p[i]-1];
  198   if(i<32) l[i]=lr[i];
  199   else r[i-32]=lr[i];
  200  }
  201  for(cnt=16;cnt>0;cnt--){ /*Main decryption loop*/
  202   cypher(r,cnt,fn);
  203   for(i=0;i<32;i++){
  204    rtemp=r[i];
  205    if(l[i]==1 && fn[i]==1) r[i]=0;
  206    else r[i]=(l[i] || fn[i]);
  207    l[i]=rtemp;
  208   }
  209  }
  210  for(i=0;i<32;i++){
  211   lr[i]=r[i];
  212   lr[i+32]=l[i];
  213  }
  214  for(i=0;i<64;i++) out[i]=lr[invp[i]-1]; /*Inverse IP*/
  215 
  216  for(i=1;i<=8;i++)
  217   for(j=1;j<=8;j++) input[i-1]=(input[i-1]<<1) | out[i*8-j];
  218 }
  219 
  220 int main(int argc, char *argv[]){
  221  unsigned char *key;
  222  unsigned char data[8];
  223  int n;
  224  FILE *in;
  225  FILE *out;
  226 
  227  if (argc!=4) {
  228   printf("\r\nUsage:  des [e][d] <source file> <destination file>\r\n");
  229   return 1;
  230  }
  231 
  232  key=(unsigned char*)getpass("Enter Key:");
  233  des_init(key);
  234 
  235  if((in=fopen(argv[2],"rb"))==NULL){
  236   fprintf(stderr,"\r\nCould not open input file: %s",argv[2]);
  237   return 2;
  238  }
  239 
  240  if((out=fopen(argv[3],"wb"))==NULL){
  241   fprintf(stderr,"\r\nCould not open output file: %s",argv[3]);
  242   return 3;
  243  }
  244 
  245  if(argv[1][0]=='e'){
  246   while ((n=fread(data,1,8,in)) >0){
  247    des_encrypt(data);
  248    printf("data enctyted");
  249    if(fwrite(data,1,8,out) < 8){
  250     fprintf(stderr,"\r\nError writing to output file\r\n");
  251     return(3);
  252    }
  253   }
  254  }
  255 
  256  if(argv[1][0]=='d'){
  257   while ((n=fread(data,1,8,in)) >0){
  258    des_decrypt(data);
  259    if(fwrite(data,1,8,out) < 8){
  260     fprintf(stderr,"\r\nError writing to output file\r\n");
  261     return(3);
  262    }
  263   }
  264  }
  265 
  266  fclose(in); fclose(out);
  267  return 0;
  268 }ntf(stderr,"\r\nError writing to output file\r\n");
  269     return(3);
  270    }
  271   }
  272  }
  273 
  274  fclose(in); fclose(out);
  275  return 0;
  276 }



The difference between Java’s “final” and C#’s “const”

Final in Java is used to declare a class that can’t be subclassed, a method that can’t be overridden, or …

A final variable means the value won’t change, but the value can still be determined at run time:

final int i;
if ( j > 0 ){
   i =1;
} else {
   i = 2;
}

You get a compile time error if the final variable isn’t definitely unassigned anytime you assign to it:

final int i;
if(j>0){
   i=1;
}
if(a<10){
   i=1;
}

In C#, a "const" must be determined at compile time.

Learning to program: A complete curiculum

I’ve seen many, many posts in forums asking about some good books to read to either get started in computer science, or what next steps to take after having read one intro book on a specific language. Of course none of them state what their goals are, other than they “want to learn to program”. But someone who just wants to write an occasional one off application for fun would take a vastly different route than someone wanting to earn a living as a programmer. This post is for the latter group, those who need in depth knowledge of how to design and develop systems, and are willing to accept that a lot of the process of getting there require a lot of hard work.

I’m not going to recommend specific books for several reasons: 1) Which books are good changes with time, the books I used to cut my teeth on are mostly out of print. 2) There are likely several books which are more than sufficient in each category, so there is no best book, each individual should choose books which suit their needs. 3) There are a lot of resources on line which can augment a book, for example some of the on-line course lectures, and it would be best to stick with the book(s) used in the course. 4) I have not read every book in every category, nor do I even know enough people for our combined readings encompass every book in every category, so it would be impossible to fairly represent every book. 5) I don’t recommend anyone go out and buy all of these books at once and try to read them in one sitting, rather they’ll have to be studied over time, so a better book might have come out while you were working your way through a different one. I would recommend individuals read reviews of whatever books are popular at the time they’re in the market for them.

Required:

The following topics should be considered required reading for everyone. No matter which type of programming you plan to get into, the following topics will provide a foundation to build on. The order of the books is not all that important, though you would obviously want to learn the basics a programming language as a first step. I have tried to put them in order so that it wouldn’t hurt to follow through them in the order listed.

  • Basic language book: This can be something as basic as “Teach yourself x in y hours/days/weeks”. Just don’t expect to learn it as fast as the title says. The language you choose shouldn’t be of too much concern, by the time you’re ‘done’ with this program, you’ll likely have become familiar with many different languages. A very common mistake is for beginners to put too much weight into which is the best beginner language, just pick one and go.
  • A more in depth language book: The basic book probably skipped over a lot of the features of the language. Choose a book which goes over the language in depth. There are many introductory books which do a good job of presenting the important parts of a language, so you might be able to get by with a book which combines #1, and #2.
  • Data Structures and Algorithms: This is where you start to learn how to actually get work done, and get it done efficiently. This book, and the books that follow won’t focus so much on the programming language, but higher level concepts of how to design programs.
  • Programming Languages: There are lots of languages out there, each with their strengths and weaknesses. There are also many common features among different languages. This book will help you decide which language features are available and which one is the best tool for whatever task you’re about to undertake.
  • Computer organization: This book will definitely include assembly language as one of it’s topics, in fact many books titled “Assembly Language” will suit the bill nicely. The purpose of this topic is to get an idea of what’s going on under the hood to help you design more efficient systems, as well as explain why somethings are or aren’t possible.
  • Operating Systems: Odds are you won’t be working directly with a machine, but will rely on an operating system to make working with the different parts of the machine easier. This book will likely assume you’re somewhat familiar with assembly language. Note, this is not a book titled something like “Teach yourself Windows XP in 21 Days”, but is a book which doesn’t focus on a specific operating system. It will concentrate more on the underlying concepts of how operating systems are designed. That’s not to say a book on the operating system you’re using isn’t a useful resource though.
  • Discrete Mathematics: This book will almost definitely not contain any code, in fact, it might not even mention computers. It will abstract out the abilities of the computer into mathematical terms. This will allow you to transcend the specifics of the machine you’re working with to design efficient solutions to problems, while still keeping the solution as something that can actually be implemented on a computer.
  • Networking: This shouldn’t be a “Network Programming in <Language X>”, but a book which focuses on the underlying principles of network communication. The book will likely not contain a single line of code, but it’s OK if it does. I wouldn’t recommend a totally abstract book, rather something that focus on TCP/IP with explanations of why certain things exist (or don’t exist) in the protocols would be OK.

Recommended:

For persons interested in game programming vs. those interested in business applications, the path taken will be different. Since my background is mostly in business applications, I can only recommend topics along those lines. Not all of these topics are specific to business programming per se’, but I don’t necessarily consider them to fall under the “required for everyone” heading. These topics are in no particular order and can be read concurrently with each other. And I would even go so far as to say you can read them concurrently with books in the “required” list.

  • SQL and database design: Almost every business application will involve the use of a database of some sort. It is important to be fluent in the use of databases in order to work efficiently.
  • Specific databases: Oracle and SQL Server, MySQL, etc: There are several different popular implementations of databases available, each with it’s own proprietary extensions to SQL. Unless you’re starting your own business, odds are you won’t get to choose which database implementation you get to work with, so it’s a good idea to be familiar with all of the most popular ones. Many books on a specific implementation also include a good into to SQL and database design, so you can combine this with book #1 on this list.
  • Design Patterns: Many programs share similar ideas, so much so that it’s a good idea to give certain ideas or “patterns” names. This allows you to discuss and explain patterns of programs with other developers at a much higher level. Additionally design patterns serve as examples of good design, and will save you the trouble of inventing them yourself. There is also a concept of “anti-patterns” (also called pitfalls) which are examples of common bad design, which can also be of great help. I would also like to warn you specifically of one anti-pattern, and that’s the overuse of design patterns. I’ve seen many programmers get too excited over design patterns that they want to use them everywhere, so it’s important to know when and where to use them.
  • Human Computer Interaction: Not all business applications involve a user interface, but you’ll likely end up writing many applications that do. Being able to develop a good, intuitive user interface is a very difficult task in most situations, but is one of the most important features required in order to make sure your application is actually useful.
  • Object Oriented Design: This is mostly a required concept, and is generally covered somewhat in even basic books on programming languages which are base on object oriented concepts. But it’s a good idea to study specifics of object oriented design in depth.
  • Computer Security: This is a definite must for any business application. It’s easy to be too naive and think no one will attempt to crack your application, or that they couldn’t possibly figure out your home grown obfuscation technique. Studying security will help you be skeptical about the security of every piece of your application and give you common tools to use to develop strong, robust, reliable systems.

Learn other languages:

Knowing only one programming language is almost like owning only one tool in your garage. I’m not saying you need to be a guru in a dozen different languages, but you should be fluent in at least a few languages, and a guru in one or two with the ability to become a guru in other languages quickly. While every business dreams of having all of their applications written in just one language, it’s something that pretty much never materializes, and certainly not for any successful business since the life of the business will certainly exceed the life of the language their applications are written in. So it’s an important marketable skill to be fluent in many different languages, as well as having the ability to pick up new ones without taking a week long training course. Just as an example, on any given day, I might program in as many as 13 different languages: VB6, VB.Net, C#, Java, Perl, C, C++ PHP, JavaScript, VBScript, Python, PL/SQL, Transact-SQL are all languages I use daily (but I don’t ask for your pity). I recommend knowing languages which encompass all of the following features (most languages will have several of these properties, but the idea is to learn several languages):

  • Object oriented language
  • Scripting language
  • Language with memory management built in.
  • Language without automatic memory management (C would be my recommendation)
  • Machine language
  • Static typing
  • Weak typing

Continued Learning

Once you’ve built a foundation, you can’t stop learning there. Computer programming is a field which is constantly changing and will require continued effort towards learning new and different techniques. So, if you don’t like learning new things, this probably isn’t the field for you. There’s a good chance that most of the techniques you learn today won’t be of much use 10 years from now, and whatever you’ll be doing 20 years from now will be barely recognizable as programming to a programmer today. Many of the underlying concepts change much more slowly than the actual technology, which is why it’s important to learn them. When you understand the concepts, it’s much easier to find a tool to make it happen.