An awesome setup for your AngularJS project (3/3)

This is post #3 of 3 to explain about fsstatic2. Beware: it may change forever how you approach web development. 🙂

Let’s finish this.

docs.html – A component catalog AND a playground environment.

When working with AngularJS, it’s very useful to have a “playground area” where you can create components without necessarily changing the behaviour of the main application. The DOCS environment serves this purpose. It’s a collection of “test pages” which are able to showcase its own code. It’s very easy to add a new test page, let me show you:

This environment actually can serve multiple purposes:

Playground area: using this environment on their local machines, developers on your team can develop and test components individually. It’s very advisable that every component have its own test page.

Component documentation catalog: If you publish this application on the internet, people can check it out whenever they need to see which components are available, and how to use them.

Prototype showcase: Developers can show their work in progress to designers, clients, and stakeholders in general, in order to collect feedback and refine the direction the product is supposed to go.

So, this is another good practice:

Good practice #7: Have a component catalog.

Tests: running, debugging and coverage reports

Tests should go in the docs folders and be called “test_*.js”. Now there are a few things you want to be able to do with them, like:

  • Run them all [runtests –singleRun=true]
  • Watch for changes, and keep running [runtests]
  • Run a single test [runtests –grep=blabla]
  • Debugging [runtests, open localhost:9876/debug.html]
  • Generate test coverage report (sorry, forgot about this in the video) [runtests –coverage=true]

The video below shows you how

 

test_todo.js: how to write good tests

If you follow Good practice #5 you’ll end up with a codebase where most of your code will be inside AngularJS services. Well, this is *very* good for testing – among all the types of objects you can create with Angular, services are the easiest to test.

Take a look at our test (test_todo.js). I could have made that test use TODOModel directly, but instead I created another service TODOTester. When testing viewmodels like TODOModel, I found out that using a “tester service” like that allows me to write more expressive tests. I mean look at this code:

TodoTester.assert_count_todos(0);
TodoTester.type_and_add('one todo');
TodoTester.type_and_add('to twodos');
TodoTester.type_and_add('tdee throdos');
TodoTester.assert_count_todos(3);
TodoTester.remove(1);
TodoTester.assert_count_todos(2);
TodoTester.assert_todo_text(1, 'tdee throdos');

It really looks like we’re simulating a user “driving” the application. You can even write the test first, give empty implementations to TodoTester methods – your tests will pass, then add the method bodies later. This gives you an incredible “TDD feeling” when you’re doing it.

Another detail worth mentioning is that the tests include api_mock.js, not api.js. This means you can reuse the same mock implementations you already have in your tests (and this is much much better than mocking ajax calls with $httpBackend). For example, we do that in TodoTester.type_and_add(). We know TODOModel.add() will make a (fake) ajax call, and all we need to do is to force our fake backend to respond by calling $timeout.flush().

expect(count).equal(TODOModel.todos.length); 
//still waiting for the "server" to respond
$timeout.flush(); //yay, the server responded!
expect(count + 1).equal(TODOModel.todos.length);

See?

Here’s another tip that may help you with your tests. You could create additional methods on the fake FSApi service (say, FSApi._set_todos(array)), which are only supposed to be used inside tests or DOCS sample pages, which would allow you to preload data on the “fake database”. Speaking more generally, you can add methods to your fake apis that change your fake backend’s behaviour. You can use those methods to load different scenarios both inside unit tests and test pages.

We talked a lot about tests and the good practice here is not so obvious this time:

Good practice #8: ViewModel tests should be talking in a user’s vocabulary.

You should think “I’m gonna write a test for requirement/scenario X” much more often than “I’m gonna write a test for method X”. High test coverage should be only a consequence of that approach. Most of the time this means having to create a “tester” service with method names that are very close to user actions. Sometimes you may also feel the need to create other types of test-helping services, like a “ScenarioLoader”. In any case, the code inside the test itself, should be “easy” enough for even non-programmers to understand.

Wrapping up

What we’ve seen here is more than a project’s setup. I believe that the techniques and ideas presented here can be applied to any web application project to improve architecture/code quality, maintainability, testability, development speed, and as a consequence, happinnes, for you and your team 🙂

Perhaps this is a lot to remember, and if so, the list of good practices below will help, hopefully.

  • #1: Have a project help on the command line (help your team and your future self)
  • #2: Everything is a component (which uses other components)
  • #3: Have a mock API (with promises created out of $timeout)
  • #4: Plan for some flexibility in your templateURLs (with some global variable as a prefix)
  • #5: NEVER use the $scope as a view model. Put your models into services (this is very important!)
  • #6: Let me see the API first (helps answer the “What does this do?” question faster)
  • #7: Have a component catalog
  • #8: ViewModel tests should be talking in a user’s vocabulary (and you’ll need to create extra services for this)

OK, that’s all I had to say folks. Hope it helps.

Cheers! 🙂

An awesome setup for your AngularJS project (2/3)

This is post #2 of 3 to explain about fsstatic2. Beware: it may change forever how you approach web development. 🙂

So, let us continue.

index.html – How the main application works

Routing

There’s not much to say here, it just applies basic ui-router configuration to make a Single Page Application.

  • fs_main.js is responsible for setting up the routing rules
  • Each route has a template that is as simple as <fsissue></fsissue>
  • The toolbar has some <a ui-sref=”statename”> links on it that activate different routes

More details in the video below

Now, notice that even if we had chosen not to build an SPA, we could still use a similiar structure. For example, instead of having an SPA in the index.html file, we could have more pages, like home.html, issue.html, and so on. The code on such a page, say: home.html, could look like:

<body ng-app="fs_main" layout="column" ng-controller="FSMainCtrl">
  <md-toolbar layout="row">
    <fstoolbar></fstoolbar>
  </md-toolbar>
  <div layout="row" flex>
    <div layout="column" flex id="content">
      <md-content layout="column" flex class="md-padding">
        <fshome></fshome>
      </md-content>
    </div>
  </div>
</body>

 

Can you smell another good practice here? Right…

Good practice #2: Everything is a component.

Our application should be structured as a composition of components, not very different from each other in terms of architecture. In our case I’ve decided that each component is a restrict=”E” directive. The result is a very standardized way of doing things. People on your team will be able to understand each other’s code faster because everything has more or less the same structure.

