Teaching (Computing)

From Jtkwiki
Jump to navigationJump to search

Misc. Links

Common Programming Problems and Mistakes

Anti-Patterns

The anti-patterns described are quite basic and thus may be of little interest advanced programmers. I list them here mainly because I seem them repeatedly appearing in beginner's coding. Presumably some of these are widely known and have names other than those I use below. You're welcome to point out these in the discussion page.

Parallel Indexes and Arrays

Synopsis: Several attributes are stored in several arrays, such that attributes with the same index pertain to the same thing.

Problem Example:

 String[] name = new String[3];
 String[] address = new String[3];
 name[0] = "John Doe";
 address[0] = "13 Roe Drive";
 name[1] = "Jane Deer";
 address[2] = "17 Caribou Close";
 ...

Problem: If it's one (coherent) thing, then it should be represented as one instance.

Solution: Use one array consisting of instances that each contain several attributes.

Correct Example:

Write a class:

 class Person
 {
   private String name;
   private String address;
 
   public Person(String name, String address)
   {
     this.name = name;
     this.address = address;
   }
 }

and use that:

 Person[] person = new Person[3];
 person[0] = new Person("John Doe", "13 Roe Drive");
 person[1] = new Person("Jane Deer", "17 Caribou Close");


Redundant Representation / De-Normalised Pattern

Synopsis: Multiple instances representing the same entity.

Problem Example:

Example 1:

 Person farmer = new Person("John Doe", "13 Roe Drive");
 Person tractorDriver = new Person("John Doe", "13 Roe Drive");
 // wrong: now there are two instances of Person representing the same real person.

Example 2:

 enum WordType = {BLAH, FASEL, BLAPP};
 
 abstract class Word { ... }
 
 class Blah extends Word
 {
   static final WordType wordType = BLAH;
   // wrong: wordType redundandly records the fact that this is an instance of Blah
 }

Note: The second pattern may be somewhat forgivable if a string is declared (rather than an enum), with the intention of using that for producing a human-readable textual representation of Blah instances. It would be better to build the string literal into the toString method, however.


Problem: The state of the data held in the process can be inconsistent with respect to the problem domain. In database design, normalisation is used to eliminate such redundancy. The same principles can, and should, be applied to the design of data structures used by programs.

Perhaps it seems to some that the more transient nature of variables and instances in a process justifies a more relaxed and less rigorous approach. Normalised data structures may also sometimes appear to be difficult to work with. These arguments only apply in the development of simple software.

Normalised data structures may sometimes limit performance. This can be a good reason for deviating from normalisation. However, this should be based on an informed decision and it should be limited and documented. A generalised concern for performance is not a sufficient reason to justify generalised use of de-normalised data structures.

Solution: Design code so that each entity is represented by exactly one instance.

Everything Is a String

Synopsis: Use of strings instead of adequate types.

Example:

 String age = in.readLin();
 if (age.compareTo("18") < 0)
 {
   System.out.println("you are not yet an adult");
 }
 int agePlus5 = Integer.parseInt(age) + 5;
 System.out.printf("in 5 years, you'll be %d years old\n", agePlus5);

Problem: Holding data in a string necessitates use of awkward methods (e.g. compareTo) and multiple conversions to more adequate types (e.g. via parseInt).

Solution: Apply the classical Input - Processing - Output pattern, noticing that acquiring input does not just mean reading data from an external source (such as a file). Acquiring input frequently means parsing it. With object oriented designs, parsing should normally result in one or more instances of classes that are specific for the application's domain.

Common Misconceptions

  • Code is ok if it works correctly in a test case.
  • Trying out what a program / class / method does in a few test cases results in understanding the program / class / method.