Programando com boas práticas – Parte 1: Este artigo apresenta algumas boas práticas de programação a serem levadas em consideração com a finalidade de incrementar a manutenibilidade e extensibilidade de códigos orientados a objetos. Boas práticas, já testadas e aprovadas, certamente irão tornar seu código mais robusto e flexível. Uma boa implementação deve não somente alcançar seus objetivos funcionais, mas também ser de fácil aprimoramento e compreensão.
Em que situação o tema é útil: Este tema é útil para desenvolvedores que
almejam aperfeiçoar seus conhecimentos em boas práticas de programação, como a abstração, reutilização, extensão
e desacoplamento de objetos e suas referências. Tais princípios facilitam tanto a criação de novos códigos como
a manutenção de outros já existentes, muitas vezes complexos de serem alterados por sua complexidade, forte
acoplamento e falta de coesão.
Boas práticas de desenvolvimento são técnicas criadas ao longo do tempo para aprimorar a qualidade de um código, facilitando sua manutenção e reuso. O uso de boas práticas, já testadas e aprovadas pela comunidade, reduz a probabilidade de um desenvolvedor eventualmente escrever códigos difíceis de terem suas funcionalidades estendidas, alteradas ou reutilizadas.
Algumas dessas práticas e princípios pregam que um código deve ser escrito uma única vez, de forma definitiva e sempre de acordo com seu objetivo funcional. Objetivo este que deve ser único, claro e preciso. Uma classe deve ser alterada somente caso haja alguma extensão em sua funcionalidade. Um código bem escrito, isolado, abstraído e coeso não precisará ser alterado por consequência de efeitos adversos ocasionados por uma ou mais modificações que tenham sido realizadas em outras partes da aplicação.
Mas e a refatoração? A refatoração tem como objetivo principal refazer algo que não foi feito da melhor maneira na primeira tentativa. A real necessidade de uma refatoração precisa ser avaliada caso a caso, levando em consideração seu custo e viabilidade. A refatoração tem sua finalidade e seu propósito. Códigos com determinadas lógicas repetidas em diferentes partes da aplicação podem precisar de refatoração para que tais duplicidades sejam eliminadas, proporcionando melhor manutenibilidade. Se ao desenvolver uma classe, por algum motivo o desenvolvedor não se satisfez com certa lógica, seja por sua complexidade, seja pela interdependência gerada entre diferentes partes da aplicação ou mesmo por sua dificuldade de reutilização, a refatoração é um bom caminho para o aperfeiçoamento. Códigos mal escritos geralmente requerem, em algum momento, refatoração para aprimorar sua estrutura interna (sua codificação), sem que se altere seu comportamento externo (o requisito funcional).
Uma eficiente refatoração certamente deve introduzir boas práticas de desenvolvimento e padrões de projeto, eliminando a necessidade de futuras novas refatorações. Se bem realizada, tanto uma melhor manutenibilidade como extensibilidade podem ser adquiridas com a refatoração. Contudo, o ideal é sempre iniciar um novo código já fazendo uso de boas práticas, incluindo padrões de projeto, evitando-se assim uma possível refatoração ou qualquer tipo de alteração que não esteja relacionada ao objetivo funcional do código (a razão de ser de uma determinada lógica, classe ou componente).
Alterações posteriores devem se restringir ao desenvolvimento de novas funcionalidades ou ampliar as já existentes, sempre de forma abstraída e desacoplada. Refatoração é sinônimo de retrabalho, e tem como foco principal refazer algo que não foi bem feito na primeira tentativa. Reescrever um código, mesmo que parcialmente, é algo que pode e deve ser evitado. Uma classe que faça referências apenas a interfaces, que esteja desacoplada de todo o resto, com objetivo claro, singular, e que faça uso de composição e abstração, dificilmente precisará de refatoração.
Como exemplo de ampliação de uma determinada funcionalidade sem a necessidade de refatoração ou reescrita, imaginemos uma classe, ou mesmo um componente de uma aplicação, responsável por realizar cálculos de contabilidade bastante complexos, que precisa ter o valor retornado por um de seus métodos alterado devido a uma nova lei trabalhista qualquer, por exemplo. Agora suponhamos que esse código já se encontre em ambiente de produção, por várias décadas, e que ao longo desse tempo tenha sofrido alterações pontuais em sua lógica por diversos times de programadores. Somando-se a isso, sabe-se que inúmeras dessas alterações foram implementadas de forma incorreta, não levando em conta futuras necessidades de alteração de sua lógica de negócio, e assim dificultando ainda mais sua compreensão e consequentemente sua manutenção. São em casos como esse que encontramos vantagens no uso de boas práticas de desenvolvimento para a extensão de funcionalidades, como na utilização do padrão Decorator, que cria uma camada superior à da função inicial, adicionando mais funcionalidades à mesma sem qualquer reescrita de código.
Ademais, como já brevemente mencionado e baseando-se nos princípios de coesão, reutilização e fraco acoplamento de funções, uma determinada classe deve representar um único propósito ou responsabilidade. Deste modo, evitam-se códigos confusos e com objetivos variados, que por sua vez dificultam a reutilização, manutenção e compreensão. Imagine como seria difícil reaproveitar algo que não possua uma funcionalidade específica e bem definida, ao contrário de algo com função singular e fortemente determinada. À vista disso, cada responsabilidade que uma classe possui torna-se uma área em potencial para futuras alterações de lógica. Quanto maior for o número de responsabilidades de uma classe, maior é a abrangência de código passível de alterações. E se cada uma dessas múltiplas responsabilidades estiver fortemente conectada, mais complexo será sua manutenção e menos óbvio sua clareza. Enfim, uma classe Bola deve ser responsável apenas por criar objetos bola, e não também chuteiras e uniformes.
Os princípios já elencados também nos ensinam que diferentes componentes, ou mesmo simples classes, devem conhecer o mínimo possível de todo o resto da aplicação. Uma classe Bola não precisa saber ou ter acesso à classe Uniforme, uma vez que a única função da classe Bola é criar bolas, que nada tem a ver com a classe Uniforme. Ainda, se um código somente tem acesso a outros códigos de forma abstrata (via interface), ele não será impactado se um ou outro código, ao qual ele faz uso, mudar. Tendo dito isso, é importante que uma classe apenas tenha referências abstratas e jamais faça uso de referências concretas. Objetos que interagem entre si devem fazê-lo de forma desacoplada.
Consequentemente, quando aplicável, prefira composição ao invés de herança, e torne seu código capaz de referenciar diferentes objetos sem a necessidade de recodificação, tanto em tempo de compilação quanto em tempo de execução. Igualmente, evite instâncias de objetos concretos, através do uso de interfaces.
Adicionalmente, separe e encapsule toda e qualquer funcionalidade que possa vir a variar ao longo do tempo. Assim será possível modificá-las separadamente sem a necessidade de modificar outras partes do código de forma desnecessária.
Abstraia, singularize e reutilize
Classes que referenciam outras classes devem realizar tais referências de forma abstraída, utilizando interfaces, sem a dependência de uma instanciação concreta. Quando se passa uma instância concreta de uma classe para outra – por exemplo, uma classe qualquer referenciando um objeto HashSet ao invés de referenciar sua interface Set –, o que se está fazendo é um acoplamento forte entre ambas, uma interdependência mútua. Isto deve ser evitado, do contrário a alteração em uma classe poderá ocasionar a necessidade de alteração em outra. Assim, uma classe que faz uso de uma HashSet deve referenciá-la através de sua interface Set, a fim de evitar o que chamamos de acoplamento forte entre objetos.
Apresentando a aplicação SysEmpresa, e seu modelo de classes
Antes de darmos prosseguimento ao artigo, vamos primeiro analisar o projeto SysEmpresa, criado com o propósito de exemplificar os princípios de abstração, singularização e reutilização. O projeto SysEmpresa é constituído basicamente de um conjunto de interfaces e suas respectivas classes. Neste cenário, IEmpresa é a interface para todas as classes do tipo “empresa” criadas no projeto. Tendo dito isso, a classe EmpresaA será a utilizada em nossos exemplos, porém outras classes empresas também poderiam ser implementadas, como EmpresaB, EmpresaC, entre outras. Cada uma dessas empresas, por sua vez, pode ter um ou mais departamentos, e todos os departamentos implementam a interface IDepartamento.
Assim sendo, em nossa EmpresaA, temos dois departamentos: DepartamentoA e DepartamentoB. E cada um desses departamentos possui instâncias das demais classes que compõem o projeto, a saber: Funcionario (que implementa a interface IFuncionario), PagamentoPJ e PagamentoCLT (que implementam a interface IPagamento) e PromoA (que implementa a interface IPromo). A interface e a classe referentes aos funcionários são responsáveis pelas funcionalidades inerentes ao cadastro de funcionários. Já a interface e suas duas classes pertinentes ao pagamento de funcionários serão utilizadas pelos departamentos da empresa para o cálculo dos salários nos regimes CLT ou PJ. Também há a interface e as implementações relativas a possíveis promoções que cada funcionário pode estar elegível. Mais à frente, no decorrer dos exemplos, criaremos outras classes, que estenderão a aplicação, referentes aos respectivos tópicos que serão abordados. Como complementação do que foi dito, vejamos o diagrama de classes, na Figura 1, referente ao projeto ...
Confira outros conteúdos:
Introdução ao JDBC
Novidades do Java
Teste unitário com JUnit
Promoção de Natal
Oferta exclusiva de Natal!
Pagamento anual
12x no cartão
De: R$ 69,00
Por: R$ 59,90
Total: R$ 718,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- 12 meses de acesso
Pagamento recorrente
Cobrado mensalmente no cartão
De: R$ 79,00
Por: R$ 59,90 /mês
Total: R$ 718,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- Fidelidade de 12 meses
- Não compromete o limite do seu cartão
<Perguntas frequentes>
Nossos casos de sucesso
Eu sabia pouquíssimas coisas de programação antes de começar a estudar com vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa bagagem consegui um estágio logo no início do meu primeiro período na faculdade.
Estudo aqui na Dev desde o meio do ano passado!
Nesse período a Dev me ajudou a crescer muito aqui no trampo.
Fui o primeiro desenvolvedor contratado pela minha
empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um
Full-Stack Dev!
Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a pena, pois a plataforma é bem intuitiva e muuuuito didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito obrigado!
Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento front-end, tinha coisas que eu ainda não tinha visto. A didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado, adorando demais.
Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É um passo a passo incrível. Só não aprende quem não quer. Foi o melhor investimento da minha vida!
Foi um dos melhores investimentos que já fiz na vida e tenho aprendido bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da programação, irei assinar meu contrato como programador graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana, aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem como não aprender, estão de parabéns!
Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na área.
Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.