Mock api

Don’t talk to URL’s directly. Instead, hide your backend URLs behind a stateless Angular service with a bunch of methods that return promises.

Then, make an alternative implementation that pretends to talk to the backend, but actually generate hard-coded data in javascript and resolves promises with $timeout. This takes us to the next good practice:

Good practice #3: Have a mock API.

This will allow you to have an environment where you can switch between a full stack environment and front-end-only environment. This ability will most likely boost the speed on your development process.

Authentication

Does it even make sense talking about authentication if we don’t have a real backend yet? The answer is YES. The front-end plays a big part in the authentication process and we can go and implement the client part beforehand, just like we can do it with anything else, really. We don’t even need a video this time (but you will have to take a look at the code as you keep reading!)

FSAuth’s (fsauth.js) responsibility is to provide information about the current user to the rest of the application. Whoever needs to know if we are authenticated can just call FSAuth.authenticated(). If they need the current username, then FSAuth.user.username. The <fslogin> directive (fslogin.js/fslogin.html) has a viewmodel (FSLoginModel) that is activated in the login screen. When the user fills the login form and hits OK, FSLoginModel.login() will ask our “backend” to authenticate us – FSApi.login(username, password) – and then give FSAuth the currently logged user by invoking FSAuth.set_user().

Now there’s an important detail here. We want the real backend implementation of FSApi.login(u, p) not only to return a json with information about the current user. This particular response also needs to come with a set-cookie header that will tell the browser to store a session variable in a cookie, which will be sent in all subsequent requests. That way, the backend can know who is the user making those requests. This is what is supposed to happen when we call FSApi.whoami() – if the request comes from an authenticated user, this should return that user data, otherwise the response must say something like “Oh, you’re just nobody :-)”.

Now FSAuth, during its initialization (see _check_for_authentication) will call FSApi.whoami() and store the current user in itself if it is authenticated. The current mocked implementation of FSApi.whoami() will always return an authenticated user – this is arbitrary. So if the user refreshes the page, FSAuth will still know who the current user is.

Our main <fstoolbar> (fstoolbar.js/fstoolbar.html) is also dependent on FSAuth. You can notice that the toolbar’s right side will show different content depending on the result of FSAuth.authenticated().

The logout feature is left as an exercise for you to understand alone 🙂

So, the only piece missing in our authentication process is the backend. If we have correct, real implementations for FSApi.login(u, p) and FSApi.whoami(), it should work for real.

Template URLs

Anywhere we include a template we have a path prefix before the template URL. For example, the templateURL for the <fslogin> directive is FS.BASE_URL+’login/fslogin.html’.

This will give you more flexibility to move included .js files relative to the main html file. Let me show you.

And don’t forget this also goes for templates included with ng-include.

This is important, so let’s add it as another good practice to our list:

Good practice #4: Plan for some flexibility in your templateURLs.

This can help you have with the dev vs. prod build differences, and it will also save you some trouble when you have to move stuff around.

todo.js – A detailed example of how to make a component

The DOCS page has a <todo> component that illustrates how to make a simple component. This doesn’t relate to any feature in FS, it’s just that I didn’t have a better idea for a sample component.

The main recommendation that I give to everyone using angular is this: do not use the $scope as a model. It’s better to put the model implementation inside a service. Let me show you.

Of course, this is another good practice.

Good practice #5: NEVER use the $scope as a view model. Put your models into services.

I can’t stress enough how important this is. Having your view models inside services allows you to have a much cleaner code as a result of a clear separation of concerns. As a bonus, it also makes your code very easy to right unit tests for.

Your screen needs some AJAX action? No problem, inject an API service into its viewmodel and let the model handle the AJAX for you. Need a loading-please-wait animation? Sure, have a boolean attribute in your model that tells the template when to display it. But keep your distance from the $scope object. Trust me, the less you rely on it, the better off you are.

If you look at the rest of the directives in the src/ folder you can see that I intend to apply this same pattern to all components.

Some other detail that you might have noticed is the way that the code inside the TODOModel is laid out:

var m = {
    newtodo: '',
    adding: false,
    todos: [],
};

angular.extend(m, {
    add: add,
    remove: remove,
});

There’s actually another good practice behind this:

Good practice #6: Let me see the API first.

You can see what TODOModel is supposed… er… to do (:P) after a quick glance on just the snippet above, right? It’s a plain object with those 3 attributes that make up its state, and those two operations that change it. Seeing the attributes and operations at the top allows me to realize faster what are this object’s responsibilities.

All right, this is enough for post #2. In the next and last post we’ll cover.

  • docs.html – A component catalog AND a playground environment.
  • Tests: running and debugging
  • test_todo.js: how to write good tests

One last thing: please repeat with me one last time (out loud is better):

I will never use the $scope as a viewmodel. 

Good.

Just to be sure 🙂

An awesome setup for your AngularJS project (1/3)

This is post #1 of 3 to explain about fsstatic2. Beware: it may change forever how you approach web development. 🙂

In the past two years I’ve been working a lot with web development and AngularJS.
FreedomSponsors is an open source web application that I made before that, so it doesn’t have in it all those cool new things that I have learned.

I’d like to change that, so I’m rebuilding FreedomSponsors as a AngularJS-based Single Page Application.
The primary reason I’m doing it is because I believe that if FS has a really friendly development environment, more people will be able to collaborate with it and this will help the project move forward.

There’s also a secondary reason: I want this new website to serve as example for people who want to learn more about good practices for web development – this is what this post is about.

The resulting webapp right now is still far from complete (feature-wise), but its architecure already has some good ideas that you may want to apply on your project. Or, if you’re starting a new project, you can just clone the project and go from there.

The main architectural features it has right now:

  • fshelp – A list of commands easy at hand so we don’t need to memorize anything
  • JsHint: Everyone loves their javascript style checked
  • DOCS (docs.html): A “playground” page that can be used both for 1) developing/testing new components, and 2) documenting how to use them
  • The app (index.html): A single page application that you can run locally (ui-router based)
  • Mock API: With this we can mock all of the backend JSON api. Focus on front-end development first; worry about the real backend api later.
  • Fast save/refresh cicle: Using devbuild/runserver, you end up with a development environment where you can save files and hit refresh, with no build steps in between (except for scss files, at least for now)
  • Javascript tests, with coverage report – Bonus: you can reuse the same mock api in the tests too
  • Production build: Build in production mode with all js and html concatenated in a single file. Bonus: it also works with file:// so it should be possible to port it to mobile with no (or maybe very little) modifications using Cordova (yes I intend to do this with FS in the future)
  • Generated CSS using Sass

