Solving Problems - Griffith-ICT/1701ICT-Creative-Coding GitHub Wiki

Computer programs can be challenging to write for a number of reasons:

  • They can be complex.
  • They can be large.
  • They can involved difficult algorithms.

We are going to discuss some strategies to make it more manageable to design and build a computer program.

Divide and Conquer

Divide and conquer is an age-old strategy to break larger tasks into smaller simpler tasks.

Computer programs often contain a number of parts or sections. It may be possible to attack them individually. Note though that programs can also be intertwined so achieving complete independence in parts of the program can be tricky and perhaps not desirable.

A good program design goal is loose coupling. Loose coupling relates to how dependent parts of the program are on each other. We will discuss later in the course how using functions and in particular passing parameters can create loose coupling. Loose coupling can also have the side effect that the parts are more reusable in other programs as they are less dependent on one particular program.

Slicing and Dicing

So how to we determine the parts? There is no fixed method to form parts. However, there are various software design techniques which can aide in the dividing. One is using object-oriented design where classes of objects are identified with their responsibilities. Another technique is Model-View-Controller or MVC for short. It is assumed that different parts of a program have different responsibilities that can fall into one of the three categories, the terms are roughly defined as:

  • Model - Parts of the program responsible for accessing and managing stored data
  • View - Parts of the program responsible for draw to the display
  • Controller - Parts of the program responsible for the logic of the program, for example, updating the trajectory of an animating object based on its current velocity.

Object-oriented design and MVC will be covered in later courses.

Another approach is to identify dependencies in the program. This approach is used in Component-Level Design. A component however is an independent reusable object often a class or object. In this course our projects will be smaller so that we won't need to write reusable components. Note that we are using reusable components. The p5.js libraries are reusable components.

Instead we are more likely to be identifying coding tasks that we will need to perform. There will be dependencies between those tasks. In this sense we can approach the problem of writing a program as a project management problem.

Here is a list tasks for a game, in order of dependency, i.e. the later tasks depend on the earlier tasks:

  1. Draw game screen
  2. Create array of object positions
  3. Draw objects on screen
  4. Move objects on screen
  5. Detect collisions
  6. Update score

Note that the order above allows us to implement the program incrementally. If we only implement up to task 4, the program will still largely work.

However, if we implement them in a different order the program may not work until later tasks are implemented. For example if we start by implementing the update of the score (task 6), we actually can't update the score because we haven't implement collision detection (step 5). If we start by implementing step 5, we can't because we don't have any objects to detect collisions, and so on.

Think of a program you would like to implement, what are the main tasks, and what are the dependencies for each of those tasks? Write the tasks in order of dependency so that the program should run at any task as long as they are implemented in order.

An iterative approach

Another common approach to designing and implementing software is iterative. More recently iterative is part of the agile paradigm. Agile is the latest buzzword which encompasses other facets as well, but a key part is iterative. Iterative means that we might complete an entire first pass of the project without actually completing the project, so that we can evaluate it and get feedback before implementing more code. The advantage of iterative is that it allows you to get early feedback before too much code as been written.

The iterative approach is similar to the dependency approach discussed in the previous section in that the program will run at each level of the iteration. There may not be any demarcation of what an iteration is, except that the process will be iterative. The first iteration will not focus too much on detail but overall layout and functionality. Each subsequent iteration will include more detail.

For example, in the previous game example, an iterative approach may implement all 6 tasks once, without final graphics, or perfect game play, and then go through all 6 tasks again multiple iterations until the final game is ready. However, since the 6 tasks have been implemented at the start there may not be the need to go through all 6 tasks each iteration, an iteration may only fine tune one task such as updating the score or how the objects move and collide.

Next: Algorithms