segunda-feira, 30 de junho de 2014

Os Princípios S.O.L.I.D. da POO

Introdução

Hoje em dia, quando falamos de programação de software, inevitavelmente estamos a falar de Programação Orientada a Objectos (POO). Torna-se pertinente perguntar o que é o design orientado a objectos (OO)? É sobre o quê? Quais os seus benefícios? Quais os seus custos? Apesar de virtualmente todos os programadores de software utilizarem uma linguagem Orientada a Objectos (OO), de alguma forma, muitos de nós utiliza estas linguagens sem saber porquê ou sem saber como retirar o máximo benefício delas.

De todas as revoluções que ocorreram na indústria do desenvolvimento de software, duas tiveram tanto sucesso que moldaram a nossa mentalidade de modo que as tomamos como um dado adquirido: Programação Estruturada e Programação Orientada a Objectos. Todas as principais linguagens de programação que usamos hoje em dia são fortemente influenciadas por estas duas disciplinas.

Mas, o que é necessário para fazermos Programação Orientada a Objectos?

Bem, podemos começar por dizer que temos que usar uma linguagem Orientada a Objectos (OO), como, por exemplo, Java, C#, C++, VB.NET. Mas só porque estamos a usar uma linguagem OO, só porque estamos a programar com classes, não quer dizer que estejamos a fazer POO. Ou pelo menos, não quer dizer que o estejamos a fazer da forma correcta. Muitas vezes os programadores não têm conhecimento dos princípios e fundamentos que são a base das disciplinas de que a linguagem de programação que estão a usar derivou.

Este artigo é assim sobre as bases da POO, sobre os Princípios da Programação Orientada a Objectos. Em específico, vamos analisar os princípios S.O.L.I.D., definidos por Robert C. Martin.

Conteúdo

Estes princípios focam-se nos aspectos de gestão de dependências da POO, i.e. a gestão do Acoplamento entre os módulos do software. O alto acoplamento é um problema que a maioria de nós já enfrentou. Sempre que temos que analisar algum pedaço de código legacy, somos confrontados com má gestão de dependências, resultando em software que é difícil de alterar, frágil e não reutilizável. Por outro lado, quando as dependências são bem geridas, resulta código com baixo acoplamento e o software é flexível, robusto e reutilizável. Então a gestão de dependências e este princípios, estão na fundação das características e facilidades que os programadores pretendem que o software tenha.

The Single Responsability Principle (Princípio da Responsabilidade Única)

Uma classe deve ter uma e apenas uma razão para mudar. Basicamente, isto significa que cada classe deve ter uma única responsabilidade e que a responsabilidade deve estar totalmente encapsulada pela classe. Todos os seus serviços devem estar estreitamente alinhados com essa responsabilidade.

Por exemplo, se criarmos uma classe que represente uma Encomenda, não queremos que essa classe faça a persistência dos dados para BD e que os exporte também para XML. Porquê? Porque se, mais tarde, quisermos mudar de BD ou alterar o esquema do XML, estamos a possibilitar que a alteração de uma responsabilidade obrigue à alteração de outra responsabilidade.

The Open/Closed Principle (Princípio do Aberto/Fechado)

As entidades de software (classes, módulos, funções, etc.) devem estar abertas para extensão, mas fechadas para modificação ou, dito de outra maneira, devemos ser capazes de estender o comportamento de uma classe, sem a modificar.

Em princípio, isto parece contraditório: como podemos fazer um objeto comportar-se de uma forma diferente  sem o modificar? A resposta: usando abstrações, ou colocando o comportamento (responsabilidade) em classes derivadas. Por outras palavras, ao criarmos classes base com funções “overridable” (que permitem substituição), podemos criar novas classes derivadas, que fazem a mesma coisa de forma diferente, sem alterar a funcionalidade base. Mais, se as propriedades da classe abstracta necessitam ser comparadas ou organizadas em conjunto, uma outra abstração deve lidar com isso. Esta é a base do argumento "manter privadas todas as variáveis ​​do objeto" (Encapsulamento).

The Liskov Substitution Principle (Princípio da Substituição de Liskov)

