20 Anos Depois, Ainda Não Entendemos Reusabilidade
23 abr
Eu tenho uma relação de amor e ódio com programação, e não estou exagerando: são poucas as coisas que me fazem ficar tanto tempo lendo um único texto, e também são poucas as coisas que já me fizeram passar tanta raiva e dizer “não, porra, não vou mais fazer isso”.
O que eu demorei a perceber, e só estou realmente aprendendo agora, é que na verdade existe uma parte da área de programação que eu amo, sou apaixonada. É a parte com a qual eu sempre sonhei trabalhar. Francamente? Eu acho que é a parte com a qual todos da área sempre sonharam em trabalhar.
É aquela parte na qual você tem de pensar, planejar o que irá fazer para criar uma solução elegante, boa e compreensível. Escrever um belo algoritmo e testá-lo. Juntar as peças de maneira lógica.
Eu me lembro de quando estava aprendendo a programar, em Pascal, no ensino técnico – a felicidade que eu sentia em pensar em maneiras de calcular as simples coisas que eram pedidas. Aquele sentimento de triunfo ao fazer seu primeiro algoritmo com recurso – que deve ter sido algo como calcular fatorial, já que este é um exemplo clássico de recursão.
Pensei “poxa, isso é realmente legal, será legal trabalhar com isso”.
Desilusões
Aí eu comecei a trabalhar, numa grande empresa de softwares de ERP para empresas – gerir informações de empresas, gerar folhas de relatório, de pagamentos… essas coisas. Mas aquilo… aquilo não era a programação. Programação para mim era planejamento, lógica – algo como, se a matemática diz “o que é”, a programação diz “como fazer”.
Não, não era aquilo que eu estava fazendo. Eu havia me tornado uma “code monkey”. O ponto mais baixo foi o dia no qual me falaram para abrir um documento, procurar ocorrências de uma string e substitui-la por outra.
Sério, leia a frase anterior de novo e me diga se você não morreu um pouquinho por dentro. A argumentação foi que eu deveria me acostumar com o fluxo de trabalho, como ler chamadas, realizá-las e fechá-las. Burocracia, enfim.
Eu pensei que fosse um caso isolado. Afinal, eu era recém-contratada, tinham me transferido para lá. Pensei que o problema fosse comigo, que talvez eu não gostasse de trabalhar com programação.
Mas, no fundo, eu ainda gostava da parte lógica, e a maneira que eu encontrei de tentar seguir essa parte foi fazer Engenharia de Controle e Automação. Afinal, juntava Informática com coisas como Eletrônica e Mecânica, então com um pouco de sorte eu nunca mais teria de ver um ERP na minha frente.
Avance alguns anos. Eu descobri que, francamente, não curto interação com Hardware.
Mas, pensando agora, talvez o meu problema não fosse com o Hardware, mas com o estado dele – era frustrante construir um mero circuito digital e ter de adivinhar se ele não estava funcionando por problemas do projeto ou se porque algum dos componentes estava queimado.
Comecei a fazer um projeto em Java e, por um tempo, as coisas até que fluiram. Entrei em um outro projeto e as coisas começaram a decair. Não que o projeto fosse ruim, longe disso, mas é que eu me vi tendo de aprender estranhas e místicas bibliotecas para fazer meu trabalho, e eu acabava passando a maior parte do meu tempo não mais tentando encontrar um bom algoritmo para resolver o meu problema, mas tentando descobrir porque diabos aquela biblioteca não estava fazendo o que eu queria.
Eu achava que isso se devia à minha inexperiência – afinal, eu era uma programadora iniciante, e havia uma série de conceitos com as quais eu não estava perfeitamente familiarizada.
Esse ano algumas coisas aconteceram e me fizeram rever minha posição – talvez o problema não esteja APENAS comigo.
Reusabilidade Do Que?
Eu pensava OK, eu tenho apenas uns conceitos básicos sobre Spring/Struts, deve ser por isso que minha aplicação vive quebrando. Eu já fiz alguns programas com Hibernate, mas agora isso não está funcionando e…
Vocês já programaram com alguma dessas bibliotecas/frameworks? Elas foram criadas para facilitar o seu trabalho, para manter um código mais claro e fácil de manter.
Fácil de manter se você fizer todos os místicos procedimentos de geração, de manutenção, de modificação, escondidos em cerca de vinte arquivos e definidos nas páginas 700 a 735 do Pequeno Manual do Desenvolver daquela framework. Tudo funciona muito bem, até você dar um passo em falso – e por passo em falso eu digo, mudar um parâmetro em um dos vinte arquivos de configuração, um método ali, ou até mesmo a ordem que você resolveu compilar/gerar seu código. E, quando você dá esse passo em falso, você sabe o que acontece?
Meu amigo, A SUA APLICAÇÃO VAI PARA O INFERNO.
Já aconteceu de eu olhar ara uma aplicação que não está funcionando e ficar me perguntando qual parâmetro estava errado. Às vezes era uma linha, uma mísera linha escondida no fundo de um dos milhares de arquivos daquela aplicação. Eu acabei fazendo o escambau naquela aplicação porque eu não conseguia entender como fazer uma pequena modificação em um dos módulos. Era uma modificação pequena, que não deveria ter levado tanto tempo para ser feito. Boa parte do tempo eu gastei me estressando, lendo e relendo documentação, wiki e tentando entender o que eu estava fazendo de errado.
Só agora eu começo a pensar que talvez eles estivessem errados. Eu queria fazer uma coisa simples, porque estava sendo tão difícil?
Ao mesmo tempo, porque ERP ainda são tão complicados? Eu entendo que eles sejam complexos, mas há quantos anos eles são desenvolvidos? Não deveria ser algo mais simples de manter hoje em dia? Certamente depois de um tempo 90~95% das funcionalidades de um ERP deveriam ser bem conhecidas e triviais, não?
Digo o mesmo sobre base de dados: quantos milhares de programas não envolvem alguma variação de manipulação de dados? Veja os dados, insira novos dados, delete dados, eventualmente visualize um relatório. A complexidade deveria estar toda em definir um bom modelo dos dados, não? E realizar alguns eventuais ajustes. Ainda assim, por isso ainda é tão complicado de ser feito? Por que algo que se tornou tão trivial ainda possui implementações tão… não-triviais?
Você pode argumentar, poxa, até em Java isso é rápido, se você for no Netbeans, você cria visualizações simples a partir de uma base de dados em questão de cinco minutos… com gerados de códigos.
Sim, claro, ao invés de fazer você mesmo o trabalho sujo, você manda a IDE fazer a porquice por você. E adivinha quem vai ter de fazer as modificações e dar manutenção no código depois? Não será a IDE, eu garanto.
Ah, a IDE tem várias ferramentas de teste, eu é que sou burra de não ter aprendido a usar isso tão bem quanto deveria.
Claro, ao invés de você mesmo sair cutucando o programa em “tentativa e erro”, mande a IDE fazer isso por você.
Gente, isso não são soluções. São bandaids criados para esconder um problema maior: a maioria das bibliotecas é uma droga. Prova disso é a quantidade de geradores de código que acompanham as IDEs mais modernas: é claro que existem certas tarefas um tanto quanto repetitivas, mas certamente criar uma aplicação base não deveria ser algo tão enrolado?
Certamente o que nós queríamos com reusabilidade não era “ah, eu escrevi 100 linhas e o IDE escreveu 1000″, ou “aprenda essas trocentas bibliotecas para fazer um belo Hello World”?
O Inferno Está Cheio de…
É claro que a idéia por trás de uma solução como Hibernate é interessante. Eu já desenvolvi um pequeno projeto com Hibernate e, tendo trabalhado com SQL puro antes, é difícil não reconhecer as vantages que uma solução como essa trouxe. Até certo ponto, quando eu falo que a maioria das bibliotecas é uma droga, não estou me referindo a algo como Hibernate (até porque Hibernate é uma framework, mas, enfim).
OK, certamente muitas bibliotecas/frameworks resolvem muitos problemas, e muitas delas representaram em bons ganhos de produtividade. Sob esse ponto de vista, nossa, as bibliotecas/frameworks são excelentes.
O maior problema é… bom, um dos maiores problemas é a gestão de complexidade. E o pior: na maior parte das vezes, existem boas técnicas para ajudar na gestão de complexidade, algumas conhecidas há mais de 20 anos, mas que muitos desenvolvedores insistem em ignorar!
Digamos que você tenha uma linguagem bem simples, na qual você queira criar… um círculo. Então você cria uma simples lista, criada assim, por exemplo:
c = Círculo(x,y,raio)
E pronto, c é o nosso círculo, com coordenadas e um raio. Simples, não? Aí você pensa “sou um gênio, vou transformar isso numa biblioteca” (para fins de exposição, imaginem que foi criado algo um pouco mais complexo).
E, poxa, é tão simples, não é mesmo? Três simples parâmetros, e você tem um círculo, será um sucesso.
Aí o fulano vai usar sua biblioteca e pensa “poxa, legal, vou criar um círculo”:
c = Círculo(raio)
Afinal, ele só quer definir um círculo, sem se importar com a sua posição. Esse exemplo pode parecer ridículo, mas vocês não imaginam quantas bibliotecas são EXTREMAMENTE RIGÍDAS (ou, infelizmente, imaginam por já terem se deparado com bibliotecas assim…). Mesmo em um caso assim, no qual os parâmetros x e y poderiam ser considerados opcionais, restando apenas o parâmetro obrigatório raio. Ou ainda, poderia ser possível criar um Círculo sem parâmetro algum, para alterar seus parâmetros mais tarde. Parece tão simples, e pode ser uma solução perfeitamente lógica para o desenvolvedor da outra aplicação, mas ele terá de fazer algum malabarismo como
c = Círculo (0,0,10)
Ao invés de
c = Círculo (10)
Simplesmente porque a biblioteca o obrigava a usar todos os parâmetros, mesmo quando isso não fazia sentido. Claro, nós estamos falando de algo simples como um círculo, e qualquer um que olhe para Círculo(0,0,10) poderá imaginar que se trata de um círculo de raio 10 na origem, mas na maior parte dos casos práticos não é algo tão óbvio.
É basicamente pegar toda a liberdade que uma linguagem de programação te dá e resolver limitá-la para funcionar apenas da maneira que os desenvolvedores da biblioteca imaginaram. Olhando por esse lado, eu nem sei como tantos militantes do software livre, da liberdade, podem aceitar certas frameworks e bibliotecas com tanto orgulho.
E, até certo ponto, isso não é tão surpreendente. Existem cadeiras em Ciências da Computação sobre como escrever boas bibliotecas? Eu imagino que existam bons livros, mas eles não costumam ser citados. Eu costumo ler sobre programação das mais diversas fontes, e diversos dos meus amigos são programadores, mas eu não costumo ler um artigo sobre a mais recente técnica para desenvolver uma boa biblioteca, e nem meus amigos costumam falar sobre o excelente livro de Desenvolvimento Avançado de Biblioteca que eles leram.
Então eu tenho motivos para desconfiar que as pessoas que estão desenvolvendo essas ferramentas também não tem um conhecimento tão aprofundado sobre desenvolvimento de bibliotecas quanto deveriam ter.
Biblioteca = Reusabilidade, só?
Eu imagino que deve ter gente pensando “O que ela está falando? Que coisa idiota, é claro que se ensina a escrever bibliotecas, só que sem esse nome – se ensina reusabilidade, orientação a objetos com fraco acoplamento…”
Sou obrigada a discordar. Tudo isso é NECESSÁRIO para escrever uma biblioteca – afinal, uma biblioteca deve ser um bom software antes de mais nada, certo?
Mas não é SUFICIENTE.
Digamos que você tenha escrito a sua biblioteca círculo para uso interno na sua empresa, e tudo funciona muito bem porque ela se aplica exatamente ao que você deseja.
E você a libera, mesmo com aquelas limitações, chamando-as de boas práticas.
Sabe o que é uma boa prática? Consistência. E pode ser um pouco difícil ter consistência se você estiver usando diversas bibliotecas, e cada uma te obrigando a seguir o que ela considera “boas práticas”.
Além disso, muitas bibliotecas e frameworks são terríveis no quesito gestão de complexidade. Você acaba tendo a impressão de que quem usa a biblioteca deve seguir a mesma escola de pensamento que o desenvolvedor, e deve ter um conhecimento tão profundo quanto o desenvolvedor se quiser fazer algo que fuja um pouco do escopo pretendido.
Sabe porque as bibliotecas incluídas na maior parte das linguagens não costuma ter esse tipo de problema? Uma das razões é que elas são escritas por pessoas realmente experientes, e a outra é que elas possuem funções mínimas e bem delineadas. Uma função vai fazer uma coisa, e você irá utilizá-la para ela fazer exatamente o que você precisa. Ao contrário de muitas bibliotecas e frameworks megalomanícos que querem funções para fazer tudo de uma vez e AI de você se quiser algo diferente.
Existem técnicas que ajudam nesse processo? Existem, inúmeras! Fraco acoplamento, Lei de Demeter, Don’t Repeat Youself… só para citar algumas que eu vi nos últimos dias.
Mas, francamente, porque desenvolver software tem se tornado tão complicado? Existem centenas de razões para isso, algumas que mal cheguei a citar nesse artigo (como as fábricas de software e seus macacos, que simplesmente acham que desenvolver software é juntar um monte de coisas e tentar juntá-las até ter algo que pode ser apresentado ao cliente) mas que costumam ser citadas na maior parte dos artigos. Eu quis atacar um pouco o outro lado hoje, o fato de que poderiamos não apenas ter culpados do lado do usuário, mas também dos desenvolvedores – que práticas hoje tão bem aceitas talvez não sejam tão eficientes quanto deveriam.
Mas claro, esses são apenas os devaneios de uma jovem programadora, e eu deveria até me desculpar por ter escrito um devaneio tão longo, mas eu precisava dizer essas coisas. Quem sabe vocês também não se sintam assim, não é mesmo? Eu mesma acabei decidindo escrever esse post depois de ler o artigo “Whatever Happned to Programming?” com quase o mesmo sentimento, mas de alguém muito mais experiente do que eu.
Então eu talvez não seja a única, e é isso o que me dá esperança de voltar a trabalhar na área de programação.
Mas antes disso, muito estudo
O Dive Into Python e o SICP não se lerão sozinhos…
