Designing, Compiling and Running Programs
This page is an introduction to the process of designing, compiling and running your programs. The techniques described here are very general. You should note the information here and use the parts that you find most useful. However there are some things that you should try to adhere to:
- You should always include a design phase in your programming.
- You should keep a journal (of some sort, even if it is in electronic form) that can be used to keep notes on your design process and write down ideas for fixing bugs.
- You should always include comments in your code. It is an aid to good design as well as to understanding the program later on.
Designing your program
In this context, the term design means "design and coding" since coding (typing the program into a text editor) is the last phase of the design process. Most of the time you spend creating a program should be spent drawing up a design of its parts and what they do. Sometimes you can switch between design and coding by building a framework of your code and then filling it in with parts you design. If your program is large you may also want to test some parts of your program before designing other parts of the program to rely on these parts. In this case design, coding, compiling and running a program are carried out for different parts of your program. In all cases, you should start with design and spend most of your time doing it (often on paper). For large programs you may find yourself designing at a number of levels (large and small).

Stage 1: Getting to know Java's parts
Before you can start to program confidently in a language you need to know a bit about the parts of the language you will be using. A computer language can be viewed as a construction set with a limited number of types of parts but an (effectively) infinite quantity of each part. This allows us to build almost anything we like as long as it is built from these parts. Most languages make things even better by providing us with a large number of pre-fabricated parts to help us build bigger programs easily. Java has many prefabricated parts organised in a way that makes them easy to find (in the Java api). Even better, Java offers more and better ways to bolt the parts together than many languages because it is Object-Oriented.
You don't have to know all the parts before you can start writing programs (otherwise it'd be impossible to get started). You only need to know about the ones you are likely to be using. The practical exercises for Computer Science I are graded so that they start by using small numbers of parts in simple ways and gradually increase in complexity. You will learn about the parts in the lectures and you will see descriptions of the parts in the book.
You will see parts like assignment statements, if-statements, loops, classes, parameters and lots more. The lectures and the books are a good introduction but, by far, the best way of learning about these parts is to experiment with them. Write the smallest possible program that puts an unfamilar language component to the test. Test the component in different ways. This is the best way to work out exactly what the lectures and the books mean.
Stage 2: Writing down a design
Once you sort of know the parts you'll need and you've had some practice using them you are ready to start designing your program. You will often find that you will realise that you need to learn about more parts as you work through your design. In this way you will find that you will alternate between stages 1 and 2 in this design process. There is nothing wrong with this. In fact, you will probably find yourself jumping back to earlier stages of the design process quite often. This reiteration of the design process is natural. It only becomes a problem if it stops you from making progress.
When you write down a design you will first have to break down the problem you are faced with into tasks. Once you have drawn up a list of tasks you might find a list of sub-tasks that you can work on. You will find that even simple problems can be broken up in this way. The next step is to design entities to do these tasks. You will find that there will often be pre-existing entities to perform certain tasks (e.g. parts to output text, parts to convert numbers to characters and so on). Use these when you can, you know that they work (mostly). In some cases it is worth wrapping up tasks into a single entity with well defined behaviour. One way of doing this in Java is to define an object. You will see a lot more about objects later but the main purpose of objects its to create enties that perform certain tasks when they are told to.
You should write down your design in your journal (or do it electronically). You can start your design by:
- drawing pictures
- writing down thoughts
- working through the way your program will run
- any other method that helps make the problem's nature and the solutions behaviour clearer and helps you see where the boundaries of the tasks in the program are.
Once you have a name for each task you should think about that task in terms of the steps that must be taken to complete that task. Write down the steps in English. If any step has a vague name e.g. "calculate the average mark" then you might want to break this down into smaller, more precise, steps.
The sequence of steps you define to complete each task is called an algorithm. Algorithms are very important in computer science. Computers are designed to carry out algorithms.
Stage 3: Coding your design
Now is the time to bring your knowlege of language components from stage 1 and your design from stage 2 together. Coding can be viewed as a process of matching the parts in your langauge to the steps in your tasks. You're not likely to find a one-to-one match between each step in your design and a part in your language. Sometimes you'll find that a step can be made up of several parts or (if you're lucky) one part does several steps. Sometimes the limitations of the parts of the language will cause you to re-design your program. This is can happen quite often when you are starting out with an unfamiliar programming language.
When you write code you can use your journal first to write the code and then transcribe your journal to a text editor or you can just design the program in your journal and work with a text editor when you start writing your code. Your precise approach to writing code does't matter. The important factor is that you have some sort of design to begin with.
While you are coding you may find it helpful to type in the steps of your tasks as comments. Comments are pieces of text that start (and sometimes finish) with a special sequence of letters (in java some comments start with "//" some comments start with "/*" and some start with "/**") . The Java software is set up so that the computer ignores comments. You can say anything you like in comments. The computer will take no offence. Once you have written your comments you can insert the real parts of the program in between them.
When you have written a part of your program that you think you can test it is probably worthwhile testing it before you write more code. The smaller the amount of code you can write before your first test, the better. It is nicer to make small mistakes than large ones.
When you save the program in your text file you have to give it the same name as the first class that is defined in the file with ".java" suffixed on the end. If you don't do this the compiler will complain. The word class will be defined early in the course. The most important things to note right now is that your program is created by a text editor, you have to make the name of the file containing the program match a certain name you have used in the program text and, lastly, your file's name has to end with a ".java" suffix.
Choice of text editor
The java system doesn't really care which sort of text editor you use. The only requirement is that you have to use an editor that can save your program code as plain-text. That is, the editior should not be inserting weird control sequences into your program text. Some text editors such as emacs and alpha (for the macintosh) help you to program in java by coloring the relevant parts of the text and helping you (sometimes helping you too much) with formatting your program. These can save a lot of time. With any text editor you will have to remember to save your changes (often). Make sure you have saved your latest work before you attempt to compile it (otherwise you will be wasting your time on an old version of your code).
The recommended text editor for your practical sessions this year is emacs. Emacs is simple to use yet also has many powerful features you can learn to make use of (and hopefully same you time) as you progress through your degree. Emacs can also show you the line numbers in your file which is very useful for debugging your code.
Compiling your program
Once you have written your program into a text editor and saved it you can now compile the program. When you compile the program you use a program called (with some creative flair) a compiler to convert your file from a sequence of characters (that is really what a text file is) to a sequence of 1's and 0's that the computer can understand.
Actually it's not that simple. The computer sees your original file of characters as a sequence of 1's and 0's too, it's just a sequence of 1's and 0's that your computer can't really understand. Computers are very narrow-minded. The whole world is made up of 1's and 0's from a computer's point of view. It is just the fancy stuff around a computer (terminal hardware, keyboard hardware, mouse hardware and other things) that acts as translator without people (or the computer) having to know.

To make things even more complicated the sequence of 1's and 0's that comes from the Java compiler still can't be directly understood by the computer (though it's closer to looking like a sequence that the computer can understand than your original program).
How your program is compiled
To compile your program you simply need to specify its name (that is the name of the text file your created which contains your programs source, often called your source file) as a command line arguement to the program that performs compilation (javac). When you do this the first thing the computer does is look around for the machine code for the java compiler (which is called javac for short). When it finds the file containing the machine code it loads it into the computers memory. Once the compiler's code is in memory it will start executing that code. Once execution of that code begins the computer becomes a java compiler (temporarily).