Exciting, isn’t it? 🙂

So, let’s dive into it with a little more detail…

Get it up and running

It should be really simple and fast, just follow the readme on github, or watch the video below.

Oh, can you please let me know in the comments below how long it took you? 🙂

Now there’s a good practice worth noting here:
Good Practice #1: Have a project help like this.

fshelp

People working in your project should not have to waste their time memorizing commands (if the predefined commands have autocomplete, even better)
When you have someone new in your team, this should save you some time

Folder structure: What is where, and how the build works.

Here’s a quick summary for you

src/                            # All your code is belong to me
src/pages/index.html            # The main application
src/pages/docs.html             # The DOCS application
src/**/*.[js|html|scss]         # The bits and pieces of the app
src/api/api.js                  # The real API that will talk to the backend
src/api/api_mock.js             # The fake API which is what we'll be using for a while
src/**/docs/**/*.[js|html]      # Documentation pages and unit tests (none of this will see production)
src/**/docs/**/test_*.js        # Unit tests
docs_src/                       # The docs framework
lib/**/*.[js|css]               # Third-party stuff
settings/*.js                   # Some settings that differentiate dev vs. prod environments
dist/                           # The result of our build goes here
dist/index.html                 # src/pages/index.html, after some find/replaces
dist/docs.html                  # Guess :)
dist/css/fs.css                 # src/**/*.scss gets compile here
dist/css/lib[.min].css          # Part of lib/**/*.css gets concatenated here
dist/css/lib[.min].js           # Part of lib/**/*.js gets concatenated here
dist/js/fs.js [P]               # src/**/*.[js|html] gets concatenated here (except for **/docs/**)
dist/js/fsdocs.js [P]           # src/**/docs/**/*.js gets concatenated here
dist/js/docs.js [P]             # docs_src/**/*.[js|html] gets concatenated here
dist/js/fs.js                   # Part of lib/**/*.js gets concatenated here
testlib/**/*                    # Libraries used only in unit tests
gulpfile.js                     # THE build
fsdev.sh                        # Handy commands

(Items marked with [P] are only relevant in the production build)

The video below will demonstrate a little more what the build can do.

There’s something I forgot to show in the video, which is, when you build the app using prodmock, it also works with file:// like this:

fsstatic2_file_protocol

 

A good side effect of this is that in the future we are more likely to be able to make an IOS/Android app out of it using Cordova (yes I intend to to that in the future).

OK, this concludes the first post. In the next two posts I’ll talk about:

  • index.html – How the main application works
  • todo.js – A detailed exampled of how to make a component
  • docs.html – A component catalog AND a playground environment.
  • Tests: running and debugging
  • test_todo.js: how to write good tests

Stay tuned.

Faça você mesmo: mini CRUD com AngularJS

Depositphotos_2421161_xs

Vira e mexe me perguntam sobre CRUD com AngularJS.
Aparentemente muita gente precisa disso.

Eu particularmente no meu trabalho no QMágico não mexo muito com CRUD então tenho pouca experiência no assunto: “existe algum componente pronto pra isso?” – aliás, se vc tiver, por favor conte pra gente aí nos comentários.

Maaas, pra demonstrar como é fácil criar componentes genéricos com Angular, eu fiz uma sequência de plunkers que mostram como criar um componente de CRUD genérico, muito rudimentar, mas que cumpre o propósito didático. Se alguém quiser continuar o serviço, criar um projetinho no Github, etc, com certeza a comunidade agradece.

A lista dos plunkers, passo a passo:

Eu tb coloquei esse código no Github pra que vc possa ver o diff de um passo pro outro: https://github.com/tonylampada/angular_mini_crud

E os diffs: https://github.com/tonylampada/angular_mini_crud/commits/gh-pages

E esse projeto no github está na branch gh-pages, então vc consegue ver o resultado final aqui também:

http://tonylampada.github.io/angular_mini_crud/

Então eu vou só dar uma explicadinha superficial em cada passo.

1) LocalStorage

Nesse plunker eu demonstro como usar o LocalStorage – a api do browser que permite vc persistir dados no disco do usuario.
No nosso exemplo, a gente vai usar o LocalStorage pra fazer de conta que eh um banco de dados no backend.

Se vc ainda não conhece o localStorage, dá uma olhada aqui no blog do Zeno: http://zenorocha.com/html5-local-storage/

2) CrudApi

Nesse plunker eu faço um CrudApi – um serviço que faz de conta que fala ajax com um backend, mas que na verdade usa $timeout e o LocalTableStorage por baixo dos panos.

O MyCtrl nem desconfia de nada.

As ações agora tem um “lag” de 500ms.

3) Arquitetura

Nessa terceira parte eu montei só o esqueleto da parada.
Temos uma diretiva <crud>, uma diretiva <crud-grid> e outra diretiva <crud-form>.
Essas diretivas não fazem nada, mas elas já sabem que vão precisar de um CrudModel pra implementar a lógica por trás delas.

Além disso, temos também um objeto models, que conhece os modelos dos objetos que a gente quer persistir.

Pra deixar mais claro, fiz um desenho com um diagrama “CRC” – que mostra responsabilidades e colaborações:

crud-angular (1)

3a) Arquitetura + raio frontentizador do Hugo Almeida

Meu amigo Hugo Almeida deu um trato no css desse cara pra ele ficar um pouquinho mais bonito.
Valeu Hugo!

4) cRuD (READ e DELETE prontos)

Agora o negócio começa a tomar forma…

Nesse 4o plunker eu mexi na diretiva <crud-grid> – ela agora lista as entidades e permite que vc apague.
Pra isso, eu tive que implementar essas funcionalidades no CrudModel – que é o modelo que a diretiva usa (também compartilhado com <crud> e <crud-form>)

Entao, se vc criou uns Tony’s e Maria’s com os exemplos 1 e 2, vc pode usar o exemplo 4 pra apagá-los.

Tah ficando bom hein 🙂

