Yup, here we go with the fun stuff!
First of all, the DDE cycle.
What is it?
Design -> Develop -> Evaluate
In business we call it ‘Analysis, Implementation, Evaluation’.
In life, we call it planning ahead, living life, reflection…
Design your solution
1. Understand the task you are about to take on – define the problem. Divide it into three separate components – inputs, outputs and processing steps to produce the required outputs.
2. Form a ‘picture’ of what the solution will look like. It may include:
- The major processing steps involved
- The major subtasks, if any
- The user interface, if any
- The major control structures (eg loops, conditions)
- The major variables and record structures
- The main path the program takes
3. Document the plan to turn the solution into reality. It could include:
- A timeline
- Allocation of tasks
- Outlining of ideas
- Sketches
- Screen designs
- Testing plan
The more complex the task, the more critical is the plan. Failing to plan could mean you are planning to fail!
Develop your solution
1. Develop and test your algorithm – the instructions documented in a standardised format that spells out to the reader exactly how the program will work. For example:
- Pseudocode (words)
- Nassi-Scneiderman diagrams (all in a box)
- Flowchart (arrows between boxes)
2. Develop a rough implementation (sometimes called alpha release) of your solution, to determine if it will actually produce the required outputs. If not, design may need to be revised.
3. Test your solution to ensure it works. Also, you may wish to test it is:
- user friendly (easy to use, has help available and does not put user in a situation they can’t handle)
- user proof (cannot be used in a way it was not intended)
4. Prepare any required documentation.
Evaluate
Evaluate both the product AND the process.
Product: the solution you have come up with
- Is the product as good as it can be?
- What would you do differently?
- Does the final product agree with the initial plan?
- Does it do what it is supposed to do?
- Is the quality consistent throughout?
- How would you rate the product?
Process: the way you arrived at the solution
- Have you worked efficiently?
- Did you stay on task?
- Did you finish on time?
- Did you complete all required aspects of the task?
- How well did team members cooperate?
- How well were tasks shared?
- Was there good communication within the team?
- Was the task affected by the personalities involved?
An objective evaluation of the product is also beneficial – somebody from outside of team is less likely to be biased.
Baby steps - the TOE method
Let's make the Develop phase a little less complicated now by using the TOE method. TOE stands for Tasks, Objects, Events. For simple projects, the TOE method makes sense, as it aids planning without overcomplicating things unnecessarily.
So, identify each of the Tasks, Objects and Events in your project.
For example; Project 1 that we worked on:
Tasks: Change the background colour of the form to red.
Objects: The main form, the button to change the colour.
Events: The button click.
It's that easy…… at least, at first. When you start to have many events and objects, it gets a bit trickier. So drawing your form(s) might help…. : )
The next example: Project 2:
Tasks: Show or hide a message text to the user
Objects: Main form, Show button, Hide button, Exit button, Text message box.
Events: Show click, Hide click, Exit click
Ok, so that looks easy again, but what do you do when there are more events than just clicking buttons?
That's why we plan - we can check our program code to ensure that we have accounted for all of the events in our plan, as it's easy to miss some. Remember, the object inspector in Delphi allows you to see which events are activated for a particular object.
Pseudocode
Remember, algorithms have 3 requirements; they must be:
- Unambiguous - clear complete instructions. Theoretically, everybody coding from your algorithm should produce programs that do exactly the same thing, because you have written it so clearly that assumptions about what an instruction means are not necessary. Writing out all of your instructions in a continuous line is NOT what we're here for.
- Finite – it must end, otherwise the program would not work properly.
- General - must stick to simple, standardised instructions, so any programmer can come along and take your algorithm away with him/her to program into the language of his choice. If your algorithm is riddled with Delphi syntax and commands for example, a VB programmer or a Java programmer will have issues interpreting the language.
One of the types of algorithms we had discussed earlier in the page is called pseudocode. It's basically listing our program out as a series of instructions - putting it into words. A happy medium, as I like to call it, between how we speak and how a computer speaks (a programming language).
Pseudocode will be weapon of choice for now. Let's look at a simple example.
Problem:
Calculate and return the area of a circle, from a radius that the user enters.
Our formula for area of a circle is Area = pi*r2 (3.14*radius*radius).
To put this into pseudocode, we need to document all of the steps that our program needs to perform. Here they are:
read RADIUS
AREA = 3.14 * RADIUS * RADIUS
write AREA
RADIUS and AREA are variables (placeholders within the program whose values can be changed by the program). We are reading the RADIUS that the user enters, and returning (writing) the AREA to the user. Your variables must be clearly distinguished from your instructions, by such means as capitals, for example.
Also, note that * means multiply, / means divide, and + and - are still add and subtract.
If we coded this in Delphi, will it work? No! It is not in Delphi syntax. Could we use this to create a working program in Delphi? VB? Java? Javascript? YES! Why? Because it’s clear, finite, and general. In fact, this algorithm is so general and portable that it can even be used on a system where a user writes the radius (eg with a pen) and the area is output to a printer, if that's the setup you have.
Your turn. Write pseudocode for an algorithm to calculate and return the average of 3 numbers entered by the user. Use the variables NUMBER1, NUMBER2, NUMBER3, TOTAL and AVERAGE.
Now that we have our working algorithm, let's work out our TOEs for the Area of Circle project.
What are the TASKS that must be performed?
- Calculate the area of a circle, based on radius (AREA = 3.14 * RADIUS * RADIUS)
What are the OBJECTS that will allow us to achieve this task? (be specific here - indicate which components you are using)
- A RADIUS Edit Box, An AREA label to output to, A CALCULATE button
What are the EVENTS that will trigger our actions?
- CALCULATE BUTTON is CLICKED
Pretty simple stuff (for now!). Now you try it. Work out your TOEs for your 'average of 3 numbers' project.
Let's take an aside for now and read a little about Delphi units, and why they are important to us as programmers. This stuff is from the text - Kevin Savage's Algorithms, Programming and Delphi 2002 (p14 - section 1.3 Delphi Units). Very important. It explains why it is absolutely crucial that you save each project into its own folder.
Developing simple applications
Delphi calls each application a project. A project can have one or more units included with it so that when it runs one or more windows can appear. The unit is the basic building block of a Delphi application. Each unit in a project has a form and Pascal code tied to it. So far we have created projects with only one unit. A unit can be created as part of a project (as we have done) or as a standalone that is later added to a project.
The procedure for creating a straightforward application in Delphi is:
- identify task, objects and events (TOE); a screen sketch will help
- start a new application with a blank form
- set the from properties
- add components
- set the properties for the components
- save the unit and project to a specified folder
- add code to the components
- resave
- run
- test and improve.
For more complex projects we will use a process called the software development cycle, but for simple applications (such as the ones above) we will follow the above procedure).
When saving your project make sure the unit, the project and any other files (eg images) are effectively named and all go into the same folder. Keeping track of what files belong to which project can be confusing, and re-establishing links between disassociated files can be tricky. Clearly naming each file and saving them into a specific project folder will save time and effort.
The Delphi unit
By breaking a project into units the task of developing an application is simplified. Each unit is independent and, if necessary, could be written by different members of a programming team. Units can also be re-used in other applications avoiding the need to re-write the code.
As an example of this, say we were going to prepare an application to let users check the personnel directory of an organisation. We might create the application with four units:
- Welcome
- Check Password
- Personnel Directory
- Exit
Each unit would have its own code and form, and together they would make up a Delphi project.
If necessary the welcome and exit units could be developed by one programmer and the other two by a second and third programmer. If the organisation wished, the welcome unit could be used for all of their applications, and perhaps the password checking unit could be used in other programs.
The use of independent, re-usable units is a very effective programming approach that we will explore later as part of structured programming.
Back to Algorithms and Pseudocode
If there's one thing you need to remember in life, it's this:
Any problem that is solvable by a computer can be written using a combination of sequence, selection and iteration.
- Djikstra
ANY problem??? Do you know what this means? This means that if you can do these things, YOU can write ANY program! Hooray for you!
Programming is that simple. Sure there are different keywords and syntax to remember that give you grief but the reality is that principles and concepts make you rich, not remembering little details (yes details help you to produce the result faster, but you can't transfer Delphi syntax into VB… which is why we have algorithms! Ha! Full circle again!).
So what do these three programming constructs mean?
Sequence - step after step (following instructions)
Selection - choosing between alternate steps (conditions)
Iteration - repeating some steps over (loops)
That's pretty simple - train goes station after station, chooses which way to go at a branch, might go around in a city circle loop. Not rocket science.
Sequence
So far you've followed 331/3% of programming theory when you've created your algorithms (sequence - instructions listed in an ordered fashion - one after the other), so let's look at the next one - selection.
Selection
IF… THEN… ELSE
Basically, it's as simple as saying IF this is true, THEN do this ELSE do that. Easier to explain with an example:
Calculate_Area_Of_Circle
_ read RADIUS
_ if RADIUS > 10
_ or RADIUS < 0 then
_ _ write 'radius out of range'
_ _ write 'program will terminate'
_ else
_ _ write 'radius is ok… calculating'
_ _ AREA = 3.14 * RADIUS * RADIUS
_ _ write AREA
_ endif
end
First of all, all those underscores at the beginning of the lines are there because I can't indent the text properly, so just try to imagine they weren't there at all.
What is happening here? The first thing you see is that our algorithm now has a name - Calculate_Area_Of_Circle. Each algorithm must have a name, as they may be executed (called) by other algorithms (It also has an end statement).
Notice that we are now using indents (space before lines). Consistent and clear indentation of your lines is a very important aspect of good documentation - it makes the algorithm (and also your program) easier to follow, and therefore easier to code, maintain and debug. The first level of indentation (no indentation - let's call it level 0) is reserved for the algorithm name and its 'end' statement. The next level (we'll call it level 1) is for statements that aren't affected by selection and iteration. Level 2 indentation is for any actions that are the result of selection (conditions) or iteration (loops). And so it goes on and on - level 3, level 4, level 5 etc… When typing up your algorithms or code, just make your indent 2 or 3 spaces rather than a whole tab stop (which is usually 8 spaces). Here's a hint, when typing up your algorithm into a word processor, set your tab stops to 3 spaces instead of 8!
Anyway, in the above algorithm, our IF statement checks if the condition is met, that is, if either of two conditions (using the OR) is true. If the RADIUS is greater than 10 or less than 0 then the condition is met and it writes two messages and ends. Only if the condition is not met will it execute the ELSE statement (and calculate and write the area).
Note that the OR and ELSE are on new lines, and are not indented further than level 1. Note that the 'do this' and 'do that' actions are indented at level 2. Very important to ensure your algorithm is readable. Finally, note the ENDIF statement indicates that the condition is finished.
Nested IFs
We can have IFs within IFs, and we call these Nested IFs:
Calculate_Area_Of_Circle
_ read RADIUS
_ if RADIUS > 10
_ or RADIUS < 0 then
_ _ write 'radius out of range'
_ _ write 'program will terminate'
_ else
_ _ if RADIUS < 5 then
_ _ _ write 'your radius is less than 5'
_ _ else
_ _ _ if RADIUS = 5 then
_ _ _ _ write 'congratulations - you have a radius of 5'
_ _ _ else
_ _ _ _ if RADIUS > 5 then
_ _ _ _ _ write 'your radius is greater than 5'
_ _ _ _ endif
_ _ _ endif
_ _ endif
_ endif
_ _ write 'radius is ok… calculating'
_ _ AREA = 3.14 * RADIUS * RADIUS
_ _ write AREA
_ endif
end
They do tend to get pretty confusing. Depending on what your conditions are, there may be an easier way using CASE… OF.
CASE… OF
We can use an alternative to the IF… THEN… ELSE statement, if we have heaps of possible values to check for.
Example.
Age_Reader_Algorithm
read AGE
case AGE of
_ 0 : message = 'embryo'
_ 1 : message = 'baby'
_ 2..4 : message = 'toddler'
_ 5..18 : message = 'schoolie'
_ 19..65 : message = 'slave to the machine'
_ 66..100 : message = 'retired'
_ else : message = 'fossil!'
end case
write message
end
Again, ignore the underscores at the beginning of the lines… But be sure that your algorithms have the appropriate indents.
What this is doing is executing an action (or group of actions) based on the value of AGE. In this case, the action is to assign a string to the variable message.
That's pretty much it.
Exercise:
Write pseudocode for an algorithm to read the user's mood (on a scale of 1-10), and outputs a message according to the user's mood.
When completed, TOE your algorithm and then use your pseudocode and TOE to code it into Delphi.
Iteration (loops)
The last of our three programming constructs is iteration which means looping, or repeating steps over and over. We use three types of loops in our algorithms. Each one has its own reason for being.
DOWHILE
The DOWHILE loop executes a sequence of code as long as a condition is met at the beginning of the loop.
Example:
count = 1
DOWHILE count <= 5
_ WRITE count
_ count = count + 1
END DO
WRITE 'finished'
What's happening here? Variable count is initialised as 1. Then the loop begins. It checks if count is less than or equal to 5. Yes it is, so execute the loop (ie execute only while count is still less than or equal to 5, otherwise skip and resume the algorithm after the END DO). Output the value of count (currently 1). Then assign to count the current value of count plus 1. Then return to the beginning of the loop to check the value of count again (it's now 2). When count is no longer less than or equal to 5 the loop is skipped and finished is output. The final output is 1,2,3,4,5,finished.
The important thing to remember about the DOWHILE loop is that the condition is at the beginning, so potentially the loop might not be run at all. If count was initialised to 6 in the above algorithm, what would be the output?
REPEAT… UNTIL
The REPEAT… UNTIL loop executes a sequence of code until a condition is met at the end of the loop.
Example:
count = 1
REPEAT
_ WRITE count
_ count = count + 1
UNTIL count > 5
WRITE 'finished'
What's happening here? Variable count is initialised as 1. Then the loop begins. As there is no check at the beginning, it executes the loop. Output the value of count, currently 1. Add 1 to count. The UNTIL line is where our condition is - check if count is equal to 5. No, it's not (it's currently 2) so repeat the loop by going back to the REPEAT. Only when count is equal to 5 will the loop end, and finished is output. The final output is 1,2,3,4,5,finished.
The important thing to remember about the REPEAT… UNTIL loop is that the condition is at the end, so the loop will always run at least once, regardless of whether the condition is met the first time it is encountered. If count was initialised to 6 in the above algorithm, what would be the output?
FOR… TO… DO
The third type of loop is a little different to the other two. There isn't really a condition - it just keeps repeating for a set number of times.
FOR count = 1 TO 5 DO
_WRITE count
END DO
WRITE 'finished'
With each iteration of this loop, count is incremented by 1. When count reaches 5, the loop is executed one last time and the algorithm resumes after the END DO. You can actually manipulate the number of iterations of the loop by changing the value of count within the loop itself, for example, a condition that says that if the user entered a special code, decrement (decrease) the value of count by 2. Having said that, you could probably argue that there is a condition - that when the value of count is equal to 5 when the END DO is encountered, the loop stops. Good for you, you do that.
Each type of loop is designed for a particular situation. When one comes up, you'll know which loop to use.
Exercise:
Write pseudocode for an algorithm that allows a user as many chances as required to guess a number between 1-100, telling them if their guess is too high or too low. If the user guesses correctly, then congratulate the user and end. Remember, use correct indentation, name your algorithm and end it. When complete, TOE your algorithm and then use your pseudocode and TOE to code it into Delphi.
Arrays: variables on steroids
In previous algorithms where we used loops to assign values to variables, we haven't stored data permanently - we've replaced the contents of the variable with the next iteration of the loop.
For example, user entering 5 test results and working out the average:
Single_Variable_Average
FOR count = 1 TO 5 DO
READ score
total = total + score
END DO
average = total / 5
WRITE average
END
What is the problem here? Nothing really, unless you needed to use one of the scores later on. Say you needed to know what the third score was… you will have to read it from the user again.
Enter arrays. An array is a series of memory spaces with the same name. Each element of the array is identified by a number (eg score[1], score[2]. You can assign a value to each element of the array. All data in the array must be of the same type, so you can't have score[1] as a real number, and score[2] as a string.
Check this out.
Array_Demonstration
FOR count = 1 TO 5 DO
READ score[count]
READ StudentName[count]
total = total + score[count]
END DO
average = total / 5
WRITE average
FOR count = 1 TO 5 DO
WRITE StudentName[count], score[count]
END DO
END
Here the scores entered by the user within the first loop are stored in the score variable (actually, no longer a variable, but an array), but each one is a separate element of the array, score[1] holds the first value entered, score[2] holds the second etc. Also, the user enters a student name for each score, which is stored in the corresponding element of the string array called StudentName.
These values may then be used again in the program, and are used in the second loop to retrieve the values in score and StudentName arrays.
Loops are a great way to cycle through each element of an array, but are not necessary if you are writing to or reading a value from one element only. For example, if you previously recorded that score[3] had the highest value and only wanted to output, you could WRITE StudentName[3], score[3]. Or, you may have assigned the value of count to the variable highest during your initial loop (highest = count) and then used WRITE StudentName[highest], score[highest] as a standalone instruction.