Showing posts with label J2EE. Show all posts
Showing posts with label J2EE. Show all posts

Sunday, October 17, 2010

Links dump 11-Oct-2010 to 17-Oct-2010

The Seven Wastes of Software Development

This talks about reducing the costs of developing software from a process-driven perspective. The seven wastes highlighted are:

  1. Partially Done Work

  2. Extra Features

  3. Relearning

  4. Handoffs

  5. Delays

  6. Task Switching

  7. Defects


As a programming grunt, I can readily identify with the problems highlighted. Basically the series talks about delivering value to customers and eliminating overheads while delivering software to the customer. These overheads are what constantly pisses off programmers. Unchecked-in, untested codes. Lost of domain knowledge. Unexplainable design decisions. Customer requests not correctly captured. Multi-tasking. Long-standing bugs that are just uncovered. The list goes on.

This is a must read for all involved in the business of building software.

Replica Island

Replica Island is a free, open-source game for Android.  I'm interested in designing some simple games but I've no experience doing such things. This website is great as source codes are provided for people to use some reference. The developer notes are also enlightening, tracing the design decisions and problems faced by Google developer, Chris Pruett. One of the most important sources of knowledge on Android game development.

chmod -x chmod

A puzzler for system administrators, what can you do if you remove the execute permission for the program that changes file permissions, aka chmod? Assume a data center environment and no Internet connection. Very interesting solutions provided.
Partially Done Work

Extra Features

Relearning

Handoffs

Delays

Task Switching

DefectsPartially Done Work

Extra Features

Relearning

Handoffs

Delays

Task Switching

Defec

Saturday, August 28, 2010

Important task completed – lessons learnt II

Recently I've been involved in a change request that modified some data that is returned to a web service client.

There was a bug that occurred whenever the stub made a remote service call, there was a conflict in the security algorithms being used. Even after googling, I still couldn't figure out what the problem was.

After some futile investigation, my colleague advised me to print out the security providers as additional providers may have been loaded during the remote service call.

So I did something like

Provider[] providers = Security.getProviders();
for (Provider p: providers)
{
System.out.println(p);
}


before and after the call, and true enough, there are security providers being dynamically added! So I called Security.remove(providerName) for those additional ones and lo and behold, it works! This is something totally new to me as I've not done much work on this aspect of Java programming before.

While debugging the problem, I realized it's sometimes more convenient to check the existence of environment variables rather than playing around with the program arguments.


#To get the environment variable in Unix
echo $PATH

#To get the environment variable in DOS/Windows
echo $PATH

#To set the environment variable in Unix
export VARIABLE=value # for Bourne, bash, and related shells
setenv VARIABLE value # for csh and related shells

#To set the environment variable in DOS/Windows
set VARIABLE=value

More info can be found at this Wiki.

Saturday, April 17, 2010

Serving static resources in Glassfish 3

I was playing around with the Google Maps API, when I found that I can't access my Javascript files in Glassfish. The JSPs were working fine, so I guess it's some URL handling thing in web.xml. As it turns out, there's a default servlet in Glassfish that should be used to serve static resources (like CSS, Javascript, PDF, image files, etc). Digging into ${GLASSFISH_HOME}/glassfish/domains/domain1/config, I found the default-web.xml. Under the section called "Built In Servlet Definitions", there's this XML snippet:


default
org.apache.catalina.servlets.DefaultServlet

debug
0


listings
false

1


I copied this verbatim into my web.xml.

Now, I want the default servlet to handle all the accesses to the static resources. I tried to map URLs with certain prefixes to this servlet like so:


default
/js/*
/css/*
/img/*


Not sure what the problem is, but it doesn't work. I'm forced to try extension matching instead:


default
*.gif
*.jpg
*.png
*.js
*.css
*.txt
*.pdf


Well, now that works, but it's not an elegant solution. Imagine, if I want to serve a new kind of file, say an Excel file, I have to remember to include the extension in web.xml, besides just throwing the file into the correct folder. I will have to relook into this again, but for now, I'm just happy it works :)

Thursday, November 5, 2009

Problems creating a JDBC resource with Glassfish 3 and PostgreSQL 8.4 drivers

What I initially thought was a straight-forward task turns out to be more complex than I imagined. After dumping the jars for PostgreSQL 8.4 driver (postgresql-8.3-701.jdbc3.jar
, postgresql-8.4-701.jdbc4.jar) into <GLASSFISH>/domains/domain1/lib/databases, I started the GF 3 server and tried to create a connection pool. I tried to create a javax.sql.ConnectionPoolDataSource resource using org.postgresql.ds.PGConnectionPoolDataSource. However I kept getting this error:
Can't find ConfigModel.Property for attr -isolation-level-guaranteed on interface com.sun.enterprise.config.serverbeans.JdbcConnectionPool

I get this error even when I do not specifiy "guranteed" for the isolation level.

Googling around,  I finally found someone with a similar problem. Seems that there is a bug in some of the earlier builds, so I downloaded the latest build (build 70)and reinstalled GF3.

All's well? Not quite. When I tried to start the server, I get some problem with using port 7676 for the default JMS host. I dont think I've gotten this error before in the older builds. Well, I did change the http-listener-2 port in domain1's domain.xml, not sure if I introduced some typo error there, so I ran
asadamin verify-domain-xml

and checked that the domain.xml is ok. The error is something along the line of
java.net.SocketException: Address family not supported by protocol family: bind

It turns out that for some reason the new GF3 build has problem using Vista's default hosts file (at C:\Windows\System32\drivers\etc).

To get it to work, change
::1 localhost

to
127.0.0.1 localhost
#::1 localhost

Restart the server again.

Now proceed to create the connection pool. However, according to the PostgreSQL driver download website,
It comes in two flavors, JDBC3 and JDBC4. If you are using the 1.6 JVM, then you should use the JDBC4 version.

.....

JDK 1.6 - JDBC4. Support for JDBC4 methods is limited. The driver builds, but the majority of new methods are stubbed out.

So, you'll need to specify an additional property JDBC30DataSource and set it to true when configuring the connection pool. That should be about it, now you can get some real work done.

Saturday, June 20, 2009

Javascript performance tuning

Recently, I was working on a customer complaint that our application was slow when churning out reports. The worst case occurs when the user selects to generate a report for the time-span of 18 months, and the application will take about 3 minutes plus to generate the reports. Not being very familiar with Javascript and DOM, I googled and found the following resources which were extremely helpful.

Nicholas C. Zakas


Speed up your JavaScript, Part 1
Speed up your JavaScript, Part 2
Speed up your JavaScript, Part 3
Speed up your JavaScript, Part 4

Yahoo! Developer Network
Exceptional Performance

Dev Opera
Efficient JavaScript

IE Blog
IE + JavaScript Performance Recommendations - Part 1
IE+JavaScript Performance Recommendations Part 2: JavaScript Code Inefficiencies
IE+JScript Performance Recommendations Part 3: JavaScript Code Inefficiencies

In our app, I found that main bottleneck was that that there was simply too much DOM interaction when creating the report's table. Creating the report involved  creating TD and TR DOM elements and adding them to a table, and deciding when to break the page. After the report is created, some of the TD cells will be merged based on some criteria.

To tune the app, I cloned the TBODY node of the table, added all the child nodes into this cloned node, and replaced the original node. Then, I has to clone the node again for doing the breaking the pages and merging the cells. Basically, it involved multiple calls to cloning the nodes, creating new doc fragments, and replacing the original nodes. Basically, it seems like the code is doing a lot more work than the original. However, it is more than 60% percent faster after tuning!

As a side-note, it really is hell trying to work on a JSP that mixes scriptlets and badly-written Javascript. First, visually it's so messy it's disorientating. Second, sometimes you can't do profiling until you've refactored the Javascript, which is sometimes hopelessly entangled with the JSP scriptlets.  And some people always wonder why I'm rewriting so much code :/

Friday, April 25, 2008

Problem starting Netbeans 6.1 RC - resolved

Recently I've downloaded the Netbeans 6.1 RC1 and RC2 but I could not get it to work. After installing, I double-clicked on the startup icon but the program won't start. I've checked the Task Manager and most of the time the process would start but end immediately. Once the program managed to run but there was no window showing.

Did some googling but could not find out more about the issue. Now, I went into command prompt to try and see if I could start Netbeans from there. Here's the result:
C:\Program Files\NetBeans 6.1 RC2\bin>netbeans.exe

C:\Program Files\NetBeans 6.1 RC2\bin>nb.exe
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
Rerunnig without "-client" option...
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

Finally! So it has something to do with not enough memory being allocated for the VM. That's weird considering I have 2 gigs of RAM and 6.0.1 worked just fine with the same programs running in the background.

Anyway, I went into C:\Program Files\NetBeans 6.1 RC2\etc folder and opened up netbeans.conf. Then I changed "-J-XX:MaxPermSize=200m" to "-J-XX:MaxPermSize=128m" and it worked.

Sunday, August 19, 2007

Debugging a JSP compilation problem on Tomcat 6

I was doing some experimentation with Maven and Tomcat 6 when I hit this error.
SEVERE: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: Unable to compile class for JSP:

An error occurred at line: 8 in the generated java file
Only a type can be imported. net.project_00.interview.java.mock.web.SomeThingStupid resolves to a package

An error occurred at line: 17 in the jsp file: /interview-java-mock-web/index2.jsp
SomeThingStupid cannot be resolved
14:
15: <%=new Date()%>
16: <%=new GregorianCalendar()%>
17: <%=SomeThingStupid.getString() %>
18: </body>
19: </html>

Stacktrace:
at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:92)
........... (rest of stacktrace)

Steps taken to debug the problem

Now, it appears to me that the error message is telling me that net.project_00.interview.java.mock.web.SomeThingStupid is not a type, but a package. I'm very sure that this is not the case after checking my code and package. Eclipse also does not give me this error when I do the import of SomeThingStupid . Conversely, when I import a package like java.util, Eclipse does give me the error.

Then I went to check that my WEB-INF\classes folder in my web-app's folder in Tomcat contained the class in the correct package. It did.

Not sure what's going on, I went to look for the generated Java class for the problematic JSP in $CATALINA_HOME\work\Catalina\localhost. I looked inside the code, nothing fishy there.

So I googled the error message, hoping to find some indication of what went wrong. Nothing useful turned up, all of them talked about importing of a package instead of a type or the exclusion of a required JAR file. Until I hit this Chinese website.

It mentions something about the Context path and docBase not being set correctly. Suspecting that my directory structure is wrong, I took the JSP page in question and copied it to the corresponding page in a web-app I know was working properly. I also copied the entire directory structure corresponding to the fully-qualified name of the class SomeThingStupid to WEB-INF\classes folder of the working web-app. And the result of the test was that it worked.

Then I checked the directory structure of the 2 web-apps and confirmed that the problematic web-app 's directory structure was wrong.

The structure of the working web-app was: $CATALINA_HOME\webapps\examples

The structure of the wrong web-app was: $CATALINA_HOME\webapps\interview-java-mock-web\interview-java-mock-web

The problem was that it was nested under an additional folder called "interview-java-mock-web" instead of being directly under the folder "webapps".

Reason for the difference in directory structure

I had used Maven2 to build the web-app, and part of Maven's advantage is that it makes the management of build life-cycle simple. However, there is a slight problem in executing "mvn clean". As stated in the "Getting Started" guide, this will remove the target directory with all the build data before starting so that it is fresh. Unfortunately, if your target directory is the $CATALINA_HOME\webapps folder, as indicated in the POM file, you will delete the entire webapps folder. This is not what I want. I want to delete only the files pertaining to the project in question and not the entire "webapps" folder, which contains other projects.

Hence my approach is to change the target directory in the POM file to $CATALINA_HOME\webapps\${artifactId}

Setting the Context element


So to resolve the original problem of the compiler not being able to find the class SomeThingStupid, the Context element has to be set in Tomcat. Taking a look at the docs, I created the file $CATALINA_HOME\conf\Catalina\localhost\interview-java-mock-web.xml

The file contains the following line:

<Context path="" docBase="/interview-java-mock-web"> </Context>

Working, but with a warning

Setting the Context element makes my web-app work, it also solves another problem of erroneous servlet mapping. However, there is a warning message when Tomcat starts up. I haven't found time to solve this.
Aug 18, 2007 10:21:06 PM org.apache.catalina.startup.HostConfig deployDescriptor
WARNING: A docBase C:\Program Files\Apache Software Foundation\apache-tomcat-6.0.13\webapps\interview-java-mock-web inside the host appBase has been specified, and will be ignored

Wednesday, July 4, 2007

Clearing the Sun Certified Java Programmer exam

It has nearly been 1 year since I bought the exam voucher for the Sun Certified Java Programmer (SCJP) exam, and today I've finally passed it! Overall, I think I've become more knowledgeable about what Java programming is about. It's definitely more in-depth and more challenging than what I had expected, even though I've been at it for a few years.

And with the advent of Java 5 and the host of new features it boasts, I definitely felt the need to upgrade myself. Moreover, my present scope of work doesn't really let me gain as much exposure or knowledge about Java than I had expected.

Preparing for the exam

You've got to be armed with a few resources to help you tackle the exam. My recommendations for books are:
SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055) (Certification Press Study Guides)
This is an excellent book. Incredibly informative and insightful, it is full of  relevant examples and peppered with some surprises about Java 5 that I felt were quite bewildering initially. The book explains the concepts well and if there is only one book to get for SCJP, it is this one. A big plus point with this book is the way the authors have imbued it with humour, making it a joy (sort of) to read.
SCJP Exam for J2SE 5: A Concise and Comprehensive Study Guide for The Sun Certified Java Programmer Exam
More of a supplementary text, it's as it's title states: concise and comprehensive. Not enough by itself, nonetheless it's pretty well-organized and certain chapters are quite well done, for example the chapters on enums and exception handling.
And here are some sites with some interesting test questions pertaining to Java,  though not necessarily Java 5.
JavaRanch
You'll want to play the Rules Roundup Game and reinforce some Java concepts. Get all your cows in the pen! No Java 5 stuff though, but it's good for the rest of SCJP.
Java Black Belt
Neatly organized site with all sorts of Java-related questions, including Hibernate and Struts. Look out for those related to the Java 5 features.

And with the passing of the SCJP, at least I've fulfilled one of my resolutions this year.

Sunday, June 17, 2007

SCJP Prep - surprising autoboxing behaviour

One of the features introduced in Java 5 is autoboxing. Boxing means that we take a primitive such as a char, byte, int, etc and wrap it using it's corresponding wrapper class such as Char, Byte, Integer, etc so that we can use the object. Unboxing means retrieving the value from a wrapper. In the code fragment below, the Integer object is first unboxed, the value is summed with 10, and the summed value is boxed into a new Integer object.

[java, Y, 1]
public Integer addTen(Integer num)
{
return new Integer(10+num.intValue());
}


With autoboxing, all this boxing and unboxing is transparent to you. Therefore you can write simpler code like

[java, Y, 1]
public Integer autoboxAddTen(Integer num)
{
return 10+num;
}


While it allows developer to write succinct code, it can be a problem if we are not careful. For example, we'll have to be careful of NullPointerExceptions when we do autoboxing, which we will hit in the code below

[java, Y, 1]
public void doSomething()
{
Integer num=null;
System.out.println(autoboxAddTen(num));
}


Another snag we might hit is if we try to autobox a primitive into a non-corresponding wrapper type. In the code below, we can assign b to i according to conversion rules. But we'll have to take note that autoboxing only occurs primitives and it's corresponding wrapper type, eg int and Integer, byte and Byte, double and Double, etc

[java, Y, 1]
public void doSomethingElse()
{
int i=1;
byte b=7;
i=b;
Integer iObj=i;
iObj=b; //error. Type mismatch: cannot convert from byte to Integer
}


The most surprising behaviour though, is this. I saw some bloggers posted this problem, but I couldn't see what the problem was until someone explained it. Can you see where the problem is?

[java, Y, 1]
public class SurpriseAuoboxingTest1 {

public static void main(final String[] args) {

Integer i1 = new Integer(2);
Integer i2 = new Integer(2);
System.out.println(i1 == i2); // false

Integer j1 = 2;
Integer j2 = 2;
System.out.println(j1 == j2); // true

Integer k1 = 150;
Integer k2 = 150;
System.out.println(k1 == k2); // false
}
}


It might be clearer if we test some more values.

[java, Y, 1]
public class SurpriseAuoboxingTest2 {
public static void main(final String[] args) {
Integer l1 = 127;
Integer l2 = 127;
System.out.println(l1 == l2); // true

Integer m1 = 128;
Integer m2 = 128;
System.out.println(m1 == m2); // false

Integer n1 = -128;
Integer n2 = -128;
System.out.println(n1 == n2); // true

Integer o1 = -129;
Integer o2 = -129;
System.out.println(o1 == o2); // false
}


The second set of values are the edge cases, for something...but what? Basically, it's the range of integral values for cached objects.

Here's what Sun has to say on this:

The primitives are equal and the values of the boxed ints are equal. But this time the ints point to different objects. What you have discovered is that for small integral values, the objects are cached in a pool much like Strings. When i and j are 2, a single object is referenced from two different locations. When i and j are 2000, two separate objects are referenced. Autoboxing is guaranteed to return the same object for integral values in the range [-128, 127], but an implementation may, at its discretion, cache values outside of that range. It would be bad style to rely on this caching in your code.

In fact, testing for object equality using == is, of course, not what you normally intend to do. This cautionary example is included in this tip because it is easy to lose track of whether you are dealing with objects or primitives when the compiler makes it so easy for you to move back and forth between them.


It's good to remember what is happening beneath all this autoboxing, we're not getting the convenience for free. For a more in-depth look at the possible repercussions of autoboxing, take a look at this post on murphee's Rant.


# Newbies will write slow code because of it: Well, one of the problems that might occur, is newbies that write horribly slow code, because they never really grasped the difference between primitives and their reference types. If the wrapper types are overused, a lot of useless AutoBoxing and Unboxing will happen. Experienced Java developers will know when that is the case and can avoid this. One of the reasons why Sun introduced this feature, is their initiative to make Java easier to use to attract more and more developers (at the last JavaOne the number 10 million was mentioned as a goal). These would mostly be taken from the MS languages like VB. So... we are talking about a lot of newbies coming along... and a lot of newbies writing code that is slow, because of the above mentioned issues.
# Memory usage will increase tremendously: Another issue concerning inexperienced developers. A newbie might think "Why should I use some weird int[] numbers = new int[x] when I could use a more flexible List numbers = new ArrayList(x);?". Well... one the main reason is the fact, that the latter version will use up way more memory than the former one. In the worst case, it could mean a 400 % increase over the array solution (why 400%? An Integer object will use 16 bytes of memory, which is four times the 4 bytes that the int value would use. It is an 400 % increase because the int[] only uses an array of 32 bit values to hold its contents. The Integer version would need an array of references (32 bits or 64 bits, depending on your CPU) plus the memory for each object).

Wednesday, June 6, 2007

Maven2 - installing 3rd party JARs

Have a little time these few days, trying to get familiarised with Maven2. Not for work, more for it's own sake, still stuck with a legacy app at work. Been reading about the praises for Maven over Ant but the learning curve for Maven is steeper than Ant. And I'm not sure that the Eclipse plugin is making it easier. Some accidents along the way when running "mvn clean" wiped out the entire webapps folder in Tomcat, not just the test app folder I was anticipating. Thankfully it's a fresh install of Tomcat 6, so it's just the default stuff that came along with it.

Anyway tried to manage some dependencies with Maven, wasn't as fuss-free as it's made out. Tried to compile a simple servlet under eclipse, but I couldn't add the dependency via the Eclipse plugin. Had to add it in manually in pom.xml.

Went to "C:\Documents and Settings\Administrator\.m2\repository" to take a look, looking for servlet-related strings. But not too sure about what I'm looking for so decided to install the JARs that came with Tomcat 6 in the end. Here's the commands I ran.



mvn install:install-file -DgroupId=tomcat -DartifactId=servlet-api -Dversion=6.0.13 -Dfile="C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib\servlet-api.jar" -Dpackaging=jar



mvn install:install-file -DgroupId=tomcat -DartifactId=jsp-api -Dversion=6.0.13 -Dfile="C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib\jsp-api.jar" -Dpackaging=jar



mvn install:install-file -DgroupId=tomcat -DartifactId=el-api -Dversion=6.0.13 -Dfile="C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib\el-api.jar" -Dpackaging=jar



The Tomcat website has some instructions on using Tomcat libraries with Maven, but I can't figure out how to get Maven to download the libraries from the correct location.

Hang on, actually I do now. The following has to be added into pom.xml

[xml]

tomcat.staging.repos
http://tomcat.apache.org/dev/dist/m2-repository/org/apache


Wednesday, February 7, 2007

SCJP Prep - when dividing by zero is ok

One of the most common examples used to illustrate exceptions is the "division by zero" example.
Exception in thread "main" java.lang.ArithmeticException: / by zero
I think I've seen it in a few Java books, so I've always had this impression that it's never ok to divide a number by zero. Until I started preparing for the SCJP, that is. I ran the code below.

[java]
import java.io.*;

class TestDivideByZero
{
public static void main(String[] arg) throws IOException
{
System.out.println(1/0.0); //prints "Infinity"
System.out.println(1.0/0); //prints "Infinity"
System.out.println(-1/0.0); //prints "-Infinity"
System.out.println(-1.0/0); //prints "-Infinity"
System.out.println(1/0); //runtime error here
System.out.println(-1/0); //runtime error here
}
}


So what's up? According to Sun:


Despite the fact that overflow, underflow, division by zero, or loss of information may occur, evaluation of a floating-point division operator / never throws a run-time exception.

Monday, November 27, 2006

New release of EasyEclipse 1.2, based on Eclipse 3.2 Callisto

EasyEclipse 1.2 is finally released, get it here. All the plugins for your development needs, none of the fuss (well almost).

Monday, August 21, 2006

Struts DispatchAction - unspecified method

I was going through a tutorial about DispatchAction and trying to define a default page to forward to when an invalid value is passed in. Eg, the parameter passed in from a form should only be value "yes" or "no" but not "maybe". If the value "maybe" is passed in, I want to handle it and forward to a default page.

I read the API for DispatchAction unspecified method, which says, "Method which is dispatched to when there is no value for specified request parameter included in the request. Subclasses of DispatchAction should override this method if they wish to provide default behavior different than throwing a ServletException."

It doesn't quite do what I expect it to do. java.lang.NoSuchMethodException will be thrown, because getMethod() cannot find a method with the specified name. Isn't that what the unspecified() is for? Seems like it's not the case. If I try to access the subclass of DispatchAction directly, the unspecified() method will run, but not if I try to pass in an null or invalid value for the parameter. So how should I solve this?

I overrided the dispatchMethod(), checked if getMethod() thows a NoSuchMethodException(), and set a default value after after catching the exception, like below.

[java]
protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse resp, String methodName) throws Exception {
// TODO Auto-generated method stub
String methodToCall=null;
try
{
if (methodName!=null)
{
log.info("methodToCall in TestDispatchAction is:"+methodName);
getMethod(methodName);
}
else
log.info("methodToCall in TestDispatchAction is null");


methodToCall=methodName;
}
catch (NoSuchMethodException exc){
log.info("NoSuchMethodException caught in TestDispatchAction");
methodToCall="defaultMethod";
}
return super.dispatchMethod(mapping, form, req, resp, methodToCall);
}
If you don't declare the parameter at all in the JSP, an empty string is passed in, not null. I wonder why.

Sunday, July 30, 2006

EasyEclipse - Free, open source, easy-to-use

EasyEclipse - Free, open source, easy-to-use Eclipse distributions and plugins for Windows, Mac and Linux

I was looking around for a decent Struts plugin for Eclipse when I came across this.

As the developers of EasyEclipse say:
Our focus is supporting Eclipse-based IDEs from the point of view of an individual developer or a small development team. As a developer, you need a specific and robust set of development tools in the smallest and simplest package possible – this is what EasyEclipse provides.

Each EasyEclipse distribution is tailored for a specific development environment with just the right functionality for that environment – no more complexity than necessary and one easy download and install procedure. And EasyEclipse is free.

Well, I think they are just about there. EasyEclipse is a neat package, not much clutter to tinker around with. There are specific packages tailored to your needs, whether you work more on desktop, mobile or server-side development. And of course you can install plugins if a particular distribution lacks a few tools that you need. While not as polished as MyEclipse, it serves my needs well, with support for Tomcat, Struts, Hibernate and Spring ready out-of-the-box for server-side distribution. I can can spend more time on learning rather than fiddling around with the IDE, or what some people call Eclipse Download Hell.

Sunday, May 14, 2006

Freelancing for students’ assignments

I started doing some small freelance Java projects for university students about 1.5 years ago. The money is not great, afterall, how much can students afford to pay? Sometimes a day in the office gets me more than 3 days on the students' assignments. The good thing about it is I get to learn about new stuff I wasn't aware of, or I get to do some hands-on stuff on the things I had read. I did my first decent Swing program (a Point-Of-Sale system) as a freelance project, and learnt about the new features of J2SE 5.0(in particular, generics) in another. As quite a big bulk of the projects/assignments deal with data structures, I also had the opportunity to refresh my concepts on sets, tries, trees, linked lists and such. Couldn't I have done this on my own free time? Definitely, but I guess I'm a bit lazy, and tiny monetary incentives can give me a nudge in the right direction. :)

I have a few "customers" who contact me now and then when they need some help, and I will oblige if I know what to do and have the time. Previously, I worked on a trust basis, as in I'll send them the source code first, then they'll transfer the money to me. But I had a nasty experience when one person went MIA after I sent him the source code, didn't reply to my emails. I guess I was too naive, but thankfully I was able to find out who the person was in real life as his real name was in the Word document which contained the project specs. I googled for his online nick and came across it in a certain university discussion board, where he left his real name as well. So finally I was able to identify him, which gave me some leverage when I asked for payment, which came in the end. So I've changed my billing policy since then. More on that next time.