UPDATE: Tem um bug na deleção – vai ser resolvido no passo 7 (sorry :P)

5) crud5 – options

Nessa versão, pela primeira vez estou passando um options (veja no arquivo script.js) com um dicionário pra gerar nomes mais amigáveis pros campos dos objetos. Eu mudei a <crud-grid> pra usar isso aih nos headers. Tá fazendo sentido isso aih?

Agora, tem um problema meio fundamental na nossa implementação:

O CrudModel.entities é um array que tá cheio de objetos não-tipados ({nome, idade}).
O ideal é que ele tivesse objetos Pessoa(nome, idade). Por exemplo, eu não consigo mandar um objeto desses fazer aniversário.

Antes de continuar lendo e ver como resolver isso, dá uma pensada aih: Qual o lugar “correto” pra resolver esse problema?

Dica: Dá uma lida no meu post anterior (aquele da macarronada), e veja o diagrama de responsabilidades acima. Tá faltando alguma responsabilidade nova? Tem alguém que não tá cumprindo sua responsabilidade direito?

Não existe resposta “certa”, mas o processo de pensar a respeito é muito bom.

6) CrudApi, eu quero objetos tipados!

Pensou? Então tá. A minha resposta é a seguinte:

Parece que é do CrudApi a responsabilidade de listar Pessoas() ou Animais(), né?

Não faz nenhum sentido fazer isso no LocalTableStorage – se a gente trocar esse banco fake por uma api com $http, por exemplo, já era.

E a gente até podia fazer essa conversão no CrudModel também, mas aí qualquer outro cliente do CrudApi eventualmente teria que duplicar esse tipo de código. Então é o CrudApi.list() e o CrudApi.get() que são os errados das história. Esses caras deviam retornar Pessoas() e Animais() ao invés de object.

Mas aí tem um probleminha: Pra isso, o CrudApi precisa conhecer o models né? Tava tão bonitinho nosso diagrama, agora vai ter uma seta saindo lá de baixo voltando lá pra cima…

Além do mais, o CrudApi estava totalmente genérico e independente. Agora ele vai ficar acoplado com o meu models. Não parece um negócio muito bom, principalmente se eu quiser liberar esse componente como open source (e portanto podendo ser usado com outros models). E agora?

Bom, não tem jeito. O CrudApi precisa saber criar Pessoas().
Mas nem por isso a gente precisa injetar o models nele durante a inicialização do angular – criando o que eu chamo de dependência forte.

A gente pode fazer que ele seja esperto o suficiente pra: caso tenha um models, ok, trabalha com o models. Senão, beleza também, trabalha com objetos não tipados.

Daí a gente injeta o models nele usando um setter da vida, e programa o if(models){ bem } else { bom tambem }. Assim a dependência pro models fica mais fraca.

Então nosso diagrama agora fica assim.

crud-angular (2)

E pronto.

No script.js a gente faz a configuração do CrudApi com o models,
O crudapi.js foi refatorado pra usar o models de acordo.
E se vc botar um breakpoint no CrudModel.list(), vai ver que agora ele recebeu uma lista de Pessoas() do CrudApi.

Agora sim. Já podemos começar a pensar no form…

7) CCCCreating!

Alterações nesse passo:

  • Resolvi um bug que não deletava entidades do banco. A alteração foi no CrudModel.remove() e na implementação interna do localStorage correspondente.
  • As “classes” Pessoa e Animal no models só conheciam os nomes dos seus atributos. Pra implementar o form, eu tive que mudar isso, pq cada campo do form precisa ser renderizado de acordo com o seu tipo. Então Pessoa.crud_fields não é mais um array de strings e sim um array de object({name, type})
  • O CrudModel sabe qual template usar pra mostrar um campo desde que o tipo seja “id”, “string”, ou “int”. É fácil adicionar novos tipos no framework, basta criar novos templates de acordo.

No próximo passo: EDIT

8) CRUD Completinho

Agora sim, o crud completo.

Repare que pra editar um objeto a gente cria uma copia dele (veja no CrudModel.update()).
Isso eh pra dar pro usuario a chance de cancelar as alterações dele sem refletir as mudanças no grid.

Eu tb tive que mudar o comportamento do CrudModel.save()if(creating){adiciona no array} else { atualiza o objeto }

O próximo e último passo é pra permitir a gente trocar entre pessoa e animal.

9) Trocando de Crud

Nesse último exemplo eu só mexi no index.html / script.js pra permitir que o usuario alterne entre o crud de pessoas e animais.
Veja que bastou trocar o model na diretiva <crud model=”model”>.

Bom, na verdade eu tive que fazer uma mudancinha no controller da diretiva <crud-grid> também, pra atualizar a lista de entidades na tabela.

Mas, é isso aih. Super tranquilo 🙂

10) E agora? Próximos passos?

Então, se vc realmente precisa de um framework como esse, o esqueleto ta aí mas ainda tem muito trabalho pela frente.
Algumas tarefas pra ficar bão:

  • Faça uma vídeo-aula explicando esse código e coloque no Youtube 🙂
  • Se vc imaginar que o <crud> vai ser um componente open source, então o CrudModel deveria ser capaz de receber o CrudApi como “dependência fraca” (via um .configure() da vida), e não como serviço injetado pelo Angular. Pensando bem, devia ter feito assim desde o começo. Sóre.
  • Faz um CrudApi que fala com um backend de verdade (usando $http, ou $resource, ou restangular). Obs: levar em conta as preocupações com segurança nessa hora: aplicações de crud tem uma tendência de expor uma api que é basicamente uma console sql pro seu banco. Seu backend precisa tomar cuidado com isso pra permitir escrita no lugar certo pro usuário certo.
  • Não é uma boa ideia implementar o grid e o form na unha, do zero. O ideal é usar coisas prontas pra isso, como o ng-grid e o formly
  • Paginação: teria que mudar o contrato do CrudApi.list(filters, options). A idéia é fazer o back retornar dados aos poucos, de acordo com parâmetros de paginação no filters.
  • Formulário de busca: o grid deveria ter um formulário de busca, idealmente customizado pelo crud_options passado pra diretiva <crud>.
  • Validação: O formulário precisa de validação de campos. Talvez o formly ajude nisso.
  • Outra opção de customização via crud_options seria escolher quais campos deveriam aparecer no grid e no form. Talvez esconder “id” por default seja uma boa ideia.
  • E outra ainda seria passar um template customizado pro form. Talvez no crud de animal eu queira usar o grid default, mas com um formulário com um comportamento diferente do padrão.
  • E se vc fez tudo isso acima, bota no GitHub!!

