Whither Java and whither offshore Java developer?

Ever since Oracle bought over Sun Microsystems, the future of Java as a language and a platform has been a hot topic of debate among the development community. The doomsayers have already started singing the swan song of Java although no one is quite sure who or what will replace Java eventually.

The future of Java programmer came up as the topic of discussion in a recent JavaPosse podcast (recorded earlier during the JavaPosse conference in early 2011). Listening to the discussion, I couldn’t help wondering what it meant for the offshore developer.

Hey offshore guy, how’s that enterprise code coming along?

If you are an offshore developer, chances are you are working for a medium to large size IT consultancy somewhere in Bangalore or Manila working for a large Banking/Insurance or Telecom client. Reading about Scala, Groovy and Clojure and how Java is bloated, you are wondering what the deal is all about? There’s enough work and more, you think. You just finished a project that used Spring and Hibernate and there is another EJB3 project in the offing. So why is everyone suddenly speaking of Java like it was something the cat dragged in?
And here in lies the crux of this debate. You see, Java is one of the most popular languages today (Tiobe index, anyone?). According to some estimates, there are a few million Java programmers in the world. It wouldn’t be amiss  remiss to say that at least a third of those are probably working for the outsourcing industry. The outsourcing budget for most Fortune 500 companies is only going to increase in the next year. Most of the work outsourced by these companies falls under the category of enterprise development for which no viable alternatives exist currently which look better than Java.
The outsourcing industry will always prefer technologies that can be commoditized. Java is a prime candidate. It’s easy to learn and has excellent tooling support. For large scale projects, outsourcing consultancies help manage costs by their ability to add and remove scores of developers with short notice. For those who scoff at the quality of software this produces, let me just say that a) the quality is good enough which is more than what most of these applications need, and b) the predictability and tooling around Java helps minimize the risks. Now imagine doing this with Scala which has an extremely high entry barrier and practically no tool support.
However, like every knowledge area, there are fashionistas in the programming world as well. Well deserving, hardworking programmers in the developed world who attended fancy computer science courses and dabbled with Robotics in their teenage no longer find Java niche. This group of developers is generally the early adopter of newer technologies. They attend conferences and write blog posts comparing Scala and Clojure and scoff at Java’s bloatedness. If you are such a developer, congratulations! We need more like you. To show the rest of us the way ahead. So please keep doing the good job you are doing.

In the meantime…

If you are a “senior” Java programmer writing enterprise code, what does this mean to you? Should you start learning Scala or Groovy or Clojure ? Or should you give it a miss because there is no way Scala or Clojure will replace Java for a long time to come ?
I have the following advice.

  1. Don’t get intimidated by all the talk about Java’s demise. Java is here to stay. But,
  2. Continue learning new languages. Languages like Scala give you a fresh perspective on programming and will make you a better Java developer.
  3. Learn to write good Java code. Now that you know the functional aspects like the back of your hand, start paying attention to non functional stuff like performance.
  4. Learn how to make your code testable, learn the importance of good version control and continuous integration. Many a project becomes a drag to work on simply because there is no easy way to integrate and test all the work everyone’s doing.
  5. Don’t learn NoSQL yet. But do learn SQL well. It’s easy. And it’s extremely useful.
  6. Pay attention to design. Pick up HTML and CSS. Make sure your next boring CRUD application is just a tad bit less boring to look at.
  7. Understand the pains specific to your work – remote connectivity, non cooperative clients, pesky managers, incomplete requirements, late night calls and find creative ways to resolve these.

In short, do not worry about the fancy stuff. We still have a long way to go before we can master writing really good Java code and executing outsourcing projects well.

All the best!

Algorithm practice – Possible addition combinations for any given number

I came across this interesting puzzle today on stackoverflow. Basically, the problem is to display all possible combinations of additions that can sum up to a given number. so for example, if the user enters 6, the program should display

>> 6