As classes derivadas devem ser substituíveis pelas suas respectivas classes base. Por outras palavras, métodos que usem referências a classes base, têm que ser capazes de usar objectos de classes derivadas, sem o saber.

Quando se faz a sobreposição de um método duma classe abstracta, este tem que ser implementado de forma correcta, na classe derivada. Ou, “quando se usa um objecto através do interface da sua classe base, o objecto derivado não deve esperar que essa utilização obedeça a pré-condições que sejam mais fortes do que aquelas requeridas na classe base". A ilustração sempre popular desta caraterística é o exemplo quadrado-rectângulo.

Nota: este princípio deve o seu nome a Barbara Liskov, que o enunciou inicialmente numa conferência em 1987.

The Interface Segregation Principle (Princípio da Segregação de Interfaces)

Devem-se refinar e criar interfaces específicos para cada cliente, ou, dito de outra forma, os clientes não devem ser forçados a depender de interfaces que não usam. Quando um cliente depende de uma classe que implementa interfaces que o cliente não usa, mas que são usados por outros clientes, então esse cliente vai ser afectado pelas mudanças que os outros clientes possam forçar na classe.

The Dependency Inversion Principle (Princípio da Inversão da Dependência)

Devemos depender de abstrações e não de concretizações. Abstrações não devem depender de detalhes. Os detalhes é que devem depender de abstrações. Isto está intimamente relacionado com o Princípio Aberto/Fechado, discutido anteriormente. Ao passar dependências (tais como conectores a dispositivos de armazenamento) para as classes, como abstrações, removemos a necessidade de programar para uma dependência específica.

A utilização de Dependency Injection é uma forma de seguir este princípio.

Este  artigos apresenta apenas uma breve introdução os princípios SOLID, pretendendo destacar a utilidade e vantagens da sua aplicação. Para um conhecimento mais aprofundado sobre o tema, recomenda-se a pesquisa e leitura da extensa bibliografia online.

domingo, 29 de junho de 2014

Quando a solução é o problema

Como evitar o excesso de engenharia e funcionalidades inúteis no software

Se só tiver um martelo, tudo se vai parecer com um prego.

Os engenheiros de software e designers acreditam que para criar e melhorar o software, basta exercer seu ofício. O produto sofre de baixo envolvimento dos utilizadores ou interrupções? Eles dizem: "Vamos para uma sala projectar uma solução no quadro branco". Existe uma crença ingénua e generalizada nesta área. A crença é que basta projecto e engenharia para resolver problemas. Esta crença mascara um ponto perverso: cada acto de projecto e engenharia, longe de ser uma de solução, é uma "intervenção numa situação complexa" [Baumer & Silberman, 2011].

Criar software é como a cirurgia

O software é subtil e complexo; miríades de componentes interagem num frágil equilíbrio de design, engenharia, marketing e utilizadores do mundo real. Na sua complexidade e inter-relação, o software é como o corpo humano. E apesar de todos os esforços de fazer a criação de software primitiva e matemática, é muito mais parecido com sangue e cirurgia intestinal. Risco, consequências imprevisíveis, e complicações ensombram cada procedimento.

A medicina moderna classifica este risco como "iatrogenia" – o dano não intencional que surge a partir do tratamento médico. Hoje em dia, a iatrogenia mata mais pessoas do que o cancro. Nos Estados Unidos, a iatrogenia mata entre 3 a 10 vezes mais pessoas do que os acidentes de viação. Mais, por mais estranho que pareça, só nos últimos tempos é que a medicina começou a salvar mais vidas do que aquelas que tira.

Em comparação com a disciplina da medicina, a engenharia de software ainda é jovem e imatura. Não é, portanto, nenhuma surpresa que o software moderno esteja cheio de funcionalidades e correções que fazem mais mal do que bem. Lembra-se do OpenSSL v1.0.1, ou a última actualização do sistema operativo que bloqueou o seu smartphone? A cura foi pior que a doença. Está na altura de se reconhecer a iatrogenia no software. Está na altura dos profissionais de software estudarem e prevenirem os efeitos nocivos do projecto e engenharia.

Não existe nenhum martelo

