Wednesday, November 12, 2008

Programming Problem 1 - Train Times


The Problem


City transportation planners are developing a light rail transit system to carry commuters between the suburbs and the downtown area. Part of their task includes scheduling trains on different routes between the outermost stations and the metro center hub.

Part of the planning process consists of a simple simulation of train travel. A simulation consists of a series of scenarios in which two trains, one starting at the metro center and one starting at the outermost station of the same route, travel toward each other along the route. The transportation planners want to find out where and when the two trains meet. You are to write a program to determine those results.

This model of train travel is necessarily simplified. All scenarios are based on the following assumptions:

  1. All trains spend a fixed amount of time at each station.
  2. All trains accelerate and decelerate at the same constant rate. All trains have the same maximum possible velocity.
  3. When a train leaves a station, it accelerates (at a constant rate) until it reaches its maximum velocity. It remains at that maximum velocity until it begins to decelerate (at the same constant rate) as it approaches the next station. Trains leave stations with an initial velocity of zero (0.0) and they arrive at stations with terminal velocity zero. Adjacent stations on each route are far enough apart to allow a train to accelerate to its maximum velocity before beginning to decelerate.
  4. Both trains in each scenario make their initial departure at the same time.
  5. There are at most 31 stations along any route.
  6. The meeting time of both trains will never be at the departure of one of the trains from a station.

Input

All input values are real numbers. Data for each scenario are in the following format:



d1 d2...dn 0.0

For a single route, the list of distances (in miles - there are 5,280 feet in a mile) from each station to the metro centre hub, separated by one or more spaces. Stations are listed in ascending order, starting with the station closest to the metro centre hub (station 1) and continuing to the outermost station. All distances are greater than zero. The list is terminated by the sentinel value 0.0.


v

The maximum train velocity, in feet/minute.

s

The constant train acceleration rate in feet/minute2.

m

The number of minutes a train stays in a station.

The series of runs is terminated by a data set which begins with the number -1.0.


Output

For each scenario, the program should determine the following:

  1. The number of the scenario (numbered consecutively, starting with Scenario #1).
  2. The time when the two trains meet in terms of minutes from starting time. All times must be displayed to one decimal place. Also, if the trains meet in a station, the station number where they meet.
  3. The distance in miles between the metro centre hub and the place where the two trains meet. Distances must be displayed to three decimal places.

Sample Input

15.0 0.0
5280.0
10560.0
5.0
3.5 7.0 0.0
5280.0
10560.0
2.0
3.4 7.0 0.0
5280.0
10560.0
2.0
-1.0



Sample output



Scenario #1:

Meeting time: 7.8 minutes

Meeting distance: 7.500 miles from metro centre hub



Scenario #2:

Meeting time: 4.0 minutes

Meeting distance: 3.500 miles from metro centre hub, in station 1



Scenario #3:

Meeting time: 4.1 minutes

Meeting distance: 3.400 miles from metro centre hub, in station 1

Tuesday, November 11, 2008

SpringSource acquires G2One

SpringSource acquires G2One - the company behind Groovy and Grails. I hope it augurs well for Groovy and helps in more shops adopting it for commercial development.

Wednesday, September 3, 2008

Language Remix

I stumbled across an interesting paper on polyglot programming here.

I am convinced more than ever that in the war of programming languages, it is impossible for one language to outshine others. So should we start looking at things differently? Should we move our focus away from trying to pick a winner?

A few trends are worth taking note of.

- Developers are not scared anymore to experiment with different programming languages and styles. While they still have favourites, they are increasingly using the most suitable language or tool for a given job. This is a welcome change from the days when we were 'shoehorning' every solution into one tool or technology.

- IDEs allow one to seamlessly integrate different tools and technologies into one platform.

- Virtual machines have brought the languages closer to each other in such a way that the language has become merely a tool for expression. Code written in one or mixed languages produces the same byte code so the run time environment has become language agnostic.

These trends suggest that the time is ripe to try out a polyglot approach to development and see if it has any real benefits or not. The paper above makes a convincing argument in favor of polyglot programming.


Friday, August 29, 2008

Fluent Interfaces

A Fluent Interface is a design construct that makes your interfaces read like natural language instructions.

I kinda like how a little refactoring of method signatures can make an interface much more "interesting", shall we say ? The idea is to make the interface read more like English. So, for ex., instead of

//<>
Aggregator a = new Aggregator();
List l = dao.getfeedFromEurope();
List l1 = dao.getfeedFromAPAC();
List l2 = dao.getfeedFromAmericas();
a.aggregate(l);
a.aggregate(l1);
a.aggregate(l2);
a.setFilterPolicy(FilterPolicy.NonPayingCountries);
a.filter();
List l3 = a.getFeeds();
...


you'll write

Aggregator a = new Aggregator();
...
List l3 = a.aggregate(l).and_aggregate(l1).and_aggregate(l2).filterWith(FilterPolicy.NonPayingCountries);



Neat, isn't it? The Aggregate class methods are self-referential. In the above example, and_aggregate() just calls aggregate() internally. But the goal here is to improve readability of the interface. Of course, like everything else, fluent interfaces can be overused or misused. You can, for ex. make a very verbose interface or worse make all the interfaces fluent.

I had a difficult time explaining this construct to the code reviewers last time. I guess it takes some time getting used to this style.

The first class

The snippet below prints the first class in the stacktrace. Might be useful for logging in some situations.

public vid test ()
{
Throwable th = new Throwable();
stackTraceElement[] ste = th.getStackTrace();
System.out.println(ste[ste.length -1].getClassName());
}

I live inside Eclipse

I have a fetish for Eclipse plugins. I use
  1. Mylyn for tasks management. Super-cool productivity plugin.
  2. Database Development Plugin. Replaces crappy DBArtisan on my desktop. Lets me perform basic database operations easily. Lightweight and super-fast.
  3. Azzuri clay Database Modelling plugin to create ER diagrams and generate DDLs from them; a basic feature that Micro$oft decided not to provide in Visio Professional edition.
  4. Beyond-CVS to integrate beyond-compare (my favourite comparison tool) with Eclipse.
  5. QuickREx for those esoteric regular expressions. I don't miss RegEx buddy now.
  6. Remote System Explorer for connecting to linux machines and running telnet/ssh/ftp shells.
  7. Eclipse web browser. Limited in features but helps during basic debugging or investigation when I want to search for an inexplicable ibatis error or how to convert dates to varchar and vice versa in the database (i always keep forgetting that). Also for keeping an eye on the latest on reddit :-). Wish it offered tabbed browsing.

