wiki:GoodCodeExamples
Last modified 16 years ago Last modified on 09/11/09 14:56:36

Here we will be adding examples of good code, if you want to add somethings, please talk with the integrators first.

  • Example for good equals method.
    • You can use the mouse-right-button menu in the source code area of eclipse -> Source -> "Generate hashCode() and equals()..." for template, but refactor it to look like the example bellow:
              @Override
      	public boolean equals(Object object) {
      		
      		if (object == null) {
      			return false;
      		}
      		
      		if (object == this) {
      			return true;
      		}
      		
      		if (object.getClass() != this.getClass()) {
      			return false;
      		}
      		
      		// Custom code here...
      	}
      
  • Writing if, else, else if, for, while, do while, try, catch, finally statements, blocks.
    • First of all always put curly brackets after the special word that opens the statement, even if the statement contains one row.
      		if (some_condition) {
      			System.out.println("pass");
      		}
      
    • Insert spaces between the brackets and the words. The opening bracket of a statement is on the row where the statement is!
      		while (some_condition) {
                              // something...
      		}
      
    • When writing conditions put spaces between the operands and the operators!
      		if (a != b) {
      			System.out.println("a is not the same as b");
      		}
      
    • if-else if- else example:
      		if (a != b) {
      			// something...
      		} else if (c != d) {
      			// other thing...			
      		} else if ((b == c) && (a == d)) {
      			// third thing, I put the brackets for easier reading, they are not mandatory.
      		} else {
      			// four...
      		}
      
    • for examples
                      for (i = 0; i < n; i++) {
      			// do something...
      		}
      
                      for (Some_iterable_type some_var : some_iterable) {
      			// do something...
      		}
      
    • try-catch-finally... The same as the above as spacing and etc...
                      try {
      			// some code
      		} catch (Exception e) {
      			// handle exception
      		} finally {
      			// some stuff
      		}
      
  • Don't use @SuppressWarnings("all") and @SuppressWarnings("static-access") at all, other like @SuppressWarnings("synthetic-access"), @SuppressWarnings("unchecked"), etc.. you can use, but rarely only when needed!
  • We don't have special conventions for naming but don't use long name or stupid ones like "stuff".
  • Don't leave commented code where you tried something to be reviewed, we will be not very happy.
  • Avoid writing expressions on several lines, instead use variables... but if it's needed for example in statements here are some examples :
    • Write && and || to be first on the new line.
      		                a == b
      				&& c == d
      				|| b != g
      				&& !flag
      
    • If you Ctrl+Shift+F, please refactor your code not to have something like:
      				res
      						.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
      
      to something like
                                      res.setDefaultCloseOperation(
      						WindowConstants.DO_NOTHING_ON_CLOSE);
      
      but again it is advisable to use variables, something like:
                                      int closeOperation = WindowConstants.DO_NOTHING_ON_CLOSE;
                                      res.setDefaultCloseOperation(closeOperation);
      
  • Writing tests:
    • Write tests that test something you wrote, not the JDK
    • The tests are code, so all the above rules apply to them.
    • You can use the template for tests in Eclipse, write the word test -> ctrl+space -> choose the "test - test method" template from the auto-complete menu.
    • Our tests extend either UnitTestBase, either IntegrationTestBase.
    • Put @After, @Before and @Test annotations.
    • The first thing in a setUp method is calling the super.setUp() method, the last thing in a tearDown method is calling the super.tearDown() method.
    • When caching an Exception in a test, use the logger.error(e.getMessage(), e); to see the message and than call fail(some_message_here)!
    • Example for good test:
      package org.sophie2.base.commons.util.position;
      
      import junit.framework.AssertionFailedError;
      
      import org.junit.After;
      import org.junit.Before;
      import org.junit.Test;
      import org.sophie2.core.testing.UnitTestBase;
      
      /**
       * Unit test for {@link ImmVector}.
       * 
       * @author Pap
       */
      public class ImmVectorTest extends UnitTestBase {
      
      	@Override
      	@Before
      	protected void setUp() throws Exception {
      		super.setUp();
      	}
      
      	@Override
      	@After
      	protected void tearDown() throws Exception {
      		super.tearDown();
      	}
      
      	/**
      	 * Tests getters of {@link ImmVector}.
      	 */
      	@Test
      	public void testGetters() {
      		float x = 5.0f;
      		float y = 10.0f;
      		float t = 2.0f;
      
      		ImmVector v = new ImmVector(x, y, t);
      
      		assertEquals(x, v.getX());
      		assertEquals(y, v.getY());
      		assertEquals(t, v.getT());
      		assertEquals(x / t, v.getPointX());
      		assertEquals(y / t, v.getPointY());
      	}
      
      	/**
      	 * Tests {@link ImmVector#add(ImmVector)}.
      	 */
      	@Test
      	public void testAdd() {
      		ImmVector vec1 = new ImmVector(10.0f, 10.0f);
      		ImmVector vec2 = new ImmVector(5.0f, 20.0f);
      
      		ImmVector expected = new ImmVector(15.0f, 30.0f);
      		assertEquals(expected, vec1.add(vec2));
      
      	}
      
      	/**
      	 * Tests {@link ImmVector#dotProduct(ImmVector)}.
      	 */
      	@Test
      	public void testDotProduct() {
      		ImmVector vec1 = new ImmVector(1.0f, 1.0f, 0);
      		ImmVector vec2 = new ImmVector(-1.0f, 1.0f, 0);
      
      		float res = vec1.dotProduct(vec2);
      		float expected = 0f;
      
      		assertEquals(expected, res);
      	}
      
      	/**
      	 * Tests whether {@link ImmRect} is immutable.
      	 */
      	@Test
      	public void testImmutable() {
      		ImmVector v1 = new ImmVector(10.0f, 5.0f, 2.0f);
      		ImmVector v2 = v1;
      
      		assertSame(v1, v2);
      
      		ImmVector result = v1.add(new ImmVector(0, 0, 1));
      		assertNotSame(v1, result);
      		assertTrue(v1.equalsHomogeneously(result));
      		assertSame(v1, v1);
      	}
      
      	/**
      	 * Tests {@link ImmVector#equalsHomogeneously}.
      	 */
      	@Test
      	public void testEqualsHomogeneouslyVectors() {
      		ImmVector v1 = new ImmVector(10, 10, 0);
      		ImmVector v2 = new ImmVector(20, 20, 0);
      
      		assertTrue(v1.equalsHomogeneously(v2));
      
      		ImmVector v3 = new ImmVector(10, 15, 0);
      		assertFalse(v1.equalsHomogeneously(v3));
      
      		ImmVector v4 = new ImmVector(10, 10, 1);
      		ImmVector v5 = new ImmVector(20, 20, 2);
      
      		assertTrue(v4.equalsHomogeneously(v5));
      
      		ImmVector v6 = new ImmVector(10, 10, 2);
      		assertFalse(v6.equalsHomogeneously(v4));
      	}
      
      	/**
      	 * Tests {@link ImmVector#opposite()}.
      	 */
      	@Test
      	public void testOpposite() {
      		ImmVector vec = new ImmVector(10.0f, 10.0f);
      		ImmVector res = vec.opposite();
      		ImmVector expected = new ImmVector(-10.0f, -10.0f);
      
      		assertEquals(expected, res);
      	}
      
      	/**
      	 * Tests that multiplication between a {@link ImmVector} and a
      	 * {@link ImmPoint} is undefined.
      	 */
      	@Test
      	public void testDotProductVectorPoint() {
      		ImmVector point = new ImmVector(1.0f, 1.0f, 1.0f);
      		ImmVector vector = new ImmVector(1, 1, 0);
      
      		try {
      			point.dotProduct(vector);
      			fail();
      		} catch (Throwable t) {
      			if (t instanceof AssertionFailedError) {
      				fail();
      			}
      		}
      	}
      
      	/**
      	 * Tests that a vector must not have all zero coordinates.
      	 */
      	@Test
      	public void testEqualsPointVector() {
      
      		ImmVector point = new ImmVector(1, 1, 1);
      		ImmVector vector = new ImmVector(1, 1, 0);
      
      		assertFalse(point.equals(vector));
      	}
      
      	/**
      	 * Tests that a {@link ImmVector} cannot have all coordinates equal to zero.
      	 */
      	@Test
      	public void testAllZeroes() {
      		try {
      			new ImmVector(0, 0, 0);
      			fail();
      		} catch (Throwable t) {
      			if (t instanceof AssertionFailedError) {
      				fail();
      			}
      		}
      	}
      }
      
      
  • About the javadoc:
    • Write good javadoc that describes classes, methods and variables
    • Add yourself to the author list when you modify the logic, if your changes do not alter the logic don't do it.
    • Write parameter descriptions on the next row.
    • Use @see for methods or classes that are connected to your code.
    • Use @since for comments of special changes since some date and write your identificator and the date.
    • Use TODO, XXX and FIXME.
    • Write all the @parameter, @return, descriptions as a sentences which begin with upper case letter and end with a punctuation mark. Write the description itself of the javadoc even for getters and setters, write it as sentences!
    • Examples:
      • Method:
                /*
        	 * Moves the head position to a specified time in the timeline. If it
        	 * exceeds the length of the timeline, the position is not changed.
        	 * 
        	 * @param time
        	 *            The time to jump to (in seconds).
        	 * @return 
        	 * 	      The new head position.
        	 */
        
      • Class:
        /**
         * A class representing a given aspect of a given {@link BasePro}.
         * Currently used only with {@link BaseProList}s.
         *
         * {@link Aspect}s can be used by {@link BasePro}s internally to reduce the attached listeners
         * and the registered reads.
         * 
         * This way:
         * 1) Some reads could be registered not with the {@link BasePro} itself but with an {@link Aspect}
         * of the {@link BasePro}, and so potentially lots of listeners will be attached to the
         * {@link Aspect}s, instead of the {@link BasePro}.
         * 2) ProChanges will be fired from the {@link Aspect}s of the {@link BasePro} to registered
         * listeners, instead of always firing from the {@link BasePro} itself. 
         * 
         * @author gogov
         */
        
      • Class:
        /**
         * Base class for persist formats (like ones for saving/loading books).
         * 
         * Can load/save between two formats. It may support only saving or only
         * loading.
         * 
         * @param <S>
         *            The source type (what can be loaded).
         * @param <T>
         *            The target type (what designates the target).
         *            
         * @author milo
         */
        
  • Comments:
    • Comment all the hard to understand algorithmic structure you write.
    • Delete all the auto-generated Eclipse TODO comments.
  • Comparing objects:
    • Don't use '==' when comparing equal immutables that are not the same in the memory.
    • Compare with 'equals' objects in way where the object, calling the 'equals' method is known : For example CONST.equals(someVar);