Os profissionais sofrem de deformação de domínio (deformação profissional), ou da “Lei do Instrumento”. Quando confrontados com um problema, tendemos a responder com o martelo que temos nas nossas mãos. Raramente nos questionamos se o problema beneficiariam ou não com as marteladas. Raramente nos questionamos se estamos sequer diante de um prego ou não. Como resultado dessa falta de questionar, a chamada "resolução do problema" é muitas vezes a "exacerbação do problema." Para superar a Lei do Instrumento devemos mudar a nossa mentalidade. A chave para essa mudança vem num soberbo e conciso artigo, “Quando a implicação é Não ao Projecto”:

"Em vez de imaginarmos que o projecto em tecnologia oferece soluções para os problemas de insustentabilidade, sugerimos pensar no projecto como uma intervenção em uma situação complexa." - Baumer & Silberman, 2011

Como parar com o excesso de engenharia

Faça três perguntas

Agora que entendemos projecto e engenharia como uma intervenção numa situação complexa, como podemos evitar o imprevisto e consequências não intencionais da intervenção? A resposta é que temos que fazer perguntas antes de desenhar um único pixel ou escrever uma única linha de código. Baumer e Silberman oferecem as seguintes três questões:

  1. "Poderia a tecnologia de ser substituída por uma abordagem low-tech ou não-tecnológica, igualmente viável a situação? “
  2. “Será que a intervenção tecnológica resulta em mais problemas ou danos do que a situação que está a abordar?”
  3. “Será que a tecnologia resolve uma transformação tratável computacionalmente
    um problema em vez de o problema em si? "
    (ou seja, é a tecnologia de um substituto pálido para a solução real)
Mude a cultura da sua organização

Se quiser evitar o excesso de engenharia e o empilhar de funcionalidades, os seguintes valores culturais serão construtivos:

  1. Valorize não fazer coisas. Inicie um debate na sua organização acerca de "menos é mais" [REWORK]. Evangelize esta mensagem numa forma que as equipas de software a possam apreciar.
  2. Explore a “extravenção”. É isso mesmo, explore que funcionalidades pode remover para melhorar o produto. Antoine de Saint Exupéry capturou a extravenção numa linha brilhante “a perfeição é finalmente atingida não quando não há mais nada a acrescentar, mas quando não há mais nada a retirar” (Se pretender uma abordagem mais formal à extravenção, consulte o artigo How to Cut Features and Enjoy it — 20+ questions to find the simplest design).
  3. Documente os caminhos não tomados. A fim de superar a Lei do Instrumento e evitar revisitar o mesmo terreno no futuro, documente o que não está a fazer e por que não está a fazê-lo. Coloque os caminhos não tomados no wiki, mesmo se todos os seus instintos lhe dizem para colocá-los numa gaveta de arquivo. Assim como a deformação de domínio nos encoraja a começar a martelar sem pensar, a deformação de publicação desencoraja-nos a documentar as coisas que nós não fazemos (a deformação de publicação é poderosa o suficiente para cegar a própria história. Consegue citar uma pessoa, viva ou morta, que seja celebrada por não ter feito algo?).

Continue a criar

Este artigo não defende o ludismo. Engenheiros e designers dão o seu melhor quando criam em território desconhecido. Este artigo defende uma mudança na perspectiva. Projeto e engenharia são intervenções em situações complexas. Praticar isto é praticar a humildade e precisão. O software, as pessoas que o utilizam e as situações que o criam são mais complexas do que pensamos que sejam. Espere resultados surpreendentes, não lineares, de cada intervenção. Lembrar-se disto é evitar iatrogenia no software. Primum non nocere, “primeiro não causar dano” é uma máxima global da medicina. Também se devia se tornar no grito de guerra de profissionais de software.

Bibliografia recomendada

Taleb, Nassim Nicholas, Antifragile: Things That Gain From Disorder, EUA, Random House, 2012

Este livro fornece um modelo de sistemas complexos que o ajuda a ver os contornos antes de intervir. "Em suma, qualquer coisa em que há intervencionismo ingénuo, ou melhor, mesmo apenas intervenção, terá iatrogenias." - Nassim Taleb

 

Tradução livre do artigo “When the solution is the problem”, de Aneesh Karve.