0+6=6
1+1+1+1+1+1=6
1+1+1+1+2=6
1+1+1+3=6
1+1+4=6
1+5=6
2+1+1+1+1=6
2+1+1+2=6
2+1+3=6
2+4=6
3+1+1+1=6
3+1+2=6
3+3=6
4+1+1=6
4+2=6
5+1=6
6+0=6

This is a classic recursion problem. Here’s my solution in Java.

	public void run(int n)
	{

		List<StringBuilder> combos = showAdditionsFor(n);
		
		for (StringBuilder s : combos)
		{
			if (s.indexOf("+") < 0)
			{
				System.out.println(s + " + 0 = " + n);
				System.out.println("0 + " + s + " = " + n);
			}
			else
			{
				System.out.println(s + " = " + n);
			}
		}
	}
	
	List<StringBuilder> showAdditionsFor(int n)
	{
		List<StringBuilder> list = new ArrayList<StringBuilder>();
		if (n == 0)
			list.add(new StringBuilder(""));
		else if (n == 1)
			list.add(new StringBuilder(String.valueOf(1)));
		else
		{
			for (int i = 1; i <=n; i++)
			{
				//get n-i list
				List<StringBuilder> tempList = showAdditionsFor(n-i);
				appendToEachListElement(String.valueOf(i),tempList);
				list.addAll(tempList);
			}
		}
			
		return list;
	}
	
	
	private void appendToEachListElement(String x, List<StringBuilder>l)
	{
		for (StringBuilder s : l)
		{
			if (s.length() == 0)
				s.append(x);
			else
				s.append("+" + x);
		}
	}

My program creates a list of all possible combinations as Strings. For input=6, it prints all possible combinations as follows.


1+1+1+1+1+1 = 6
2+1+1+1+1 = 6
1+2+1+1+1 = 6
3+1+1+1 = 6
1+1+2+1+1 = 6
2+2+1+1 = 6
1+3+1+1 = 6
4+1+1 = 6
1+1+1+2+1 = 6
2+1+2+1 = 6
1+2+2+1 = 6
3+2+1 = 6
1+1+3+1 = 6
2+3+1 = 6
1+4+1 = 6
5+1 = 6
1+1+1+1+2 = 6
2+1+1+2 = 6
1+2+1+2 = 6
3+1+2 = 6
1+1+2+2 = 6
2+2+2 = 6
1+3+2 = 6
4+2 = 6
1+1+1+3 = 6
2+1+3 = 6
1+2+3 = 6
3+3 = 6
1+1+4 = 6
2+4 = 6
1+5 = 6
6 + 0 = 6
0 + 6 = 6

The program could also be further refined to eliminate duplicate combinations by using Sets instead of StringBuilders.

I have also decided to eliminate the combination with 0 in the calculation logic because it adds ambiguities to the solution (as this answer points out). Instead I am handling this case by brute force in the run method.

A possible reason why database transactions may not work in CodeIgniter with MySQL

For CodeIgniter transactions to work in MySQL, make sure that the database engine is InnoDB or BDB, both of which are transactional as opposed to MyISAM which is more common but a non-transactional engine.

This is clearly mentioned in the CodeIgniter documentation but easy to miss if you are not paying attention.

Vi magic

I was trying to replace the pipe character with a comma in a file using vi. I tried using

:%s/\|/,/g

to replace all pipes with commas in the following string.

|a|b|c|d

But this didn’t work and resulted in a comma before each letter as follows.

,|,a,|,b,|,c,|,d

Searching on the internet, I found a suggestion that worked.

:%s/\v\|/,/g

this correctly replaced the pipes to commas as expected.

a,b,c,d

After some digging through the vi manual, I found out that this was because vi has a special meaning for ‘\|’ when used in patterns.

In a vi substitution pattern, some characters are taken literally and gain special meaning if preceded by a backslash. At the same time, there are some other characters that have a special meaning by default and need to be preceded by a backslash for a literal match.

This is governed by the ‘magic’ option in vi.

