Artem Kholodenko
Engineering @ BuildZoom
4 min readSep 24, 2015

--

On AngularJS, External Components, and Abstraction

The Industrial Revolution brought with it the concept of division of labor. Having specialists in all areas of production led to faster production with higher quality. The concept applies well to software development and has led to roles like front-end, back-end, and dev-ops engineer. Frequently — especially for start-ups — it doesn’t make sense to develop certain technology in-house. Companies look to external experts to fill in the specialized gaps. Engineers use AWS for cloud computing, MixPanel for engagement analytic, Google Maps APIs for location services, Optimizely for A/B testing, Twilio for SMS messaging, New Relic for application performance management, and many more. As most modern software applications heavily rely on third-party services, it’s critical to properly architect in-house applications to abstract and modularize external resources.

At BuildZoom, we rely on Google Map APIs to visualize projects in the construction industry. Building permit data is often incomplete and we leverage the geocoding service to flesh out the location details.

This is a basic example of using the geocoding service (via the Google Maps JavaScript API):

var geocoder = new google.maps.Geocoder();

geocoder.geocode( { 'address': '501 Folsom St., SF' }, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
console.log(results); // TODO: replace with a success callback
// results OBJECT
// {
// "address_components" : [
// {
// "long_name" : "501",
// "short_name" : "501",
// "types" : [ "street_number" ]
// },
// {
// "long_name" : "Folsom Street",
// "short_name" : "Folsom St",
// "types" : [ "route" ]
// },
// {
// "long_name" : "South Beach",
// "short_name" : "South Beach",
// "types" : [ "neighborhood", "political" ]
// },
// {
// "long_name" : "San Francisco",
// "short_name" : "SF",
// "types" : [ "locality", "political" ]
// },
// {
// "long_name" : "San Francisco County",
// "short_name" : "San Francisco County",
// "types" : [ "administrative_area_level_2", "political" ]
// },
// {
// "long_name" : "California",
// "short_name" : "CA",
// "types" : [ "administrative_area_level_1", "political" ]
// },
// {
// "long_name" : "United States",
// "short_name" : "US",
// "types" : [ "country", "political" ]
// },
// {
// "long_name" : "94105",
// "short_name" : "94105",
// "types" : [ "postal_code" ]
// },
// {
// "long_name" : "3175",
// "short_name" : "3175",
// "types" : [ "postal_code_suffix" ]
// }
// ],
// "formatted_address" : "501 Folsom St, San Francisco, CA 94105, USA",
// "geometry" : {
// "location" : {
// "lat" : 37.786958,
// "lng" : -122.394462
// },
// "location_type" : "ROOFTOP",
// "viewport" : {
// "northeast" : {
// "lat" : 37.78830698029149,
// "lng" : -122.3931130197085
// },
// "southwest" : {
// "lat" : 37.7856090197085,
// "lng" : -122.3958109802915
// }
// }
// },
// "partial_match" : true,
// "place_id" : "ChIJY4RvdXuAhYARysWjlVIhXv0",
// "types" : [ "street_address" ]
// }
}
else {
console.log(status); // TODO: replace with a fail callback
}
});

It’s very simple to use, with only a few lines of code. A more detailed set of success and fail callbacks is all that is really needed to get off the ground. Based on the need of a specific feature the callbacks can extract the needed location information (despite the result the service provides being poorly structured). That’s great! Stick this snippet in any feature that has a location provided (user address, project address, property search, contractor search, etc.) and you’re ready to go…for now.

Fast forward a year: Google Maps API code is engrained into many of your core features and your company gets notice that prices are going up 500% and maximum quota is going down 50%. Luckily you find an alternative service. All you need to do is swap out every use of the API code and refactor any logic that was architected around the third-party specs. How can this have been avoided? Abstraction and modularization.

Using AngularJS (or your front-end JavaScript framework of choice), create a module that wraps the functionality of a geocoding API. Create simple methods that will provide the needed result. The internal logic of the methods can be changed to leverage any API.

This is a basic example of using the geocoding AngularJS service we wrote:

geocoderService.findDetails("501 Folsom, SF").then(function (location) {
console.log(location);
// location OBJECT:
// {
// alias: "501-folsom-st-san-francisco-ca-94105-usa",
// city: "San Francisco",
// county: "San Francisco County",
// formatted_address: "501 Folsom St, San Francisco, CA 94105, USA",
// lat: 37.786958,
// lng: -122.39446199999998,
// neighborhood: "South Beach",
// state: "CA",
// street_address: "501 Folsom St",
// street_name: "Folsom St",
// street_number: "501",
// zipcode: "94105"
// }
});

Wrapping third-party services in an additional layer between your core application sets the code up for flexibility of plugging in any service, while maintaining a consistent internal interface and data output. Checkout the details of the AngularJS geocoding service, which wraps the Google Maps API on GitHub.

Originally published at www.buildzoom.com on September 24, 2015.

--

--