10 sugestões para melhorar a gestão do Tempo

De vez em quando, depara-mo-nos com programadores que se queixam de como é difícil arranjar tempo, na sua agenda diária, para aprender coisas novas. Apesar da vida moderna ser bastante movimentada, o mais frequente é as pessoas não possuírem vontade, energia e competências de gestão de tempo para lidar com a situação. Na maioria das vezes, esta falta de tempo deve-se ao facto das pessoas gerirem mal o seu tempo, de não terem qualquer estratégia para o gerir de forma eficaz.

Aqui estão 10 sugestões que nos podem ajudar a gerir o tempo de uma melhor forma.

Se aplicar estas sugestões, poderá gerir o seu tempo de uma maneira melhor do que antes. Não vamos ver quaisquer gráficos ou figuras extravagantes, que mais não fazem do que ter uma boa aparência no papel. Vamos ver simplesmente algumas sugestões práticas que poderá começar a usar de imediato.

1. Não aceite coisas maiores que a sua capacidade

Sejamos honestos – todos nós temos recursos limitados em termos de tempo, energia e capacidade para completar uma tarefa. Mesmo que queiramos completar mais tarefas, vai haver um limite para o que conseguimos realizar num dia.

Em vez de tentar terminar muitas tarefas, que não vão caber num só dia, tente apenas aquelas que cabem no seu “prato”. Se tentar realizar muitas tarefas de uma só vez, o mais provável é não conseguir termina-las todas no mesmo dia. E então este "fracasso" vai aumentar a pressão para completar as tarefas à pressa, no dia seguinte. Isto, por sua vez, pode causar mais erros do que o esperado e adiar ainda mais a conclusão das mesmas.

Assim, é importante identificar e começar apenas aquilo que conseguir terminar no  mesmo dia. Seja realista ao fazê-lo. Aplique bom senso e experiência prévia para concluir essas tarefas. Com alguma experiência, pode determinar o limite que é o ideal para si - não muito baixo (preguiça não permitida), nem muito alto (fadiga não permitida).

2. Planeie um dia de cada vez 

Um erro comum que algumas pessoas cometem é o de planear um longo período de tempo. Quanto maior o período, maior a probabilidade surgirem obstáculos inesperados.

Não planeie uma semana, por exemplo, porque algo inesperado pode surgir. Para começar, planeie apenas um dia (ou mesmo menos) de cada vez. Uma vez criado o plano, cinja-se a esse plano sob qualquer das formas. Muitas pessoas mudam de plano com muita frequência. Seja firme. Depois de gizar um plano, não o altere sob qualquer circunstância. Ao fim de algum tempo vai aprender a introduzir alguma flexibilidade na sua programação diária. Mas até lá seja rígido sobre o seu plano diário. Aprenda a dizer NÃO a tudo o que não esteja planeado.

3. Estabeleça prioridades para as tarefas

Simplesmente escolher tarefas para terminar num só dia não é suficiente. Também é necessário estabelecer prioridades. Nem todas as tarefas são igualmente importantes, o seu nível de urgência também é diferente. Baseado na importância e urgência é preciso definir alguma prioridade para cada tarefa.

Pode-se definir a prioridade de várias formas diferentes - numa escala de 1 a 10, ou de Baixa, Abaixo do Normal, Normal, Acima do Normal e Alta (valores tirados a partir da enumeração CacheItemPriority, do ASP.NET – Low, BelowNormal, Normal, AboveNormal, High). Lembre-se que estas prioridades são para as tarefas a serem concluídas num único dia.

Uma vez estabelecidas as prioridades, comece a executar as tarefas por ordem, da de maior prioridade para a de menor. Se não conseguir completar uma tarefa de baixa prioridade nesse dia, ela poderá passar para o dia seguinte e, eventualmente, subir na na ordem de prioridades.

4. Evite distrações

Deve aprender a evitar todos os tipos de distrações. Se estiver envolvido em algo urgente ou importante, diga às pessoas à sua volta para não o perturbar. Não pode esperar que elas tenham noção da sua urgência a menos que lhes diga especificamente. Aprenda a desligar o telemóvel. Além disso, desligue as notificações instantâneas de email e qualquer outro tipo de alerta. Não esteja a verificar o email a cada momento. Se está a fazer algo, não interrompa a tarefa em curso para responder a um email. Não ligue os headphones ao ouvido quando está a fazer algo importante.