The pipe character is non-magic by default which means it need not be escaped for a literal search. So the expression

:%s/|/,/g

would have also worked in this case.

The expression

:%s/\|/,/g

escaped the pipe character and therefore made it “magic”. Pipe, in its special form is treated as a separator. So in this case, the expression reads

“Find nothing and replace with a comma i.e., add a comma before every character.”

Using \v makes every following character to be treated as special or magical. Therefore

:%s/\v|/,/g

makes the pipe character from non-magical to magical.

But escaping pipe with a slash makes it non-magical again.

:%s/\v\|/,/g

The expression, therefore, now reads as

“Replace pipe character with comma”

which works as intended.

Mars Rovers

This is my solution for the famous Mars Rovers problem. The problem is a typical random walk simulation problem with input data coming from user. I wrote this in Java in 2007. Looking back, I do admit that there is a lot of verbosity here. In a more expressive language, the solution could be reduced to half, I am sure.

package com.nasa.rovers.data;

//Enumerator for Directions (N,E, W, S)
/*
 * Each direction is defined as a set of 1 step move from (0,0) in that direction
 * so NORTH is (0,1) and EAST is (1,0) and SOUTH is (0,-1) and so on
 *
 */
public enum DIR {
	N(0, 1), //NORTH
	E(1, 0), //EAST
	S(0, -1), //SOUTH
	W(-1, 0); //WEST

	private XY xy;

	DIR(int x, int y) {
		xy = new XY(x, y);
	}

	public XY getXY() {
		return xy;
	}

	public DIR left() {
		//return the left (i.e. anti clockwise) move of 'this' direction
		switch (this) {
		case N:
			return W;
		case E:
			return N;
		case S:
			return E;
		case W:
			return S;
		}

		throw new AssertionError("Unknown direction: " + this);
	}

	public DIR right() {
		//return the right (i.e. clockwise) move of 'this' direction
		switch (this) {
		case N:
			return E;
		case E:
			return S;
		case S:
			return W;
		case W:
			return N;
		}

		throw new AssertionError("Unknown direction: " + this);
	}

}


package com.nasa.rovers.data;

/*
 * Encapsulation for (x,y) coordinates
 * Needed because they are everywhere.
 */
public class XY
{

	private int x = 0;
	private int y = 0;

	public XY() {};

	public XY(int x, int y)
	{
		this.x=x;
		this.y=y;
	}

	public XY(XY xy)
	{
		this.x = xy.x;
		this.y = xy.y;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public void add(XY xy)
	{
		this.x = this.x + xy.getX();
		this.y = this.y + xy.getY();

	}

	public void scale(int m)
	{
		this.x *= m;
		this.y *= m;
	}

	public String toString()
	{
		return "(" + x + "," + y + ")";
	}

	public static XY add(XY from, XY to)
	{
		XY result = new XY(from);
		result.add(to);
		return result;
	}

}


package com.nasa.rovers.data;

import java.util.ArrayList;
import java.util.List;

//Define the boundaries of the surface
public class Map {

	private XY left  = new XY(0,0);
	private XY right = left;

	private int maxX = right.getX();
	private int maxY = right.getY();

	public int getMaxX() {
		return maxX;
	}

	public int getMaxY() {
		return maxY;
	}

    public Map() {};

	public Map(XY right)
	{
		this.right = new XY(right);

		maxX = right.getX();
		maxY = right.getY();
	}

	public void setBoundary(XY right)
	{
		this.right = new XY(right);
		maxX = right.getX();
		maxY = right.getY();
	}

	/*
	 * Check if the coordinates are on the map or outside
	 */
	public boolean onMap(XY xy)
	{
		if ((0 <= xy.getX() && xy.getX() <= maxX) &&
		   (0 <= xy.getY() && xy.getY() <= maxY))
			return true;
		else
			return false;
	}

}


package com.nasa.rovers.data;

public class Rover
{