My wish List

  1. A Mind map plugin to let me gather my thoughts.
  2. More powerful text editor. I use block-editing heavily.
  3. A plugin for MS Outlook that lets me attach emails to Mylyn tasks.
  4. A plugin for MS Excel
  5. A powerful desktop indexing and search plugin.

Amen.

Wednesday, August 27, 2008

Random Thoughts

Xtreme Programming is not a synonym for planning-less programming. It is not a euphemism that poor management can hide behind.

Xtreme is an ideological change and should be a conscious decision.

Ternary logic in SQL

A fellow colleague ran into a strange problem recently with a "not-in" SQL query. There were two tables, say A and B and we weretrying to get all values of a column from table A that did not exist in Table B.

Here's a result of the queries we ran.

select count(distinct column1) from A
-----17567 records

select count(distinct column1) from B
-----10234 records

So to get the values of column1 that are in A but not in B, we tried,

select distinct column1 from A where column1 not in (select distinct column1 from B)
-----0 records


Funnily, the query returned no records. Something was wrong.

After breaking our heads for several hours on this problem, the culprit turned out to be some null values in table B.

We changed the above query as follows to make it work.

select distinct column1 from A where column1 not in (select distinct column1 from B where column1 is not null)
-----~8000 records


SQL implements what is known as ternary logic for handling NULLs. I found a lucid explanation of this problem here.

Thursday, July 24, 2008

My experience with unit testing

I am not new to programming but have had bad programming habits for too long. "Enough is enough", I said to myself one day and decided to use a test-first approach for the next project.

Here's what I experienced.

1. Although I created the test cases before writing the classes, I didn't keep up with the policy for long. I found it a little distracting to think of and write a test case before any change to my code. The result was that soon my test cases were totally out of sync with the code.

2. It is difficult to be disciplined enough to keep test cases up to date specially when you are working with tight deadlines. Effort estimation must take into account this fact.

3. I had to continuously refactor my code to make it more testable. Writing test cases turned out to be a great way to write well formed APIs and good code in general. I had to make several modifications to my initial design to allow dependency injection. Moral of the story - automated unit tests can't be implemented as an after thought.

4. I found it difficult to test private methods and had to change their visibility to test them.

5. I found it difficult to automate everything. There were times when I just wanted to print the values of a hashmap and inspect manually. I found it too time consuming to completely automate the testing in such cases. Perhaps it's a case of old habits. But I realized how much of our testing is based on manually inspecting the results. It is difficult to break this habit and to learn to rely on automated test results.

6. Mocks are confusing (jmock) but very very helpful.

7. Seeing the unit tests run successfully didn't give me much confidence except for the first time when I ran them with fresh code. I can think of several reasons for it. Firstly, as I mentioned before, manually verifying the results of a testcase gives one a confidence that's difficult to achieve by running automated tests. There is something reassuring about seeing the results with your own eyes. Secondly, my test cases were not comprehensive enough to test full functionality. So after some time, I didn't see much value being added by running these tests. And lastly, I was coding for a database intensive CRUD application; my code was heavily dependent on file i/o and database access, both of which needed extensive integration testing. After a while, the unit tests were rendered completely useless and I was hardly running them.

8. There is only so much that unit tests can achieve. Most of the bugs in my code were caught during integration testing. But I must admit that at least some of these could have been caught during unit testing if I had better unit tests.

10. There should be a set of integration tests that check essential functionality. These tests may not run during the continuous build but must run during the nightly build.

Thursday, July 10, 2008

Java Code Review Tools