Estas e muitas outras distrações causam perda de tempo. Embora possam ser apenas alguns segundos ou minutos, quando se acumulam, podem resultar numa considerável quantidade de tempo. O pior ainda, é que sua mente se afasta a cada distração e precisa de mais tempo para se voltar a concentrar na tarefa a ser concluída.

5. Faça uma melhor gestão do seu tempo online

Como programador de software, estará conectado à Internet durante uma grande parte do seu dia de trabalho. No entanto, só porque tem uma ligação à Internet não significa que deva permanecer sempre online. Muitas pessoas têm o hábito de verificar os emails com frequência e de fazer log-in no Facebook ou Twitter de vez em quando. Isto é desnecessário. Crie o hábito estrito de aceder a emails e redes sociais numa altura específica do dia. Defina também a frequência de verificar estes recursos. A jornada de trabalho tem, normalmente, um "horário nobre", onde o seu nível de energia e produtividade é mais alto. Não gaste este horário nobre na verificação de emails ou nas redes sociais. Algumas coisas que podem ajudar incluem:

  • Só porque um email chegou à sua caixa, não quer dizer que lhe deva responder imediatamente. Não ponha de lado a tarefa que está a executar, agende a resposta ao email para mais tarde.
  • Decida a prioridade e importância para os emails. Isto é especialmente importante se receber dezenas de mensagens todos os dias. Use filtros de email para guardá-los em pastas separadas e depois olhe para eles de acordo com o horário programado.
  • Aprenda a limpar os seus feeds de notícias em sites de redes sociais, como o Facebook.
  • Utilize algum plugin de redes sociais para melhorar a sua experiência no Facebook e Twitter.
  • Faça uma pequena lista de sites/blogs que são importantes e úteis para o seu trabalho diário ou para actualizar o seus conhecimentos. Em vez ter que ler centenas de sites diferentes, mantenha um olho nas actualizações destes sites selecionados.
  • Desligue todos os alertas ou notificações instantâneas. Isso inclui email e sites de redes sociais.
  • Durante a leitura de um conteúdo online é fácil dispersar-se perante a pilha de informação. Mantenha-se focado. Faça questão de se manter no tópico original que estava a ler/pesquisar.

6. Faça uma melhor gestão do seu tempo em viagem

Se viver numa cidade como Luanda (ou Londres, ou Lisboa, …), o mais provável é que gaste uma quantidade considerável de tempo a viajar – da sua casa para o escritório e de volta para casa. Este tempo é pouco produtivo, mas pode utilizá-lo de uma forma mais eficaz. Escolha um meio de locomoção que seja confortável. Por exemplo, em vez de ir em viatura própria, opte por um autocarro de carreira, climatizado e apanhe-o numa paragem onde consiga ir sentado. Porquê? Uma vez que está numa posição confortável, pode pensar nalgumas formas criativas de utilizar o tempo de viagem. Aqui estão algumas sugestões:

  • Leve um leitor multimédia portátil para ouvir/ver áudio, vídeos e podcasts no caminho.
  • Dê uma vista de olhos a um livro ou revista técnica, que adicione novos conhecimentos.
  • Leve um bloco de notas e uma caneta. Anote, desenhe, visualize conceitos relacionados com o seu trabalho ou coisas novas que viu. Isto vai permitir-lhe rever o que aprendeu.
  • Durma. Não é brincadeira. Há muitos programadores que não dormem o suficiente à noite, devido a várias razões (porque vão tarde do escritório para casa, antecedentes familiares, meio ambiente, etc.). Se não pode fazer mais nada para utilizar o tempo de viagem, aproveite para induzir relaxamento e descanso no seu corpo. Use um pouco de técnicas de yoga, para relaxar durante este tempo. O corpo recargado é mais eficiente na realização de tarefas, uma vez chegado ao escritório ou a casa.

7. Estabeleça as expectativas das pessoas à sua volta