Now, the computer will read in your source file and start to compile it. Once the compilier has started working it will read in your text file (which it sees as a long ribbon of 1's and 0's) and start trying to produce its output.

If the java compiler can understand your program its output will be a program in a language called java byte code. This language can't be understood directly by your computer. Your computer needs to run a program to act as an interpreter between your program which is written in byte code and your computer which really only understands a very primitive machine code. The byte code produced by the java compiler is stored in a class file. Class files have the same name as your source file except they finish with the suffix ".class" rather than ".java".
If the java compiler can't understand your program then it will not produce a byte code program. Instead, it will produce error messages. Often there will be lots of them. It is very hard to write large programs without errors that the compiler will pick up. A simple typing error is enough to stop the compiler understanding your program. This can be frustrating. The good news is, after a few months of practice, you'll find most compiler errors easy to fix. For more information on these errors see the section called debugging at the end of this page.
Running your Program
Once you have:
- Designed your program.
- Written your code in a source file.
- Compiled your source file (and fixed the errors it picked up)
You can run your program. You do this by taking the ".class" file produced by the the java compiler and passing its name (without the ".class" suffix) as an arguement to another program called a Java Virtual Machine (JVM). On most systems (including most of those you will be using) the JVM is called, simply "java".
Once you have fed your file into the JVM your computer should pretend to be the thing in your program file. It is still possible to get errors while running your program and it is definitely possible for the program not to run exactly as expected. It is this unexpected behaviour while a program is running that can tell you interesting things about how a language is set up. Often, it is possible to find very obscure properties of a languge by observing weird behaviour as your program is running.
Testing your program
If you've designed, written, compiled and run your program then you should test it to see if works properly under all sorts of conditions. Simple programs (like programs that say "Hello World" and finish) are easier to test than large ones.
For any reasonably large program it soon gets impractical to test all of the conditions that may come up. This is especially true when the program is integrated into a real system such as an aircraft or nuclear power plant. You may find that some conditions are hard to test and you may also find that the program does things wrong but does them quietly (until something really bad happens years down the track). The devising of testing strategys (so things don't go wrong years later) is an important area of study. Unfortunately, testing will rarely guarantee that your program is correct. The best strategy to minimise errors is to design the program carefully from the start.
Having said all of that, make sure you test your program with easy as well as difficult input, especially if the program is worth marks. The markers tend to run the program with all sorts of input so you have to be prepared.
Debugging your program
When you first start programming you will make a lot of errors. In fact every time you learn a new programming language you will probably make a lot of errors (I do). These errors are called bugs and fixing these errors is called debugging. Bugs are horrible...

... and fixing them, only to have more bugs appear is very demoralising. If you are just starting to program a lot of the bugs will arise because you have a different idea of how something works to the people who designed Java. These errors are the hardest to fix because you have to unlearn your original idea and relearn the correct idea. There is no way to avoid these errors but there is a way to make them easier to fix and that is to experiment with new parts of the language on a small scale before you put the new part into a program with other new parts. The driving philosophy of this is that things are easiest when you build on what you know. If you have a program that works and you want to integrate a new part into it, see if you can find a way of testing the new part by itself in a small program. It is easier to track down and fix a bug in a small program than a large one.
Where bugs happen
There are several occasions when bugs can become visible:
- When you compile your program and it complains
- When you run your program and the JVM complains
- When you run your program and your program behaves unexpectedly
- When you run your program and it behaves as you expected but what you expected was not what you really wanted after all.
Generally bugs get harder to fix as you go down this scale. A summary of each of these sorts of bugs follows.
1. Compile-time bugs
These bugs are usually easiest the fix. Often (but not always) the error message that the compiler gives you is helpful. Sometimes you will find that the compiler says that the error is on a certain line in a file but you eventually find that an error on some other line is really responsible and the line the compiler complains about is just the first place the error gets noticed. Sometimes you will find that the compiler complains about an error that seems to be related to something in your code but is really caused by other factors (you will see more of these errors when you start to use packages later on). Throughout this process you will have to bear in mind that compilers (all compilers) are simpletons. They don't have any common sense.
If you have a compile time bug that is really difficult to find the cause of, start thinking of how the bug came to be. What did you add to your program that might have caused the bug to happen? Hide parts of the program that may not be the cause of the trouble in comments and see what happens. Eventually you will find a line of code that is the real point where the error is occuring.
If you still can't find the cause of the error and you have eliminated anything complicated from around the error (remember to save the original file somewhere safe in case you want to go back to it) then you should read about the things causing the error in manuals and seek advice on its cause.
2. Run time errors
Sometimes your program is running along happily when suddenly it stops and an error message appears. These errors happen when the JVM is asked to do something that it can't do. Examples of these things include:
- Asking the JVM to get something that can't be found.
- Asking the JVM to process something that doesn't exist.
- Asking the JVM to divide a number by zero.
- Asking the JVM to handle a number bigger than is allowed by the definition of that sort of number.
There are other sorts of errors too. The ones above are quite common. Most versions of the JVM are very helpful in tracking down these errors. The JVM will often tell you which part of your program caused the error. In most other languages beside Java the computer is often not much help in tracking down an error.
If the message still doesn't give you enough information to track down the error then you should resort to putting lots of "System.out.println("I got to here: x");" messages in your code. These will print out messages telling you where your program got to before it stopped. These messages are often called trace writes. You have to make all of your trace writes output slightly different messages so you can tell which is which as the program runs.
3. Unexpected behaviour
These errors are harder to track down. You should use trace writes to try to work out where your program is going. You should choose test data to cause the problem to happen again. If you are having trouble getting the problem to happen then you can try to modify the code (remember to save the original file somewhere safe) so that the bit of program code causing the error condition runs more frequently. You should try to reduce the program down to the simplest version that still produces the error. Once you do this you know that what you have left is the cause of the error and you can work on it from there.
Quite often, even once you have found the cause of the error, this type of problem can be a lot of work to fix. This is because unexpected behaviour as the program is running is often caused by design errors. Redesigning your program is time-consuming.
4. Expected behaviour that is not what you really wanted
These errors are easy to track down. You will normally know straight away what part of the program is doing the thing that you don't want it to do. Unfortunately these errors are often the most time-consuming to fix. That is because these errors aren't caused by errors in programming, or even errors in design, they are caused by errors in your understanding of the original problem to be solved. In other words they, are a symptom of an incorrect specification of your problem.
Sometimes errors in the specification require a complete redesign of the program. In the worst cases, you might realise that the problem is a lot harder to solve than you first thought. You will probably not run into this problem very often in your first year of programming. You will start to see it happening as you work on solutions to complicated problems. Some third year subjects provide opportunities for making/avoiding this sort of error.
Conclusion
Building programs which make the computer do what you want is a difficult but rewarding task. As you learn to use more and more tools you will find that you will be able to write larger and more sophisticated programs without coming up against really difficult errors. The key to programming is to start small and experiment. After you have a lot of small programs that you know work it is easier (and a lot less frightening) to build larger programs out of these smaller parts. Once you have a deep knowledge of the tools for building programs then the range of problems you can solve will be enormous. However, as with any sphere, there are always new tools to learn and new applications to think of.
Brad Alexander
|