I know that you might be tired of reading/hearing about it, and there is enough material on it out there. Still, there are many inconsistencies and misconceptions that might make you fuzzy. So I’ll show you what I see as being the basics and give you good references. If it makes you curious enough, soon I’ll be posting some samples.

Concept

Erick Evans, on his book about DDD, raises an interesting point about the object’s life cycle and reconstituting stored objects when writing about factories:

At some point, most objects get stored in databases or transmitted through a network, and few current database technologies retain the object character of their contents. Most transmission methods flatten an object into an even more limited presentation. Therefore, retrieval requires a potentially complex process of reassembling the parts into a live object.
Eric Evans

He is explaining the importance of factories (as ORMs) to recreate objects as they were before being persisted to the database. He argues that there is a great responsibility for these objects when they reconstitute the previous state of a disposed object as they once were.

Although his idea of object’s life cycle could be considered already flatten on an event-driven perspective. So we could say Most structural data models flatten objects into an even more limited presentation. Due to understanding it better, we should discuss what it means. Consider reading Martin Fowlersarticle about the subject, where he explains his view about event source (ES):

The core idea of event sourcing is that whenever we make a change to the state of a system, we record that state change as an event, and we can confidently rebuild the system state by reprocessing the events at any time in the future. The event store becomes the principal source of truth, and the system state is purely derived from it. For programmers, the best example of this is a version control system. The log of all the commits is the event store and the working copy of the source tree is the system state.
Martin Fowler