	private XY xy;
	private DIR dir;

	private boolean debug = Boolean.getBoolean("debug");

	public Rover() {};

	public Rover(int x, int y, DIR d)
	{
		xy = new XY(x,y);
		this.dir = d;
	}

	public XY getXY() {
		return xy;
	}

	public void setXY(XY xy) {
		this.xy = xy;
	}

	public DIR getDir() {
		return dir;
	}

	public void setDir(DIR dir) {
		this.dir = dir;
	}

	public void move()
	{
		xy.add(dir.getXY());
	}

	public void moveBy(int m)
	{
		XY moveBy = new XY(dir.getXY());
		moveBy.scale(m);
		xy.add(moveBy);
	}

	public void leftSpin()
	{
		this.dir = this.dir.left();
	}

	public void rightSpin()
	{
		this.dir = this.dir.right();
	}

    /*
     * Heart of the system
     * Navigates based on plan (string of instruction characters) and
     * a map that defines the boundaries
     * So...
     * The rover knows where it is going
     *
     * TODO implement logic to avoid collision with other rovers
     */
	public void navigate(String plan, Map map)
	{
		//must check if boundaries are crossed
		//rover must have knowledge of planet (map)

		char[] instructions = plan.toCharArray();
		char ins = 0;

		int moveX = 0;
		int moveY = 0;
		XY moveTo = null;

		print("start");
		print(this);

		for (int i =0; i < instructions.length; i++)
		{
			print(instructions[i]);
			switch (instructions[i])
			{
			case 'L' : leftSpin();break;
			case 'R' : rightSpin(); break;
			case 'M' :
				//check if it's a valid move
				//a move is invalid if it takes the rover beyond the boundary

				//find out what the final destination will be
				moveTo = XY.add(this.xy, this.dir.getXY());

				if (map.onMap(moveTo))
				{
					//safe move as it doesn't take us out of the boundaries
					move();
				}
				else
				{
					//don't move
					//should we throw an exception?
					print("invalid move");
				}
				break;

			default: //do nothing; we just ignore all crappy instructions.
			}

			print(this);
		}

		System.out.println(this);
		print("end");
	}

	public String toString()
	{
		return xy.toString() + "  " + dir.toString();
	}

	private void print(Object o)
	{
		if (debug) System.out.println(o);
	}
}


package com.nasa.rovers.control;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import com.nasa.rovers.data.DIR;
import com.nasa.rovers.data.Map;
import com.nasa.rovers.data.Rover;
import com.nasa.rovers.data.XY;

public class Navigator
{

	public static void main(String[] args)
	{
		System.exit(run(args));
	}

