O terceiro nível de abstração em programação
Programar para computadores é fácil, difícil é programar para pessoas. São as pessoas que devem entender o que o seu programa faz. O computador sempre faz o que você pede sem questionar. Quem geralmente questiona porque você fez de tal forma são os outros programadores e, muitas vezes, você mesmo. Assim, programar bem é quase o mesmo que escrever bem. Não é a toa que o que usamos para programar se chama linguagem – Linguagem de Programação. Uma parte do trabalho do programador é traduzir o algoritmo que resolve o problema para uma linguagem que o computador entenda. A outra parte e, provavelmente a mais importante, é saber se expressar de forma clara a fim de lidar mais facilmente com a complexidade.
Quase todo software é um grande problema a ser resolvido. E para resolver um problema precisamos ter conhecimento do seu universo de informações. Porém, um novo problema surge por uma limitação do nosso cérebro: a quantidade de informação que somos capazes manter na memória enquanto pensamos numa solução é limitada. Por isto, geralmente decompomos o problema em partes menores. Estas partes menores, depois de resolvidas, nos permitirão ignorar grandes quantidades de informação que de outra forma manteríamos como ruído na nossa memória enquanto tentamos solucionar o problema maior. Em outras palavras, as partes menores do problema encapsulam detalhes que não são pertinentes saber enquanto pensamos no problema maior. E porque estamos livres de pensar em todos estes detalhes ao mesmo tempo o grande problema se torna mais fácil de ser resolvido. Esta é a melhor arma do programador para lidar com a complexidade e se chama Abstração.
A abstração pode existir em níveis infinitos, mas eu considero que para lidar bem com a complexidade precisamos entender três níveis de abstração:
1. Abstração de linguagem de alto nível
2. Abstração do SDK da linguagem
3. Abstração dos objetos do domínio
O primeiro e o segundo nível de abstração geralmente são fornecidos para o programador. Uma linguagem de alto nível já é uma abstração de muitos detalhes de outras linguagens de mais baixo nível. O Java, que é uma linguagem de alto nível, abstrai detalhes de mais baixo nível como o tratamento de ponteiros do C, por exemplo. Isto porque se considerou no projeto da linguagem Java que este tipo de detalhe (trabalho com ponteiros) seria um ruído desnecessário que o programador teria que manter em sua mente enquanto pensava sobre o problema a ser resolvido.
Porém, mesmo as linguagens de alto nível possuem detalhes que podem ser considerados de mais baixo nível e por isto existem os SDKs. O SDK do Java oferece mais um nível de abstração que evita que o programador tenha que saber no detalhe o que é preciso fazer até mesmo para tarefas simples como imprimir uma mensagem no console – isto está encapsulado na classe “System”. Assim, os SDKs elevam ainda mais o nível das linguagens de alto nível fornecendo determinados serviços que deixam o programador mais livre para pensar naquilo que lhe é pertinente.
Por fim, existe a abstração que é responsabilidade do programador. Esta é a abstração dos objetos do domínio; os objetos que o programador cria para o seu negócio. O problema a ser resolvido pelo programador é adicionar itens num carrinho de compras e não adicionar “floats” para preços, “strings” para nomes e “ints” para quantidades numa “Collection”. Se o programador tiver que pensar em “floats”, “ints”, “strings”, “Collections”, etc. enquanto tenta resolver o seu problema ele estará ocupando espaço em sua mente com detalhes demais ao mesmo tempo e não estará lidando bem com a complexidade. Assim, o programador pode criar um Objeto que deixa as coisas num nível ainda mais abstrato. No caso do carrinho de compras o programador poderia criar algo do tipo ShoppingCart.add(item). Desta forma é possível ler um programa quase que em linguagem natural, o que permitirá ao programador pensar sobre o seu problema nos termos do seu negócio e não nos inúmeros detalhes técnicos. Isto reduz imensamente o overhead cerebral que nós mesmos criamos ao não usar bem a abstração e é como se nós tivéssemos criado o nosso próprio SDK com os objetos do domínio do problema que queremos resolver.
Este terceiro nível de abstração também é importante porque ao ler o seu programa outro programador precisa ter inicialmente um entendimento global da solução. Neste momento é suficiente saber que ShoppingCart.add(item) faz o seu trabalho e não como isto é feito. Mais uma vez (não me canso de repetir) isto evita que o outro programador tenha que manter em sua mente o modo como o carrinho de compras funciona enquanto tenta entender o Shopping virtual como um todo. Se ele quiser saber como o carrinho de compras especificamente funciona ele desce um nível na abstração e assim sucessivamente até chegar ao nível mais baixo que desejar.
Mas pior do que não criar os seus objetos do domínio é o programador usar instruções cada vez mais baixo nível para implementar funcionalidades de negócio. Lembro que certa vez eu mostrei para uns amigos a instrução “de baixo nível” ChangeWacher.watch() do SDK do Flex e isto se espalhou por todo o software que estávamos desenvolvendo. Não estou dizendo que não devemos usar instruções de baixo nível, mas a questão é onde usá-las. Se você está implementando um Caso de Uso ou uma User Story,quando você ou outro programador for ler o programa ele tem que se deparar, inicialmente, com algo no terceiro nível de abstração. O que o programador deve ler inicialmente ao ver o seu código são chamadas aos métodos e propriedades dos objetos do domínio do seu problema. Misturar estas chamadas com instruções de baixo nível como “ChangeWatcher.watch” não é uma boa prática. Afinal de contas, para quê eu preciso saber que alguém usou um “ChangeWatcher.watch()” quando tudo que eu quero saber é como o meu Shopping virtual funciona como um todo? Sempre que vemos uma instrução de mais baixo nível enquanto tentamos entender a implementação de uma funcionalidade de negócio somos obrigados a parar e tentar adivinhar porque ela foi usada daquela forma e naquele momento.
Conclusão: se tivermos que pensar em detalhes técnicos (ints, floats, Collections, etc.) enquanto resolvermos o nosso problema não estaremos usando o terceiro nível de abstração, o único de responsabilidade do programador. Ao trabalhar com o SDK e com linguagens de alto nível o programador pode resolver facilmente os problemas menores – os detalhes técnicos de implementação. Ao trabalhar com os objetos do domínio o programador pode resolver facilmente problemas maiores – os problemas do seu negócio. Assim ele consegue o nível de abstração necessário que lhe permite lidar melhor com a complexidade. Assim ele escreve programa para pessoas, não para computadores.


Excelente post!
Muito bom! se artigo! muito bem escrito!
Parabéns pelo post, excelente leitura, principalmente para mim que ainda estou iniciando minha carreira como programador, pois isso me ajudou muito a relacionar minhas idéias.