IMS transport - Web application

In the year 2018, while I was working with my father in his cargo auto-transport firm, we decided to create a Web site that would increase our visibility on the Internet, and hopefully increase the number of transport jobs we currently had. We decided to make it simple and interactive, to hopefully differentiate us a bit from other firms in the same business. The decision in terms of interactivity was to include a map where a potential customer could draw the desired route and have the application print out the approximate price. Maybe foolish, as this could potentially be a generator of constant arguing with customers, but we decided to go with it anyway. The name was “Ima me svuda” (IMS).

My friend and I were learning Clojure and ClojureScript at the time, so we immediately choose them as our languages for the back-end and front-end, respectively. For the server-side framework, we choose Duct which was popular at the time. The server needed to calculate the potential prices and one of the components was the travel distance. The Google Maps Road API, specifically the Distance Matrix API was perfect for the job. Distance Matrix API calculates the distance from one point on the globe to another by taking the shortest, available roads into the calculation.

For the front-end, for the map specifically, we chose OpenLayers, which conveniently had a package in the CLJSJS project.

The auto-transport firm is now defunct, so the Web application is no longer active, but during the production time it managed to generate some traction and it even paid for itself during one period.

You can view the source here. The overall code quality is not good.

The development and maintenance of this application was an interesting ride, and we had a few obstacles to overcome.

Generating a price

There were 3 cases of price calculation that needed to be considered. Since the firm was based in Belgrade, the first case was calculating the price for any transport within the city. The second case was calculating the price for transport outside Belgrade anywhere in Serbia, and the third price was for outside the borders of the country.

Statistically, most of the jobs within the city are short in distance, and applying any calculation on these values will result in very dubious prices. The decision was to return a fixed price for any transport within the city.

Similarly, we wanted the routes outside of the country to return a constant response because transporting cargo over the border has its difficulties. In the end, if the customer requested a price for a route outside the country, a message was displayed informing them to contact us for a real price and more information.

All that was left is to produce a price for transport within the country. The Google Road API returned a distance for the inputted route in meters, so we had a basis for our price. The end price was calculated by multiplying the projected route distance (in kilometers) with the unit price per kilometer (which was 30 RSD at the time) and adding a fixed price part that represented costs like getting out of Belgrade, and toll prices. The resulting price was displayed to the customer alongside the message to contact us for confirmation.

Drawing a valid road on the map

Drawing a road on the map had two problems that needed to be solved. The first one is the actual displaying of the map and route, and the second one is distinguishing routes in Belgrade, in Serbia, and out of the country.

The drawing part was easy thanks to OpenLayers (OL) being so well structured and having a package in the CLJSJS project. With OL we handled the displaying of a map that had a fixed zoom and focused on Serbia. It came with basic navigation and info commands out-of-the-box. However, it did not have a snap-to-road feature that would, for example, enable the customer to draw a straight line between two points and the map would display the path between them using valid roads. This proved to be quite a difficult task, and there are some solutions for it (like Google Snap to roads API), but we decided to not pursue it. Instead, we displayed the straight lines as customers draw them, but informed the customer that the valid, shortest road was used for calculation (as Google roads API stated it did).

We approached the problem of distinguishing the routes by defining two polygons on the map (only in coordinates, not actually drawing them). The first polygon’s edges went alongside the borders of the city of Belgrade, while the second one went alongside to borders of Serbia. When the customer draws the route we check if all points belong to the first Belgrade polygon and display the price. If it doesn’t belong to the Belgrade polygon then we check if it belongs to the Serbia polygon, and ultimately if it doesn’t belong to any polygon we know that the route goes beyond the borders of the country. For this calculation, we implemented the Winding number algorithm, but the version where intersections are counted (like here).

Hosting on Heroku and DNS acrobatics

We decided to host on Heroku since it was the only platform that could host a Clojure application that we were familiar with. At one point we purchased the domain name from a local DNS provider which proved to be a mistake. The DNS provider did not have any advanced DNS configuration that we needed. Heroku platform hosts the applications on a auto-generated sub-domain, and that requires that our DNS zone configuration points our root domain name to this URL which was impossible in the provider’s configuration panel. DNS providers like GoDaddy can configure this easily.

Luckily, we found a solution. It appears that we were not the only ones with this problem. Service offered domain redirection using basic DNS configuration. And, it is free! We quickly set up the configuration like in the documentation and the application was up and redirected successfully with normal response times.