As pessoas à sua volta, no escritório ou em casa, têm certas expectativas sobre si. Essas expectativas são definidas com base na forma como interage com elas diariamente. Por exemplo, uma pessoa que está sempre a ajudar os outros, cria essa mesma expectativa nas pessoas ao seu redor. Então, se um dia essa pessoa não ajudar, as outras pessoas acham estranho e podem mesmo desenvolver sentimentos negativos sobre ela. Elas costumam facilmente esquecer todas as ocasiões em que essa pessoa as ajudou e lembrar-se apenas desta ocasião, quando não prestou a sua ajuda.

Se o seu comportamento indica que está sempre disponível quando as pessoas precisam de alguma coisa (seja importante ou não, não interessa), então elas vão esperar sempre o mesmo comportamento. Tem que os avisar que não gosta de ser perturbado quando está a fazer algo importante. Não pode assumir que as pessoas vão saber o significado da tarefa que está a fazer, automaticamente. É necessário transmitir especificamente a necessidade de estar sossegado e também dizer-lhes porque que é que a atividade é importante para si. Por exemplo, em vez de simplesmente dizer aos seus familiares para não o perturbar, pode explicar-lhes como o conseguir terminar a tarefa que tem mãos o vai ajudar e à sua família (digamos para uma promoção, ou aumento salarial, ou um novo emprego). Aqui estão algumas coisas a ter em consideração:

  • Aprenda a dizer NÃO.
  • Aprenda a delegar tarefas.
  • Se lhe estão a ser atribuídas muitas responsabilidades, avise as suas chefias, de forma adequada.
  • Nas relações profissionais, é bem aceite recusar-se educadamente a participar em eventos pessoais. Se estiver a tornar-se mais íntimo de uma dada pessoa, pode achar que é difícil dizer-lhe NÃO.
  • Não permita que os outros o pressionem ou forcem a participar em algo que vai afetar os seus horário e a sua agenda, previamente planeada.
  • Transmita a importância de terminar atempadamente uma tarefa que tenha em mãos, aos seus familiares. Depois de completar a tarefa, passe algum tempo de qualidade com eles.

8. Evite sonhar acordado e conversas sem importância

Quando estiver a realizar uma tarefa não permita que a sua atenção se desvie. Se tem que pensar sobre algo não relacionado com a tarefa atual, primeiro termine a tarefa e, em seguida, passe algum tempo a pensar sobre o assunto, antes de se concentrar de novo no seu trabalho. Faça questão de evitar conversa desnecessária ou de circunstância. Aprenda a desligar o seu telemóvel enquanto completa alguma tarefa importante. Muitos programadores costumam manter alguma aplicação de mensagens instantâneas (Skype, Google ou Facebook Messenger) a correr em segundo plano, enquanto fazem o seu trabalho. De vez em quando, mudam para essa aplicação, para participar em alguma conversa. Aprenda a evitar essas distrações.

9. Aumente o seu nível de energia

A gestão de tempo não é apenas a criação de horas disponíveis para fazer algum trabalho. É igualdade importante possuir a energia necessária para completar as tarefas. De fato, se o seu nível de energia é alto, pode realizar muito mais trabalho num determinado período de tempo. Para aumentar o seu nível de energia três coisas são importantes - dieta, sono e respiração (prana). Faça uma dieta saudável, coma alimentos naturais e que consiga digerir facilmente. Durma o bastante. Se possível durma uma pequena sesta retemperadora, durante a tarde. Por exemplo, o Yoga tem muitos tipos de exercícios de respiração (Pranayama), para revitalizar todo o sistema de energia no corpo. Aprenda-os a partir de algum especialista e torne-os parte de sua rotina diária.

10. Mantenha-se em forma

Isto pode soar como não relacionado com o tema do artigo. No entanto, a sua aptidão física e mental desempenham um papel vital na gestão do tempo. Um equipamento mente-corpo não saudável não se pode concentrar na tarefa em mãos. Ele não consegue gerar bons níveis de energia e, como resultado, você acaba por não cumprir os prazos. Exercitar-se diariamente e manter-se em forma é um aspecto importante de uma vida em plenitude. Exercícios como caminhada rápida, jogging, corrida, natação ou yoga são todos adequados a aptidão física geral. Se está adoentado, consulte um médico especialista imediatamente e elimine a raiz do problema o mais breve possível. Um indivíduo saudável é capaz de realizar muito maior quantidade de trabalho, num determinado período de tempo, em comparação com uma pessoa não saudável ou em baixa forma física.