In addition to Erick`s view, ES expands the immutability, only covered by Value Objects on DDD, to whole application state, like a shadow. We only append facts to the repository. In spite of changing and deleting objects, we create new events that, when applied, remove or change them from the current state.

Aplication

As good as it sounds, of course, you might not be already pumped to use it. I’ve just described what it is, not why. Why should you care? After all, if you wanna fix something without nails, a hammer is useless.

I’ve questioned myself that years ago. To answer I had to associate with other concepts first, like distributed computing, DDD, functional programming. Now, I have a view of my own, and I hope to help to build yours.

One of its characteristics is traceability/auditability. Natively, you got the ability to trace all domain changes and easily understand how the application is behaving. Even more, you could easily add user information and audite user changes.

Another important feature it provides is an easy reconciliation. So, when things go south between distributed systems, one can simply ask for what happened to others on a period then process all lost messages.

For these reasons, ES should solve many problems like conflict management and desynchronization on microservice applications that shares business flows and IoT/embedded systems that might work off-line.

There is plenty of real-world applications that would leverage this pattern, like:

  • Shipment tracker
  • IoT systems in general
  • Version control systems
  • Banking transactions

Conclusion

To conclude the pros/cons, I will let Greg Young, who has made the concept popular, anwser that:

Pros

Single Event Centric Model
Simplified/Better Testing
Conflict Management

Cons

Harder to sell to an organization
Less known tools/technologies (though you can implement the Event Store in a RDBMS which kind of mitigates this)
Very difficult to migrate a legacy app to
Greg Young

Next steps

I’ve been working with C# for a while now, so I will be posting some sample soon. But keep in mind that, as Vaught Venom wrote in his book Implementing Domain Driven Design, “ES is inherently functional in nature”, and its use on this paradigm would “potentially lead to more concise code that performs optimally”.

Semana passada eu estava procurando uma forma de encontrar a cidade a partir de uma latitude e longitude. Então aqui esta o que eu aprendi.

Circunstâncias

NA realidade eu e meu time tropeamos nesse problema pois estamos utilizando os locais da API do Foursquare, que nem sempre prove essa informação, e quando prove pode estar incorreta. Então eu me debati com algumas soluções não satisfatórias, entre as quais testei as APIs do Geonames, Onpenstreemap e Mapbpx. Finalmente encontrai o serviço beta do Opencage, que utiliza o Towfishes para reverter o geocode.

Eu estou atualmente usando o mapa do Mapbox map para mostrar os locais do Foursquare, e a API do Geoname para fazer o auto complete do mome cidades no nosso formulário de busca. Não deveria ser nada difícil, se não fosse pelo fato de não podermos usar a API do Google, pois a seus termos de uso obrigam o uso do seu mapa.

Desenvolvendo o acesso às APIs

O senário ideal seria utilizar a API do Geoname, pois o serviço é gratuito e nós já estamos usando, então os nos das cidades seriam similares aos utilizados na pesquisa de locais.

Como já havia experimentado antes, os seus resultados não seguem um padrão ao certo, mas testei novamente para ter certeza.

Como alternativa escolhi testar as APIs do Mapbox, na qual já temos conta, e Openstreetmap, que não necessita de conta.

No intuito de desencolver o teste para as APIs, programei um Webapp com Angular utilizando um template do Yeoman.

Implementação

Então eu desenvolvi um serviço que utilizaria todas essa APIs.

Para configurar o serviço, adicionei uma constante para o módulo angular como segue added.

reverseGeocodeModule.constant('GeoAPIConstants', {
    mapBoxId: 'xxxxxx',
    geonameId: 'xxxxxx',
    openCage: 'xxxxxx'
  });

Quando desenvolvi o serviço, usei essas constantes para identificar as configurações de ambiente, então não é preciso ficar procurando per todos arquivos para alterar minhas conde acesso.

Veja o serviços.

Mapbox

A WEB API do Mapbox tem essa chamada para reverter o geocode.

reverseGeocodeModule.service('MapboxService', [ '$http','GeoAPIConstants',
  function($http,GeoAPIConstants){
    var self = this;
    var urls = {};
    urls.geocode = "http://api.tiles.mapbox.com/v3/{0}/geocode/{1},{2}.json";
    self.FindCityReverseGeocode = function(lng, lat){
      var q = $http.get(urls.geocode.format(GeoAPIConstants.mapBoxId,lng,lat));
        return q.then(function(r){
                    return self.extractCityFromGeocodeJSONResult(r.data);
        });
      };
    self.extractCityFromGeocodeJSONResult = function(result){
      if(self.isResultEmpty(result))
        return null;
      return self.searchInMatrixForCity(result);
    };
    self.isResultEmpty = function(result){
      return !result.results || result.results.length === 0;
    }
    self.searchInMatrixForCity = function(result){
      for(var i = 0; i < result.results.length; i++){
        for(var j = 0; j < result.results.length; j++){
          if(result.results[i][j].type == 'city')
            return result.results[i][j];
        }
      }
      return null;
    }
  }]);

Openstreetmap

reverseGeocodeModule.service('OpenstreetmapService', [ '$http',
  function($http){
    var self = this;
    var urls = {};
    urls.geocode = "http://nominatim.openstreetmap.org/reverse?format=json&lat={1}&lon={0}";
    self.FindCityReverseGeocode = function(lng, lat){
            return $http.get(urls.geocode.format(lng,lat));
    };
  }]);

Geonames

reverseGeocodeModule.service('GeonamesService', [ '$http','GeoAPIConstants',
  function($http,GeoAPIConstants){
    var self = this;
    var urls = {};
    urls.reverseGeocode = "http://ws.geonames.org/findNearbyPlaceNameJSON?lat={1}&lng={0}&style=full&username={2}";

    self.FindCityReverseGeocode = function(lng, lat){
            var q = $http.get(urls.reverseGeocode.format(lng,lat,GeoAPIConstants.geonameId));
            return q.then(function(result){
                var listResults = result.data.geonames;
                for(var i = 0; i < listResults.length; i++){
                    if(0<=self.findFeatureClassIndexFor(listResults[i]))
                      return listResults[i];
                }
            });
    };
    self.findFeatureClassIndexFor = function(geolocation){
      var featureClassNameList = geolocation.fclName.split(',');
      return featureClassNameList.indexOf("city");
    };
  }]);

Solução escolhida

Opencage

reverseGeocodeModule.service('OpenCageService', [ '$http','GeoAPIConstants',
  function($http,GeoAPIConstants){
    var self = this;
    var urls = {};
    urls.geocode = "https://api.opencagedata.com/geocode/v1/json?q={1},{0}&pretty=1&key={2}";
    self.FindCityGeoCodeReverse = function(lng, lat){
      if(lng>0)
        lng='+'+lng;
      if(lat>0)
        lat='+'+lat;
      var q = $http.get(urls.geocode.format(lng,lat,GeoAPIConstants.openCage));
        return q.then(function(r){
                    return r.data.results[0].components;
        });
      };
  }]);

Próximos passos

A API escolhida esta rodando em versão beta, então considere esse risco. Para mitigar esse risco, o próximo passo seria testar a solução Twofishes, que opencage utiliza, para avalia-la como alternativa.

Neste jump start vou mostrar como criar diretivas do Angular usando Yeoman.

Mas antes da parte boa, deixe-me introduzir brevemente o Yeoman, ou apenas pule para parte boa.

What’a hell?

Você pode não saber sobre a existência do Yoeman, como eu não conhecia. Nesse caso você deve estar se perguntando “Que m#$%# é essa?”. Yeoman é uma ferramente de scaffolding, que ajuda a desenvolvedores a começar seus projetos, especialmente o tipo web. Ele gera código ordinário, incluindo referências de pacotes bower e npm e scripts de task runners como Grunt e Gulp.

E o queco?

Na realidade é uma solução bem elegante, pois você pode facilmente configurar um projeto com toda uma estrutura, sem ter que ficar copiando código de outros projetos ou reescrever a mesma balela de sempre.

Copy ain't funny

Dessa forma aumenta a sua produtividade e, se usada da forma correta, a qualidade do software ao adicionar ferramentas que você deixaria para traz por “atrasar” o “progresso” do projeto.

Já contém uma coleção de geradores, que cobrem uma boa variedade de soluções. Cada qual requer algumas tarefas usuais ligados ao seu proposito, como testes automatizados, build, watch (livereload), e dependências em comum, como AngularJS, Bootstrap.

No intuito de cobrir essas necessidades, pode gerar referencias para pacotes bower e npm e arquivos Grunt ou Gult para rodar tarefas.

#LetsGetDownToIt

Precisamos de algumas coisas primeiro:

  • Instale NPM, nodejs package manager;
  • E depois o próprio Yeoman.
npm install -g yo

Agora estamos prontos para começar! Precisamos baixar o gerador do Yeoman para diretiva de Angular.

Você pode encontrar geradores pesquisando no npm por por pacotes com o prefixo “generator”, dessa forma:

npm search generator OQueVocêEstaPesquisando

Nessa caso em especifico, vamos precisar procurar a diretiva do angular, então pesquisamos dessa forma:

npm search generator directive

Com o nome do pacote em mãos nós instalamos ele.

npm install generator-angular-directive -g

Os pacotes npm com o prefixo “generator-“ nomeiam templates do yo. Para rodar o gerador recentemente adicionado, nós apenas retiramos o prefixo e passamos como argumento para o Yeoman. Antes disso, garanta que já esta na pasta do projeto.

mkdir ng-yomanDirective
cd ng-yomanDirective
yo angular-directive

Agora que a magica acontece! O Yeoman irá perguntar algumas configurações para gerar de forma mais conveniente o projeto.

Esse template irá o nome que você quer dar para diretiva e o sue nome no github.

Então irá criar a solução com: * Uma configuração para, rodar os teste e o servidor em em live mode; * Configuração para Testes automatizados com karma e jasmine; * configuração para integração continua usando Travis.

Essas são as coisas que você precisa para começar a desenvolver.

Com a solução preparada, rode as seguintes linhas para instalar as dependência:

npm install -g gulp
npm install -g bower
npm install
bower install

Para rodar o live reload demo rode:

gulp serve

E para desenvolver usando TDD, procurando sempre se manter no verde, rode:

gulp test