CPTTM software developer newsletter issue #7

Dear Software Developers,

This CPTTM Software Developer newsletter is to bring useful news to you, software developers in Macau, for references without obligations, so that you can do your jobs easier and better! Hope you like it. if you'd like to unsubscribe or recommend your friends to subscribe, just let me know. Old issues are available here.

Kent Tong, Editor in Chief

Topics in this issue:

Simple way to improve code quality

We can improve our code quality easily. For example, consider the following code I took from the Internet:

public class FamousCurves extends Applet {
double tmin;
double tmax;
double dt;

public void init() {
this.tmin = 0.0;
this.tmax = 6.824;
String tminstring = getParameter("tmin");
String tmaxstring = getParameter("tmax");
String dtstring = getParameter("dt");
if (tminstring != null) {
try {
this.tmin = Double.valueOf(tminstring).doubleValue();
} catch (NumberFormatException e) {
}
}
if (tmaxstring != null) {
try {
this.tmax = Double.valueOf(tmaxstring).doubleValue();
} catch (NumberFormatException e) {
}
}
if (dtstring != null) {
try {
this.dt = Double.valueOf(dtstring).doubleValue();
} catch (NumberFormatException e) {
}
}
}
}

Obviously a lot of code is duplicate. We can extract the duplicate code into a method:

public class FamousCurves extends Applet {
double tmin;
double tmax;
double dt;

public void init() {
this.tmin = parseParameter("tmin", 0.0);
this.tmax = parseParameter("tmax", 6.824);
this.dt = parseParameter("dt", 0);
}
private double parseParameter(String paramName, double defaultValue) {
String paramValue = getParameter(paramName);
if (paramValue != null) {
try {
return Double.valueOf(paramValue).doubleValue();
} catch (NumberFormatException e) {
}
}
return defaultValue;
}
}

Now the code is a lot easier to read and write. To learn more about similar skills and do more exercises, attend our upcoming OO course.

Using transactions easily

Common we use transactions like this:

public class CoursesService {
public void addCourse(Course course) {
System.out.println("start transaction");
try {
//add a course
System.out.println("committing transaction");
} catch (RuntimeException e) {
System.out.println("rolling back transaction");
throw e;
}
}
public void deleteCourse(String courseCode) {
System.out.println("start transaction");
try {
//delete the course
System.out.println("committing transaction");
} catch (RuntimeException e) {
System.out.println("rolling back transaction");
throw e;
}
}
}

The transaction handling code and the try-catch are duplicate in many such methods. To extract the code, we can say that whenever someone tries to call any public method in the CoursesService class, start a transaction and then enter a try-catch, execute the original method and finally commit or rollback. This can be done using AOP (Aspect Oriented Programming):

public aspect Transaction {
Object around(): call(public * CoursesService.*(..)) {
System.out.println("start transaction");
try {
Object retValue = proceed();
System.out.println("committing transaction");
return retValue;
} catch (RuntimeException e) {
System.out.println("rolling back transaction");
throw e;
}
}
}

What it says is that, whenever any public method of CoursesService is called (the return type, the method name are wildcards matching anything and the arguments are ignored), run the code inside the curly brackets. In that code, it starts a transaction and then enters a try-catch. The proceed() statement will call the original method using the original arguments. Finally it commits. If a RuntimeException is thrown, it will rollback the transaction. Now CoursesService can be simplified as:

public class CoursesService {
public void addCourse(Course course) {
System.out.println("adding a course");
}
public void deleteCourse(String courseCode) {
//some test code
if (courseCode.equals("c1")) {
System.out.println("deleting a course");
}
if (courseCode.equals("c2")) {
System.out.println("c2 not found");
throw new RuntimeException();
}
}
}

If you have a main program like:

public class Main {
public static void main(String[] args) {
CoursesService service = new CoursesService();
service.addCourse(null);
service.deleteCourse("c1");
service.deleteCourse("c2");
}
}

The output will be:

start transaction
adding a course
committing transaction
start transaction
deleting a course
committing transaction
start transaction
c2 not found
rolling back transaction
Exception in thread "main" java.lang.RuntimeException
at test.CoursesService.deleteCourse(CoursesService.java:13)
at test.Main.deleteCourse_aroundBody4(Main.java:8)
at test.Main.deleteCourse_aroundBody5$advice(Main.java:107)
at test.Main.main(Main.java:8)

To learn more about AOP, see the AspectJ Programming Guide. To actually run the code above, get the AspectJ Development Tools for Eclipse and choose to create an AspectJ project. In addition, Spring also provides AOP support and thus you don't have to use another IDE or plugin. You can take our upcoming Spring course to learn more.

Feedbacks

Have any questions, ideas or experiences regarding software development? Contact me at 781313 or kent at cpttm dot org dot mo.

Until next time, 

Kent Tong