Sobre orientação a objeto, responsabilidades e comida italiana

tulum-trattoria-romana

Faz tempo que eu venho pensando sobre um assunto e só há poucos dias conseguir botar no papel.

Tem a ver com orientação a objetos, responsabilidades, colaboração/comunicação, e comida italiana.
Aqui vai…

Quando eu comecei a programar, lá em 2000, eu tive contato com esse conceito de “orientação a objeto”.
Classes, atributos, métodos, herança, polimorfismo, pá.
As pessoas diziam que era melhor programar usando esse paradigma. Mas, olhando pra trás, nunca ninguém me explicou porquê exatamente isso era melhor.

O tempo passou e eu ouvi uma metáfora que ficou na cabeça: usando orientação a objetos, seu código fica menos parecido com um prato de espaghetti e mais parecido com um prato de ravioli. Cada ravioli faz uma coisa, os raviolis falam com outros raviolis quando necessário, e seu sistema fica muito mais fácil de manter e evoluir,

Só que… na prática não era bem assim.

De lá pra cá eu programei muita coisa OO, e tive contato com muito código OO. Herança, Polimorfismo, classes, tá tudo lá, sempre. Mas ainda assim, muitas vezes o código, mesmo OO, ainda tinha aquele cheirinho de spaghetti.

E aí a medida que eu fui ficando mais experiente, eu me pegava cada vez mais pensando em termos de responsabilidades e “conhecimento”:

  • Onde eu devo colocar esse método? De quem deve ser a responsabilidade por essa tarefa?
  • Hum, essa responsabilidade tá no lugar errado, precisa refatorar isso aqui…
  • Xi, esse componente aqui não deveria conhecer aquele componente acolá.

(Veja que eu estou usando a palavra componente de maneira muito genérica aqui. Pode ser um <input>, uma classe java, um módulo python, uma função javascript. Neste contexto, um componente é um pedaço do seu software que tem uma responsabilidade ok?)

E aí tem vezes que um sistema crescendo lembra até uma empresa: vira e mexe vc se pega perguntando “quem é/deveria ser a pessoa/área responsável por essa atividade?” – alguém aí já passou por isso?

Peraí que eu tô viajando muito, deixa eu aterrisar aqui…

Então, refletindo de maneira um pouco mais profunda sobre isso, cheguei à conclusão que:

Pensar meramente em termos de OO não causa código raviólico.

Pra fazer código raviólico vc precisa enxergar seu software como uma rede de componentes que colaboram entre si.

Acho que, idealmente, isso deve se parecer com a estrutura B abaixo.

unnamed

  • Cada componente tem uma responsabilidade bem definida – senão vc vai ficar perdido scrollando no meio de um monte de código.
  • Cada componente deve conhecer apenas alguns poucos vizinhos mais íntimos – senão gera alto acoplamento: os componentes perdem a capacidade de variar independentemente. Aí se vc muda um negócio aqui -> causa vários impactos (ou bugs) acolá.
  • E cada componente pode ser quebrado em componentes menores. Vc pode ter uma rede de componentes dentro de um componente.

No nosso trabalho, além de programar as responsabilidades de cada componente, a gente precisa definir responsabilidades e organizar essa rede de modo a facilitar a comunicação entre os componentes; de modo que comunicação entre eles flua de maneira ótima.

Fazer software bem feito é a arte de ser CEO do sistema! 🙂

Então: no dia que vc for ensinar programação pra alguém que tá começando: antes de falar sobre OO, herança, etc; por favor considere falar primeiro sobre raviolis. O ravioli que é o importante.

Antes de bitolar no OO, o caboco precisa entender porquê dividir um sistema em partes menores, com responsabilidades bem definidas, e tão independentes umas das outras quanto possível.
O importante é focar na rede, e na otimização da interação entre os elementos da rede. OO é só uma ferramenta pra ajudar a construir a rede.

Pq se o caboco não tiver pensando em ravioli desde o começo, vai sair espaghetti.

Ah vai.

Dado que o Angular 2.0 tá aí, vale a pena investir no Angular 1.X?

Angular-2.0
O Angular 2.0 está sendo desenvolvido a todo vapor, e vai ser completamente incompatível com o Angular 1.X.

Em outras palavras, não será possível migrar a sua aplicação do Angular 1.x pro 2.0 sem um refactoring muito grande no código.

Por isso, muita gente me fez/faz alguma variante da pergunta acima.
Tem gente que até me pergunta “cadê o curso de Angular 2.0 que eu quero me matricular!”

Estou escrevendo esse post porque assim, da próxima vez eu posso simplesmente redirecionar a pessoa pro meu blog. Pura preguiça, digo, puro reuso.

Mas então, qual a resposta?

Antes de responder, eu quero deixar claro que essa é a minha opinião sobre um assunto polêmico.
Eu não sou o dono da verdade e programadores diferentes podem ter opiniões diferentes.
E digo mais, nada impede que no futuro minha opinião mude! A única coisa que eu garanto nesse caso é que se isso acontecer, eu voltarei aqui nesse post pra fazer um update. OK?

Então tá.

Sim, vale muito a pena investir no Angular 1.

E aproveitando pra fazer o jabá-de-cada-dia: se vc quer aprender Angular 1, ainda dá tempo de se inscrever pra turma 4 do ng-masters! Nessa edição vamos usar a versão 1.3 (é a versão stable mais recente)

E não, não vale a pena investir no Angular 2 HOJE, a menos que vc domine Angular 1, e tenha tempo sobrando, e não tenha nada mais relevante na sua fila de coisas que vc gostaria de aprender. (então no meu caso, por exemplo, não vale).

Mas… por que?!

Angular 2.0 vai ser o cão chupando manga. Vai usar webcomponents, vai ser mais rápido, vai ser lindo, vai usar recursos da nova versão do javascript

Opa! Alguém falou novo javascript?

Pois é… O Angular 2 depende do ecmascript 6, o novo Javascript que vai ter classes, Map, Set, Object.observe (que deverá deixar os bindings bem mais rápidos) – também vai ser outra coisa linda de Deus o ecma 6.