Today I gave a presentation to the team on java code review tools. I covered 2 tools in detail, PMD and Jupiter. while I was talking about them, I realized that both the tools can do with some improvements.

PMD
  • Improved filtering to allow me to run the tool on selective files.

Jupiter

  • Must let me view defects data in a more user friendly way. I want to be able to view all defects and then aply filters on them. The functionality is there but not in the way I want it.
  • Must allow me to generate reports on defects metrics.
  • The workflow is confusing (why should i choose a reviewer in the 'rework' phase ?). The process should be simplified.
  • There should be a filtering icon in each view.

Note to self: Explore option of adding these features yourself.

Wednesday, July 9, 2008

Use groovy as your scratchpad during java development

How many times have you wanted to test out a small piece of java logic before implementing it in your code?

In the past, whenever I did something 'smart' with Dates or Calendar or Strings or StringBuffers, I wrote a small java program (often called Test.java) to test the logic I had in mind. The process, as we all know, is slow to do in java because of Java's write-compile-run cycle. Even if you are using the most sophisticated IDEs, it is still a chore.

Enter Groovy

Groovy is a dynamic language written for the Java virtual machine. You can use Java syntax in a perl like language. While Groovy is a full featured new-age programming language (I am having lots of fun learning it by the way), I use it more often to test out bits of java logic before I want to introduce it into my code.

The other day, I wanted to check how GrgorianCalendar's firstDayOfWeek is affected by the Locale. Normally, I would have written this in Test.java but not any more. I opened the Groovy console and typed in the code snippet I wanted to test. I didn't have to create any class or import anything (java.unit.* is imported by default). There was no manual compilation needed (because it happens under the hood). All I had to do was type my code and press Ctrl-R. Presto. The output was displayed in the output screen. I changed the Locale in the constructor and again pressed Ctrl-R to re-run. No recompilation, nothing.






I recommend this tool to every serious java developer as a productivity tool. Of course once you get hooked to Groovy as a programming language, I am sure you'll find it as interesting as I do.



Working on maintenance projects

first posted on personal blog on Monday, November 13, 2006

It is difficult to understand why people have such an anathema towards maintenance projects. I often come across programmers whose enthusiasm takes a nosedive every time they are asked to work in a maintenance project.

I think, it is an attitude problem more than anything else.


Most projects that I have worked on have been either maintenance (bug fixing) or enhancement projects. If one has the right kind of attitude, working on a bug fixing project can be a very fulfilling experience.


What attitude, you ask? I suggest the following.

All bugs can be replicated and fixed.

All bugs can be detected, analyzed and fixed. If you can't replicate it, don't give up. Check that you are following the right steps. Make sure that your assumptions are correct. Investigate and find out more about the conditions in which the bug was reported.

The software doesn't control you. You control it.

A program does what it is told to do. So even the seemingly erratic/intermittent behavior will have some logical explanation. Don't be afraid of ripping open the class files using a decompiler if needed. As a bug fixer, you are like a private detective. You have access to all areas of the application and you must go through all the code if needed. I once saw a colleague going through the decompiled code of log4j. He was apparently getting some trouble with logging and wanted to understand log4j code to see what was wrong.

...And it's all small stuff.

Don't be smug. Don't ignore trivial causes. Are you running the right build? Are you connected to the correct database? Are you using the right version of code? I can't begin to count the number of occasions where I have done this mistake or have seen someone else doing it. It's like forgetting the attachments in your emails. No matter how experienced you are, you will still catch yourself doing silly mistakes every once in a while.


Be humble.

As I said before, it's software you are working on. Software will have bugs. Even after you fix them, there will still be some more. So don't take it personally if someone points out a bug in your code or if the fix that you provide doesn't work. Be humble and accept your mistakes. I hate to see programmers getting defensive about their code or design.


Pretend that the "Go to" guys don't exist.

Do not get into the habit of raising an SOS every time you see a NullPointerException. There will always be a few star programmers in your project but it irritates them beyond belief if you go asking for their help for every stupid exception that your program throws. Try to fix the problem yourself first. That's what separates good programmers from lazy nincompoops.


Do your homework before seeking help.

In other words RTFM and save the logs. If you do need to take help, do your homework first. Read the specs, do some research, google the error message and find out if someone has already faced it before. Post your query on the forums. And for God's sake, save the logs before calling someone for help.

Be lazy. Automate!!

I learnt this very early. Best programmers are creatively lazy. Automate. Find out tools that can help reduce your time. In short, be a smart coder. If you are working on legacy code, you will need powerful tools and good skills to search the codebase. Learn regular expressions and use them in your searches.


Think out of the box.

People have been known to recover from the dreadful "rm-rf" that someone accidentally typed on a Unix box. The point is, no problem is big enough that it can't be solved. There must exist a solution. And you should find it. Think laterally if needed.


Always get the big picture. Don't forget to ask the "whys".

This is very important. There is a reason why everything works the way it does. There is a reason why your client chose Java over C++ (or vice versa) and there is a reason again in why they chose to not use entity beans. Be inquisitive. Question everything. Get a bigger perspective.It will help you come up with better solutions to problems that you are working on.