Tradução livre do artigo “10 Tips For Better Time Management”, de Bipin Joshi.

Nota: Na tradução optei por usar o masculino, não com qualquer intenção de discriminação, mas apenas como facilidade de linguagem.

quinta-feira, 26 de junho de 2014

Compreender a “Dependency Injection” (I)

Introdução

Ao ler documentos, artigos ou livros sobre programação, com certeza já se deparou com o termo Dependency Injection (Injecção de Dependência).

Mas o que é exactamente Dependency Injection (DI)? E porque queremos usar DI?

Acontece que a DI é um pattern extremamente útil para o desenvolvimento de aplicações, com algum grau de complexidade. Em pequenas aplicações, o uso da DI tem um benefício reduzido, podendo, mesmo, criar complexidade desnecessária.

O principal resultado da utilização de DI é a obtenção de um sistema com Baixo Acoplamento (loose coupling), o que resulta em benefícios em termos de extensibilidade, testabilidade e late binding.

Compreender a Dependency Injection

Vamos iniciar uma série de artigos que nos ajudarão a compreender o que é a DI e os seus benefícios e veremos alguns exemplos de aplicação.

Parte I – Apresentação e Conceitos Base (este artigo)
Parte II – Introdução prática da DI
Parte III – Boa programação da DI
Parte IV – Contentores IoC – Exemplos de Aplicação

Nesta primeira parte, vamos começar por especificar alguns dos conceitos base relacionados com a DI.

Na segunda parte, através da análise de exemplos simples, vamos motivar a introdução do conceito de DI e verificar alguns benefícios da sua utilização. Na primeira parte, temos uma descrição mais teórica dos conceitos, na segunda, vamos introduzir a DI na prática.

Na terceira parte, vamos analisar algumas armadilhas quando se tenta gerir dependências. Vamos verificar como o desenvolvimento convencional nos pode deixar com código fortemente acoplado (mesmo quando pensamos que temos uma boa separação de conceitos). Vamos ver então como a adição da DI permite resolver este problema.

Finalmente, vamos apresentar alguns Contentores de IoC, com exemplos de configuração e aplicação.

Ao longo dos artigos serão feitas referências aos princípios S.O.L.I.D., que consistem num conjunto de 5 princípios da Programação Orientada a Objectos (POO), definidos por Robert C. Martin. Não entraremos em detalhes sobre estes princípios, sendo isso tratado futuramente noutro artigo.

Esta série de artigos apresenta apenas uma pequena introdução à DI, pretendendo destacar a utilidade e vantagens da sua utilização, bem como alguns exemplos de aplicação. Para um conhecimento mais aprofundado sobre o tema, recomenda-se a pesquisa e leitura da extensa bibliografia online.

Conteúdo

O que é a Dependency Injection

Um dos problemas com a DI é que existem dezenas de definições diferentes, que provocam uma confusão que se alastra à terminologia, objectivos e mecanismo.

Uma definição possível é a seguinte:

A DI é um padrão de desenho de software que permite que a escolha de componentes seja feita em run-time, ao invés de compile-time.

Infelizmente, esta definição, embora formalmente correcta, está um pouco incompleta. Menciona decisões em run-time (também chamadas de late binding), mas a DI é muito mais do que isso.

Vejamos outra definição:

Dependency Injection é um conjunto de princípios e padrões de desenho de software que nos permitem desenvolver código com Baixo Acoplamento.
Seemann, Mark, Dependency Injection in .NET, Manning, 2012

Esta definição é muito melhor. A DI tem tudo a ver com a criação de sistemas com baixo acoplamento, o que permite o late binding, entre outras coisas.

Então, o que pretendemos, nesta série de artigos, é ver como podemos criar código com Baixo Acoplamento.

Baixo Acoplamento, porquê?