MAS

Sua aplicação web precisa rodar no browser do seu usuário.
Então, na prática, até que todos os navegadores tenham suporte nativo ao ecma 6, Angular 2 está fora de questão pra ser usado em produção.

Então… “Dado que o Angular 2.0 tá aí”…
FALSO! O Angular 2.0 não tá tãaao aí assim. E vai demorar um pouco até que ele possa estar aí.

Estudar Angular 2 hoje é equivalente a se matricular numa escolinha de hoverboard: vc pode até se divertir pacas, mas vai demorar um pouco até vc conseguir aplicar o que aprendeu.

hoverboard1

Então eu tenho uma postura mais pragmática: eu vou me especializando cada vez mais no que eu posso usar em produção, que é o Angular 1.X véio de guerra! :-). Pra resolver hoje problemas que meus usuários têm hoje.

A hora nós tivermos ecma 6 em todos os browsers, aí sim eu pretendo dar uma olhada nos frameworks e como eles me ajudam a resolver problemas. Nesse dia possivelmente eu decidirei investir em Angular 2, mas pode ser que eu decida por outra coisa tb, sei lá. Duvido que Angular 2 vai ser a única opção. Acho muito provável que será a melhor opção, mas duvido que será a única.

De qq forma esse dia parece meio longe ainda.

Tá, então tem outra pergunta mais relevante que pode ser feita que é a seguinte:

Dá pra fazer alguma coisa hoje na minha aplicação pra minimizar o tamanho do refactoring se eu quiser migrar pra Angular 2, no dia que isso for possível?

Eu acho essa pergunta bem mais relevante que a primeira.

A resposta é: Tem sim: pára de armazenar estado no $scope dos seus controllers.
Tem um vídeo que fiz há um tempo atrás que eu considero a sacada mais importante sobre Angular que eu já tive.
O vídeo é esse aqui: Como fazer TDD com Angular.

Nesse vídeo eu explico como vc pode armazenar o estado da sua tela num serviço criado com angular.factory() ao invés de usar o $scope do controller.
Fazendo isso, vc tem um objeto javascript puro que armazena todos os dados que aparecem na sua tela, e contém alguns métodos que aplicam transformações no estado interno dele. Enfim, um objeto simples como o que vc viu na aula de OO.
Com isso sua aplicação fica mais testável (daí o título do vídeo), e menos dependente do próprio Angular.
Eu acredito que uma aplicação construída nesse esquema vai dar um pouco menos de trabalho pra migrar pra Angular 2, ou pra qualquer outra coisa!
Nós já estamos trabalhando nesse esquema lá no QMágico e só tem benefícios. Não só pela testabilidade, mas a qualidade do código tá melhorando bastante por causa disso. Recomendo demais.

Bom, tá aí minha opinião…
Se eu falei alguma bobagem aí, por favor fica a vontade pra me corrigir nos comentários abaixo, e se vc tem alguma informação relevante pra jogar na roda, fica a vontade (principalmente, se vc acha que eu estou errado, bora quebrar o pau!!! :-)) ). O assunto é polêmico mesmo, eu acho.

As 3 leis da build

Semana passada eu implementei um negócio interessante no QMágico, daí resolvi passar aqui pra contar a história.

1. O problema:

Lá no QMágico, a gente usa o Jenkins pra fazer integração contínua. E temos um monitor visivel que fica vermelho quando a build está quebrada. Builds quebradas atrapalham o trabalho de todo mundo, e quando a build fica quebrada por bastante tempo, isso tende a ter um impacto negativo na produtividade do time.
O principal bloqueio da build quebrada é que, como não é possível dar deploy da versão, fica difícil testar suas alterações no ambiente de testes.

2. A solução:

Pra resolver isso, instituímos “As 3 leis da build”, que são as seguintes:

3leis

 

Não, mentira, são essas abaixo! hehehe

  • 1a. lei: Não comitarás em branch quebrada (Ou seja, uma branch que não tenha sido buildada com sucesso pelo Jenkins).
    Se vc quiser fazer um commit mas a branch está quebrada, vc deve providenciar que ela fique verde primeiro: Ou seja, ou vc conserta o que está quebrado, ou vai atrás da pessoa que quebrou pra ela consertar. Só depois que estiver verde, vc pode comitar suas alterações.

 

  • 2a. lei: Se vc quebrar a build, vc tem 20 minutos pra consertar. Mesmo que pra isso vc preciso desfazer seu ultimo commit.

 

  • 3a. lei: Se vc encontrar uma build quebrada há mais de 20min, e o responsável pela quebra não estiver disponível, vc tem o direto de desfazer o último commit do safado, e colocar o seu commit em cima da build verde.

Na minha interpretação, isso é o mais parecido que dá pra se ficar do conceito de “Jidoka / Stop the line” da Toyota: quando aparece um problema, tudo pára até que o problema seja resolvido.
Com uma vantagem que, no nosso caso, dá pra jogar o problema pra uma branch separada. Assim, dá pra resolver o problema com calma numa branch temporária sem atrapalhar o trabalho de todo mundo na branch principal.

Agora, pra que essas leis sejam realmente cumpridas, precisa de uma forcinha das ferramenta envolvidas no processo. Nenhum processo funciona baseado exclusivamente na boa vontade de um número grande de pessoas, por melhores que elas sejam.

Então, nosso servidor do Git agora eh capaz de rejeitar “pushes” com uma mensagem do tipo:

Seu push foi rejeitado porque essa branch estah quebrada!
desc=qm-1697[48e670a4..f88f4372] by tonylampada / DEU PAU no teste python
last_update=2015/02/23-20:30:14
Vai lah no Jenkins e ve o que tah rolando
Se vc quiser fazer um commit pra consertar a build use a palavra mahgica “WILLFIX” no comentario
(por favor nao abuse desse recurso, senao vai rolar um creu em vc)
Se o responsavel pela quebra nao estiver disponivel no momento, vc pode – e deve – voltar o commit do safado
Pra isso, basta usar o job no Jenkins “Voltar_commit”

ou então

Já tem uma build dessa branch rodando, tenta daqui a pouquinho!
desc=qm-1697[48e670a4..f88f4372] by tonylampada
last_update=2015/02/23-20:30:14