	public static int run(String[] args)
	{
		System.out.println("---Begin Program");

		try
		{

			Map map = new Map();

			String fileName = args[0]; //do basic authentication later

			//read input data
			BufferedReader f = new BufferedReader(new FileReader(fileName));
		    String line = null;

		    //read first line
		    line = f.readLine();
		    if (line != null)
		    {
		    	//top right coordinates
		    	line = line.trim();
		    	int x = Integer.parseInt(line.substring(0,1));
		    	int y = Integer.parseInt(line.substring(2));
		    	map.setBoundary(new XY(x,y));
		    }

		    int i = 1;
		    Rover r = null;
		    //TODO should we maintain a list of rovers
		    while (( line = f.readLine()) != null)
		    {
		    	line = line.trim();
		    	if (i % 2 != 0)
		    	{
		    		// first line of input for rover
			    	int x = Integer.parseInt(line.substring(0,1));
			    	int y = Integer.parseInt(line.substring(2,3));

			    	char d = line.charAt(4);
			    	switch (d)
			    	{
			    	case 'N': r = new Rover(x,y, DIR.N);break;
			    	case 'E': r = new Rover(x,y, DIR.E);break;
			    	case 'S': r = new Rover(x,y, DIR.S);break;
			    	case 'W': r = new Rover(x,y, DIR.W);break;
			    	default : r = new Rover(x,y, DIR.N);break; //create a new Rover anyway
			    	}

		    	}
		    	else
		    	{
		    		// second line of input
		    	    //TODO implement logic to avoid collision with other rovers

		    		r.navigate(line, map);
		    	}

		    	i++;

		    }

		}
		catch(Exception e)
		{
			e.printStackTrace();
			return (-1);
		}

		System.out.println("---End Program");
		return (0);
	}

}

SQL – Nuances of IsNumeric() function

I love complex sql queries.

Today I was working on generating a report that called for a join between two tables which looked as those below. The fist table (company) contained approx.80K records and the second (company_lookup) contained approx. 20K records.


.--------------------------------.
|             Company            |
+----+------------------+--------+
| Id | Name             | Ticker |
+----+------------------+--------+
|  1 | Dummy company 1  | IBM    |
|  2 | Dummy company 2  |   0002 |
|  3 | Dummy company 3  | 46ABD  |
|  4 | Dummy company 4  | NAN    |
|  5 | Dummy company 5  | BP     |
|  6 | Dummy company 6  | BP     |
|  7 | Dummy company 7  | MSFT   |
|  8 | Dummy company 8  | E      |
|  9 | Dummy company 9  | GOOG   |
| 10 | Dummy company 10 | SUN    |
| 11 | Dummy company 11 |   0046 |
‘----+------------------+--------’


.---------------------------.
|       Company_Lookup      |
+------------------+--------+
| Name             | Ticker |
+------------------+--------+
| Dummy company 1  | IBM    |
| Dummy company 2  |      2 |
| Dummy company 3  | 46ABD  |
| Dummy company 4  | NAN    |
| Dummy company 5  | BP     |
| Dummy company 7  | MSFT   |
| Dummy company 8  | E      |
| Dummy company 9  | GOOG   |
| Dummy company 11 |     46 |
‘------------------+--------’

As there can be multiple records with the same ticker, I tried writing a simple join on ticker and name.

select * from company a, company_lookup b
where a.ticker = b.ticker and
         a.name = b.name

However, notice the following rows


.--------------------------------.
|             Company            |
+----+------------------+--------+
| Id | Name             | Ticker |
+----+------------------+--------+
|  1 | Dummy company 1  | IBM    |
|  2 | Dummy company 2  |   0002 |  <-----
|  3 | Dummy company 3  | 46ABD  |
|  4 | Dummy company 4  | NAN    |
|  5 | Dummy company 5  | BP     |
|  6 | Dummy company 6  | BP     |
|  7 | Dummy company 7  | MSFT   |
|  8 | Dummy company 8  | E      |
|  9 | Dummy company 9  | GOOG   |
| 10 | Dummy company 10 | SUN    |
| 11 | Dummy company 11 |   0046 |  <-----
‘----+------------------+--------’

.---------------------------.
|       Company_Lookup      |
+------------------+--------+
| Name             | Ticker |
+------------------+--------+
| Dummy company 1  | IBM    |
| Dummy company 2  |      2 |   <-----
| Dummy company 3  | 46ABD  |
| Dummy company 4  | NAN    |
| Dummy company 5  | BP     |
| Dummy company 7  | MSFT   |
| Dummy company 8  | E      |
| Dummy company 9  | GOOG   |
| Dummy company 11 |     46 |   <-----
‘------------------+--------’

Essentially, the ticker is same but is stored differently in the two tables (although the data type is varchar in both tables). A simple join doesn’t work as it fails to compare, for ex., ’2′ with ’0002′. I can’t blindly convert the column to numeric either since the column also stores alphanumeric values. After a lot of tinkering, I managed to write a rather ugly query using ‘isnumeric’ and ‘case’ clause.

select b.*, a.* from company a, company_lookup b
where
case isnumeric(a.ticker)
    when 0 then a.ticker
    when 1 then cast(cast(a.ticker as int) as varchar(10))  --stripping leading zeros, if any, by converting to int and then back to varchar
end = b.ticker
and
b.name = a.name

My intention was to do a numeric conversion only if the tickers are numeric. To my dismay, this query didn’t work either and kept giving me a ‘Can’t convert NaN to varchar’ error. Upon debugging further, it turned out that the isNumeric() function treats ‘NaN’, ‘E’, ’31E’ etc. as numeric. However, the cast/convert idn’t able to convert ‘NAN’ to a valid numeric value.

This issue has also been touched upon in the following stackoverflow query: http://stackoverflow.com/questions/570075/sql-isnumeric-returns-true-but-sql-reports-conversion-failed

So, finally I had to modify the query to filter out such values as follows.

select b.*, a.* from company a, company_lookup b
where
case a.ticker
    when 'NAN' then 'NAN'
    when 'E' then 'E'
else
    case isnumeric(a.ticker)
        when 0 then a.ticker
        when 1 then cast(cast(a.ticker as int) as varchar(10))
    end
end = b.ticker
and
b.name = a.name

P.S. – By the way, the above tables have been generated using the Text::ASCIITable perl module. Also, WordPress has a habit of converting double dashes to some special character so I had to edit the HTML of this blog entry to replace all dashes with ampersand hash045;

Java Thread Programming by Paul Hyde

I have just finished reading “Java Thread Programming” by Paul Hyde. I have never gotten my hands dirty with concurrent programming in java and it is a matter of great consternation and distress to me every time I need to write multithreaded code or go for a job interview (For some reasons, multithreading seems to be a favorite trivia topic with interviewers). I know the basics but not enough to call myself even intermediately skilled in it. Not that I haven’t tried. But every time I picked up a book on multithreading, I found myself helplessly entangled in the confusing Java Swing examples the author had used to explain esoteric concurrency concepts. I dislike Swing. I have never used it. And I could never find a single book that explained multithreading with simple server side code snippets alluding never or rarely to Swing examples. Until I found the aforementioned book by Paul Hyde. This is the first multithreading book that I thoroughly enjoyed for its simple, easy to understand language.

The book is divided into two parts. Part I contains ten short yet lucidly written chapters covering the basic concepts from how to create a thread to more complex topics like thread intercommunication. Part II of the book is dedicated to useful tips and tricks like thread pooling etc.

Paul has used simple code examples in most of the places and has kept Swing/AWT examples to a minimum. Instead of peppering Swing code everywhere, he has written a separate chapter explaining how multithreading can be used in Java GUI programming. Personally I found this to be the best introductory book on Java multithreading. It is the unofficial “Head First…” book of java multithreading. You can download the source code from the book’s official web page.

This book was published in 1999 and therefore does not cover the new concurrent APIs introduced in Java 5. But if you scratch your head every time you come across a synchronization block, this is the book for you. Specially if you, like me, get confused and lost in the labyrinthian Swing examples that most books on this subject contain.

Thanks, Paul. I now feel well equipped to start hacking concurrent programming.

Lenovo Thinkpad T400

After a lot of research to find a good programmer’s laptop, I finally bought a new Lenovo Thinkpad T400 to give a boost to my programming efforts. This is my first personal laptop. Although I have still not fully recovered from the hole it burnt in my pocket, I am very excited about the flexibility it provides. Last week, I took it to the National library and spent some quality time there practicing programming. Just like any creative pursuit, programming requires its practitioners to work in an environment that allows their creative juices to flow. As for me, the ideal environment for hacking is a busy (but not very noisy) public place in the outdoor. Surprising though it may sound, I really do feel most creative when there are lots of people around me. So my plan is to visit all the cafes in the city and make a list of preferred locations ideal for working.

In order to discipline myself into doing some real work and not simply wasting time browsing the net, I have purposely not enabled online mobile broadband. This compels me to plan my work in advance since I am forced to download all the reading material, software, source code etc. that I need before stepping out of the house.

Traits of a good programmer

In his latest blog, Peter Bohm has written a review of Chad Fowler’s “The Passionate Programmer” and has basically summarized a few qualities that a programmer should have. I think that analytical and programming skills apart, it is the amount of “passion” a programmer has that makes him/her a good programmer.

One of Peter’s arguments is about how good programmers never stop to learn. I couldn’t agree more. If there is a one key difference I have seen between good and average programmers, it’s their passion for learning. Good programmers see learning as an investment and spend a lot of time upgrading their skills and improving their knowledge. They read, browse, blog, network, join forums, attend conferences and above all get into the trenches try out new things whenever they can.

Good developers hate bad code. I was reading “Secrets of the Rockstar programmers: riding the IT crest” by Ed Burns. This book is a collection of interviews of some of the “celebrities” from the IT world. One of the traits that sprung up as a common characteristic among most programmers interviewed in the book was their passion for continuously improving the systems they were working on. In the interview with Kohsuke Kawaguchi, the creator of continuous integration tool Hudson, he says that he wrote Hudson because he wasn’t happy with CruiseControl (and other CI tools). Good programmers will feel very uncomfortable on seeing poor code or existing bugs and would want to fix them. They will cringe every time they are forced to put in a tactical solution/bug fix for the benefit of time and will always go back and put a better fix whenever they can.

In my opinion, good programmers are lazy. They hate doing manual tasks and therefore invent creative ways to automate mundane jobs. One of my friends recently spent several hours converting a manual build task into a fully automated one-click build and managed to reduce her effort from several hours per build to almost zero. She was almost delirious with joy on seeing all the time she saved. As Yukihiro Matsumoto, the creator of Ruby once said, “Be lazy. Machines should serve human being. Often programmers serve machines unconsciously. Let machines serve you. Do everything you can to make you lazy”.

I have also often observed that many, if not all, smart programmers are tool junkies. Nothing excites them more than tinkering with new tools, installing new plugins or customizing their development environments. I am not sure if there is a pattern here but the child like pleasure we programmers derive from these activities make our work all the more interesting.

Another interesting characteristic of good developers is that they are not scared to step out of their comfort zones. For example, they share their code with others and welcome feedback. It takes a lot of courage to show your code to the rest of the world. Good programmers work hard to swallow their pride and overcome their fear and shyness of letting other people review their work. For the same reason, they enjoy company of programmers who are smarter than them. This gives them an opportunity to observe and learn from others. Joel Spolsky once said in his podcast, “if you’re not doing a few things where you’re failing a little, you’re probably not trying hard enough. I say if everyone likes you, you probably aren’t doing anything interesting.”

Finally, the one quality that I hold in very high esteem is humility. Good programmers are humble. They don’t mind admitting that they don’t know something. While it is easier said than done, I have seen that the biggest disservice we do to ourselves is by being egoistic and snobbish about our knowledge and programming skills. You end up losing by shutting off other people if you are continuously trying to prove the superiority of your programming skills to others. Smart programmers don’t do that. They know that there is nothing wrong in saying “I don’t know”, nor do they harshly judge another team mate who says that. There is a lot that can be learnt from each other if only we let our guards down and stop being defensive about our skills or lack thereof.

Tagged ,

Main method not supported in scala companion object

I was working on some practice problems from the Ninety-Nine Scala Problems website when I stumbled across an interesting behavior.

I wrote a dummy class and a main method in its companion object.

package arithmetic {

    class S99Int(val start: Int) {
      import S99Int._

      def hello = println("hello")
    }

    object S99Int {

      def main(args: Array[String]) :Unit = {
          println("hello world")
      }

    }

}

To my surprise, I got a NoSuchMethodError: main from the compiler.

Turns out that this is not supported in Scala (as of now). Companion objects can’t have a main() method. There are some esoteric explanations available on the Scala mailing list for this behavior.

Follow

Get every new post delivered to your Inbox.