Porque devemos criar código com baixo acoplamento?
Porque isso nos oferece uma preciosa ajuda numa quantidade de áreas. Eis algumas:

Extensibilidade
Extensibilidade representa a facilidade em adicionar novas funcionalidades ao código. A palavra "facilidade" significa que podemos fazer actualizações em locais específicos, sem que isso signifique ter que actualizar pedaços ao longo de todo o código base.

Late Binding
Conforme já mencionado, late binding é a capacidade de escolher quais os componentes que usamos em runtime, em vez de compile-time. Isto só é possível se o código tiver baixo acoplamento – o código só se preocupa com abstrações em vez de um tipo concreto em particular. Isso permite trocar componentes sem a necessidade de modificar o código.

Desenvolvimento Paralelo
Se o código tiver baixo acoplamento, torna-se mais fácil ter várias equipas de desenvolvimento a trabalhar no mesmo projeto. Podemos ter uma equipa a trabalhar na camada de negócio, e outra a trabalhar na camada de serviços. Como as camadas são independentes, as equipas estarão a trabalhar em código fonte diferente, que não afeta diretamente o outro.

Facilidade de Manutenção
Quando os componentes são independentes, a funcionalidade é isolada. Isto significa que se for necessário descobrir bugs ou ajustar a funcionalidade, sabemos exatamente onde procurar.

Testabilidade
Os Testes Unitários (Unit Testing) são um tema extremamente importante. O principal objetivo é testar pequenas unidades de código em isolamento. Quando temos código com baixo acoplamento, podemos facilmente criar dependências simuladas (mock/fake), de modo que podemos facilmente isolar as partes do código que realmente desejamos testar.

Inversion of Control (IoC)

Muitas pessoas referem-se a DI como Inversion of Control (Inversão de Controlo). Estes dois termos são por vezes usados ​​como sinónimos, mas DI é um subconjunto de IoC. Cabe aqui fazer uma pequena desambiguação entre os conceitos DI e IoC.

O termo Inversion of Control, originalmente, significava qualquer estilo de programação onde uma framework global ou o próprio runtime controlava o workflow de execução da aplicação. Isto era o oposto do que acontecia na programação procedimental.

Quando desenvolvemos uma aplicação web, seguimos o lifecycle das páginas ASP.NET, mas não estamos no controlo, a framework do ASP.NET é que está. Quando desenvolvemos um serviço WCF, podemos estar a escrever o código do serviço, mas não estamos no controlo, a framework WCF é que está.

Hoje em dia estamos tão habituados a utilizar frameworks (muito comuns na programação .NET, ou Java), que deixou de se dar um significado especial, mas não é a mesma coisa que ter o controlo total da execução, como acontece, por exemplo, numa aplicação de linha de comandos, mesmo no mundo .NET.

Antes da DI ter um nome definido, era comum chamar-se às frameworks que geriam dependências como Inversion of Control Containers e rapidamente o termo IoC passou a subentender-se como inversão de controlo sobre dependências. Mais tarde Martin Fowler introduziu o termo Dependency Injection para designar especificamente IoC no contexto de gestão de dependências. Desde então, DI tem sido aceite como a terminologia mais correcta.

Em resumo, IoC é um termo mais abrangente, que inclui, mas não está limitado à DI.

Padrões de desenvolvimento de Dependency Injection

A implementação da DI pode ser executada recorrendo a um variado número de design patterns:

  • Contructor Injection
  • Property Injection
  • Method Injection
  • Ambient Context
  • Service Locator

Nesta série de artigos vamos olhar em especial para a Constructor Injection, que é o principal padrão utilizado. O leitor poderá debruçar-se sobre os outros padrões, quando se sentir mais confortável com a DI.

Isto pode parecer um pouco complexo e poderá estar a equacionar se realmente vale a pena envolver-se na DI. Na realidade, estes padrões e princípios não são assim tão complicados. Vamos efectuar calmamente o nosso caminho, de modo a termos uma boa ideia do que vai acontecendo.

No próximo artigo: Compreender a “Dependency Injection” (II), as coisas vão ficar um pouco mais claras, quando começarmos a criar componentes e a aplicar a DI, verificando as suas vantagens.