Voltar commits com o git é uma tarefa que nem todo mundo sabe fazer.
As vezes alguém pode se atrapalhar com os comandos do git e acabar “fazendo merge” se é q vc me entende.

Então pra facilitar, criamos um job no Jenkins pra isso.
Após voltar o commit de alguém, ele manda um email parecido com:

Ola tonylampada, tudo bem?
Aqui eh o seu amigo Jenkins véio de guerra.
Tenho uma notícia que talvez vc não goste, mas que eh pro bem do time, e do processo de desenvolvimento como um todo.
Entao, sabe o zorak… ele voltou seu commit. Provavelmente pq vc quebrou a build.
Ele deixou um recadinho pra vc, veja:

ow! q p*** eh essa???

Mas fica tranquilo que eu salvei seu trabalho. Veja as minhas instruções pra você no final do email.
——————————————
Historico:
* 91bae56 – pep8 (2015-02-23 16:43:12 -0300 ) <tonylampada>
* 859a608 – quebradeira geral (2015-02-23 16:42:46 -0300 ) <tonylampada>
* beb04a6 – Quebra mais quebra mais (2015-02-23 16:41:11 -0300 ) <tonylampada>
* a9f9192 – teste: quebrando a build! (2015-02-23 16:40:46 -0300 ) <tonylampada>
* a502197 – Corrigindo textos da edição de provas. (2015-02-23 16:37:04 -0300 ) <Luiz Edmundo Mizutani>
Voltou para: a5021970
Quem mandou voltar: zorak
Branch salva: tonylampada_91bae56
——————————————
O estado do seu trabalho está salvo na branch tonylampada_91bae56.
Basta que voce continue seu trabalho lá, e assim que a build nessa branch estiver verde, vc pode fazer um merge de volta pra dev, flw?
Boa sorte aih, fique longe das gambiarras e mantenha os amiguinhos longe tambem!
Um grande abraço do seu amigo
Jenkins

3. O impacto

Esse esquema já está em vigor no QMágico há quase 1 semana e o efeito é interessantíssimo.
É muito difícil a build ficar vermelha. E normalmente, quando fica, é numa branch temporaria diferente da branch principal onde todo mundo trabalha.
Eu fiquei até meio frustrado de até agora não ter podido voltar o commit de ninguém! rs
Ou seja, como ninguém quer ser vítima da 3a lei, todo mundo tá praticando a 2a. direitinho (que é a única lei que a gente não força via automação)

O gráfico abaixo mostra a quantidade de horas por dia em que a build ficava quebrada (sem nenhum filtro por branch. O ideal seria filtrar apenas pela branch de desenvolvimento, mas isso não era tão trivial de extrair do Jenkins)

build_quebrada

No dia 24/2, a gente habilitou as 3 leis. De lá pra cá o pior dia foi 4/3 que teve 2h30m de build quebrada – e ainda assim parece q isso é uma anomalia.

Repare que no dia 10/2 nós tivemos ~22h de build quebrada – que também não é normal no nosso dia a dia, só que esse tipo de coisa nunca mais deverá acontecer.

4. A receita

Implementar isso não é tão difícil. Precisa de um pouquinho de bash, python e criatividade.

  • a) O Jenkins precisa expor o status das branches.

Toda build do projeto atualiza o arquivo /var/lib/jenkins/userContent/status_qmagico.json, que é automaticamente compartilhado pelo Jenkins na URL jenkins.meudominio.com/userContent/status_qmagico.json

O conteudo desse arquivo é algo tipo [1]

E o script usado pra atualizá-lo é um programinha python como [2].

O a build do projeto então usa esse script pra setar o status da branch como “BUILDING”, “SUCCESS” e “FAIL”.

b) No servidor do git, vc precisa criar um “pre-receive hook”, ou seja, um script que é executado no servidor toda vida que alguém faz um push: O push só é aceito se o script sair com retorno 0, além disso, tudo que o script mandar pra saída padrão aparece pro programador que fez o push.

No nosso caso, nosso servidor git fica dentro de uma instância do Gitlab.
Daí é só criar um script aqui “/opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive”

O que eu fiz foi partir desse exemplo (http://www.stavros.io/posts/pep8-git-hooks/) (que é um script pra rejeitar pushes se o codigo nao obedecer alguns padrões de codificação python) eu fui mexendo pra ele fazer o que eu precisava.

Uma parte que deu trabalho foi encontrar o encantamento correto pra buscar o arquivo de status.
Veja como a função em bash que faz valer a 1a lei: [3]

Obs: Esse XXXX aih no lugar do password não é a minha senha do jenkins. É um “API TOKEN” que tem disponível na página de configuração do usuario do jenkins.

E o arquivo “$TEMPDIR/ci/primeiraleidabuild.py” [4] é que interpreta o json.

E é isso aí. Espero que seja útil!

Até a próxima.

How to make LibreJS like you

librejs

GNU LibreJS is a browser plugin that aims to address the JavaScript problem described in Richard Stallman’s article The JavaScript Trap.

LibreJS thus blocks the execution of any javascript files that aren’t licensed as free software.

A while ago, Richard Stallman contacted me and asked me if I could try and make freedomsponsors.org compatible with LibreJS. At the time I was really busy and couldn’t do it. But recently I made another attempt and succeeded.

Making your website compatible with LibreJS is hard-ish, I’ll summarize below a few tips that worked for me.
If you need libreJS to like your site too, I think these tips will be very helpful, specially if your website uses AngularJS or AJAX.

Before we get down to it, here’s a few pointers that may be useful:

Now, the tips

1) The easiest way to make your .js files recognized as free software is to use the web labels method.

  • Every page on your website should have a link to that page, with rel=”jslicense”
    Example: on https://freedomsponsors.org you’ll find this link:

<a href=”/jslic” rel=”jslicense”>JavaScript license information</a>

  • The “Javascript license information” should have a 3 column table that lists all .js files used in your website
    • column 1: A link to the .js file, with the same path used in the <script src=”…”> tags
    • column 2: A link to the free software license this file is released on. This link should be one of the ones listed under the Free Licenses Detection section of the documentation
    • column 3: A link to the original source code for that file.

2) You need to restart firefox everytime

When you’re testing your website using firefox with LibreJS enabled, you’d think it would go somehow like this:

  • Change something in the backend
  • Refresh the browser and see if it works
  • Start again

It took me a while before I realized this doesn’t work. You have to restart firefox for LibreJS to behave consistently, thus:

  • Change something in the backend
  • Close firefox
  • Open firefox, go the page and see if it works
  • Start again

3) LibreJS may change the contents of AJAX responses.

Whenever the browser gets any http(s) response with content-type == ‘text/html’, LibreJS might change its contents adding a header and a footer. This email thread explains that in more detail (look at the screenshots attached on the first email)

So, beware of that.

4) If you’re using AngularJS, then you need to use $templateCache

Because of (#3), you can’t let AngularJS load html templates dynamically – LibreJS will change them and break your website.
You need to cache those templates in a .js file using the $templateCache Angular service.

FreedomSponsors does this using Grunt.
All templates are concatenated along with other javascript files into fs.js (the html templates are at the bottom)

5) You need to use the correct content type for json responses

Chances are that your client-side code makes AJAX calls that return json responses.
You should set content-type == ‘application/json’ for those responses. If you leave the default of “text/html”, LibreJS will change them and break your site

6) You need to escape special characters properly.

For example:
* No: «
* Yes: &laquo;

Otherwise they won’t be displayed correctly when LibreJS is enabled

7) The guys at the help-librejs mailing list are very helpful

Sign up for that mail list and ask for help whenever you need it.
The guys there are great people and are willing to help.

Well, those are the tips I had to share.

Did it help you? Or perhaps you have more hot tips? Please let me know in the comments below.

Conclusion

Overall, making my website compliant with LibreJS was sometimes frustrating and annoying.
It felt harder than it should’ve been, with more hidden obstacles than I anticipated (and I’ll bug them more about this soon at help-librejs!)
But looking in retrospect, there are a few hidden prizes too

  • Concatenating all my js and template files made pages load faster
  • Using the right content-type for json responses is always a good thing
  • Forcing yourself to know exactly what third party libs and licenses you’re using is a good thing

Free Software ftw! 🙂

Vixe!! Javascript tem getters e setters!

Outro dia “descobri” por acaso uma feature nova da linguagem.
Só eu que não sabia que javascript tinha uma sintaxe especial pra getters e setters?

Veja só, abre um console aí e digita o seguinte:

 o = {a:1}; //nada de mais
 o = {a:1, get x(){return this.a++;}}; //cuma???
 o.x
 o.x
 o.x
 o.a; //só eu que não sabia disso???

Interessante né.

A princípio eu pensei: “legal, mas não consigo pensar em muitas aplicações práticas pra isso.”

Até que bateu a idéia de fazer um binding AngularJS (usando ng-model) com uma property baseada em getter e setter. Como prova de conceito, imagina um controle de paginação, com um botão “ANTERIOR”, um input com o numero da página, e um botão “PRÓXIMO”. Veja como fica simples:

http://tonylampada.github.io/randomstuff/getters_n_setters.html

Não é o tipo de coisa que se usa todo dia, mas é bom saber 🙂

Async Manifesto – Será que o Agile está ultrapassado?

Outro dia meu amigo Edmundo mandou na lista dos desenvolvedores do QMágico:

http://asyncmanifesto.org/
Será que o Agile Manifesto já está ultrapassado?
Nós já seguimos muita coisa que esse manifesto está propondo.
O que acham?

Dei uma lida no manifesto, e isso me fez dar umas filosofadas a respeito.
Resolvi compartilhar minha resposta aqui no blog 🙂

Concorda? Discorda? Mete a caneta nos comentários aí 🙂

————————————————————————–

Bem legal. A idéia de diminuir a quantidade de reuniões é sempre bem vinda, principalmente entre nós programadores né 🙂

Mas, tua pergunta me fez dar umas filosofadas, que acho legal comptilhar.

Será que o Agile Manifesto já está ultrapassado?

Vamos ver:

Agile:

1. Individuals and interactions over processes and tools
2. Working software over comprehensive documentation
3. Customer collaboration over contract negotiation
4. Responding to change over following a plan

Async:

1. Modern tools and flexible work environments over meetings and office hours
2. Flexibility in prioritization over detailed planning
3. Comprehensive documentation over tribal knowledge

À primeira vista parece que o Async é mais um complemento do que um substituto pro Agile.
Por exemplo, olhando Agile2 + Async3, temos:

Working software > comprehensive documentation > tribal knowledge.

Só que não.

Lendo com mais calma o Async, vc nota que o “comprehensive documentation” se refere a coisas diferentes nos dois manifestos! – No meu entendimento pelo menos:

No Agile, ele fala de documentação que vc entrega pro cliente. Que eu concordo que é realmente uma parada secundária.
No Async, ele se refere a documentação que a gente consome internamente (como a nossa página de componentes!!), que estamos começando a perceber que tem um valor enorme!

Mas beleza, até aí nenhum conflito tb.

Mas quando vc olha pra Agile1 x Async1, eles parecem opostos, conflitantes, sim:

Agile1: people+interactions (=meetings?) > tools
Async1: tools > meetings

Né?

Eu já tinha pensado um pouco sobre isso pra falar a verdade…
Cada vez mais eu acho que processos e ferramentas são importantes demais – e o jeito que o Agile fala deles não parece fazer justiça ao tamanho dessa importância. Então nesse ponto, o Async1 me parece ser mesmo uma correção válida em cima Agile, sim.

Duas coisas que eu tentaria falar diferente no Async:

1) Acho que não tem nada a ver falar que o Scrum é uma encarnação do Agile. Apesar dessa ser uma interpretação comum da nossa indústria.
Na real, uma cultura ágil tem muito mais a ver com ENGENHARIA (TDD, Refactoring, Refactoring, já falei Refactoring?, Integração contínua, Deploy contínuo, etc) do que com GESTÃO (Scrum, Daily meetings, etc).
Quem acha que é ágil pq usa Scrum, tá fazendo isso errado.

2) É perigoso dizer “Document everything”!
Não. Tudo não, po! É pra documentar só o que precisa.
Acontece que o que precisa é bem mais do que o normalmente se documenta.
Mas isso é muito menos que “tudo”.
Isso dá margem pra que gerentes sem noção demandem um monte de documentação inútil.

[ ]’s!