sábado, 28 de setembro de 2013

O que é um programador profissional?

A característica mais importante de um programador profissional é responsabilidade pessoal. Programadores profissionais assumem responsabilidade por suas carreiras, suas estimativas, seus compromissos com o cronograma, seus erros, e sua criação. Um programador profissional não passa essa responsabilidade para os outros.

  • Se você é um profissional, então você é responsável por sua carreira. Você é responsável por ler e aprender. Você é responsável por estar atualizado com a industria e a tecnologia. Muitos programadores sentem que é responsabilidade de seus empregadores treiná-los. Desculpe, isso está simplesmente errado. Você acha que médicos se comportam assim? Você acha que advogados se comportam assim? Não, eles se treinam em seu próprio tempo, e com seu próprio dinheiro. Eles passam muitas de suas horas vagas lendo artigos e decisões. Eles se mantém atualizados. E assim devemos fazer. O relacionamento entre você e seu empregador é bem descrito no seu contrato de trabalho. Em resumo: seus empregadores se comprometem a lhe pagar, e você se compromete a fazer um bom trabalho.
  • Profissionais assumem responsabilidade pelo código que escrevem. Eles não liberam código a menos que saibam que funciona. Pense sobre isso por um minuto. Como você pode considerar-se um profissional se pretende liberar código sobre o qual não está seguro? Programadores profissionais esperam que o QA não encontre nada por que eles não liberam seu código até que o tenham testado por completo. Claro, QA sempre encontra algum problema, por que ninguém é perfeito. Mas como profissionais, nossa atitude deve ser não deixar nada para o QA encontrar.
  • Profissionais são jogadores de equipe. Eles assumem responsabilidade pela entrega de todo o time, não apenas pelo seu próprio trabalho. Eles ajudam um ao outro, ensinam um ao outro, aprendem um com o outro, e até mesmo substituem um ao outro quando necessário. Quando um colega de equipe está mal, os outros intervêm, sabendo que um dia serão eles que precisaram de ajuda.
  • Profissionais não toleram grandes listas de bugs. Uma lista de bugs enorme é desleixo. Sistemas com milhares de issues em sistemas de issue-tracking são tragédias do descaso. De fato, em muitos projetos, a simples necessidade de um sistema de issue-tracking já é um sintoma de descaso. Apenas sistemas muito grandes deveriam ter uma lista de bugs tão longa que alguma automação seja necessária para gerenciá-la.
  • Profissionais não fazem bagunça. Eles tem orgulho de sua criação. Eles mantém seu código limpo, bem estruturado, e fácil de ler. Eles seguem padrões acordados e boas práticas. Eles nunca, jamais se apressam. Imagine que você está tendo uma experiência fora do corpo assistindo um médico realizando uma cirurgia em seu coração aberto. Esse médico tem uma deadline (no sentido mais literal). Ele deve finalizar antes que a máquina de circulação artificial danifique demais as suas células vermelhas. Como você quer que ele se comporte? Quer que ele se comporte como um típico desenvolvedor de software, correndo e fazendo bagunça? Quer que ele diga, "Voltarei e corrigirei isso depois"? Ou quer que ele se atenha cuidadosamente a suas disciplinas, tomando seu tempo, confiante que sua abordagem é a melhor abordagem que ele pode razoavelmente tomar. Você quer uma bagunça, ou profissionalismo?
Profissionais são responsáveis. Eles assumem responsabilidade por suas carreiras. Eles assumem responsabilidade por fazerem seu código funcionar apropriadamente. Eles assumem responsabilidade pela qualidade de sua criação. Eles não abandonam seus princípios quando as deadlines os assombram. Na verdade, quando a pressão monta, profissionais se atém ainda mais forte às disciplinas que eles sabem serem corretas.

Robert C. Martin (Uncle Bob)

97 Things Every Programmer Should Know: Collective Wisdom from the Experts, Kevlin Henney, O'Reilly Media, Fevereiro de 2010, pág. 134.

quinta-feira, 25 de julho de 2013

Substituindo SVN por Git

Após alguns anos trabalhando com ferramentas de controle de versão centralizado, como StarTeam e Subversion (SVN), e já tendo feito algumas experiências com Mercurial e Git, usando BitBucket e GitHub como repositórios remotos, decidi iniciar um novo projeto usando Git, no entanto configurando meu próprio repositório remoto.

Numa empreitada como esta, três desafios normalmente precisarão ser superados:

  1. Configurar um repositório remoto e um repositório local e colocá-los para conversar educadamente. Essa tarefa é bem fácil e detalho mais adiante.
  2. Convencer os membros da equipe, acostumados com a comodidade do TortoiseSVN e com um processo de commit mais simples, que Git irá facilitar a vida deles, não o contrário. Isso também não será difícil, e há um modo suave de se fazer essa transição, que apresentarei a seguir.
  3. Convencer a empresa a aceitar os riscos de substituir o já conhecido SVN pelo Git, ainda que apenas num primeiro projeto. Isso será um pouco mais difícil, mas há algumas alternativas, caso isso não possa ser feito.

Para solucionar o primeiro problema, basta seguir este simples script:

  • Instale o Git, ou "GitHub for Windows", no servidor que será usado como repositório remoto.
  • No servidor onde o Git foi instalado, escolha uma pasta para hospedar o repositório remoto.
  • No Git Shell, navegue para a pasta escolhida e inicialize o repositório remoto com "git init --bare".
  • Instale o Git, ou "GitHub for Windows", em uma estação de trabalho.
  • Nessa estação de trabalho, escolha uma pasta para hospedar o repositório local.
  • No Git Shell, navegue para a pasta escolhida e inicialize o repositório local com "git init".
  • Monte dentro desse repositório a estrutura de pastas para o projeto.
  • Adicione a estrutura do projeto no git com "git add .".
  • Comite os arquivos recém adicionados no git, com "git commit -m 'Primeiro Commit'"
  • Configure o repositório remoto a ser usado pela estação de trabalho com "git config remote.origin.url endereço_do_repositorio_remoto".
  • Envie seu primeiro commit para o repositório remoto com "git push origin master"
  • Concluído. A partir agora você já poderá usar seu repositório local enviando os commits para o repositório remoto.
Para convencer a equipe a ao menos experimentar o Git, pode ser necessária muita conversa sobre as diferenças entre sistemas de controle de versão centralizados e distribuídos.

Apresentar a eles o "Git Game"  também pode ser útil.

No caso de equipes acostumadas a não usar ferramentas de linha de comando, esta será provavelmente a principal barreira. Para isso há duas ferramentas, em ambiente Windows, que podem ajudar. A primeira seria o TortoiseGit, semelhante ao provavelmente já conhecido TortoiseSVN, e a segunda o "GitHub for Windows". Quando trabalho com SVN, utilizo o TortoiseSVN, no entanto nas experiências que já fiz usando o GitHub usei o "GitHub for Windows", e esta será a ferramenta que usarei neste novo projeto.

Fica claro, pelo que disse acima, que o "GitHub for Windows" pode ser usado sem problema com repositórios remotos que não sejam repositórios do GitHub. Phil Haack, desenvolvedor da ferramenta, já falou sobre isso, no entanto utilizando um outro provedor de repositórios remotos, no caso o CodePlex. No nosso caso, precisamos usar o "GitHub for Windows" com um repositório remoto disponível na nossa intranet.

A configuração desse repositório remoto já foi feita acima, e sua utilização com o "GitHub for Windows", não poderia ser mais simples. Basta arrastar o repositório local, já configurado para enviar os commits ao nosso repositório remoto, para dentro da janela do "GitHub for Windows" e clicar no botão "Publish". A partir dai o botão "Sync" ficará disponível e poderá ser usado para sincronizar o repositório local com o repositório remoto. O uso dessa ferramenta pode tornar a aceitação do Git pela equipe bem mais simples.

Já para o terceiro desafio, o processo de convencer a empresa a experimentar o Git pode ser o mesmo usado com a equipe, ressaltando principalmente os ganhos de produtividade devidos a melhor performance e a maior segurança caso um desastre aconteça com o repositório remoto.

No entanto, caso a empresa se mantenha relutante, nada impede o uso misto de Git e SVN. Para isso pode ser usada a ferramenta "git svn", ou simplesmente usar um repositório local Git, e ter todas as vantagens que esse repositório local oferece, como a possibilidade de fazer vários commits, reverter alguns deles e "reordená-lo" antes de enviar ao repositório remoto, e um repositório remoto SVN, sendo sincronizado com o repositório local do modo tradicional. Ou seja, você trabalha localmente com Git até que seu código esteja em condições de ser compartilhado com a equipe, e nesse momento faz esse compartilhamento através de SVN, normalmente. Obviamente que com essa última abordagem, assim como com o uso de "git svn", muitas das vantagens do Git serão perdidas, mas ao menos você poderá fazer uso de parte delas.

terça-feira, 18 de junho de 2013

Novas Linguagens e Ambientes de Execução

Ultimamente tem sido crescente a discussão sobre JavaScript e linguagens que "compilam" para JavaScript, como CoffeeScript, TypeScript e outras. Já testei algumas dessas linguagens e todas elas, na minha opinião, são incrivelmente superiores em muitos aspectos ao JavaScript.

Outra questão que vejo ser abordada com frequência recentemente é o uso de Node.js, um framework realmente fantástico, performático, incrivelmente escalável e totalmente assíncrono. Mas que no entanto só entende uma linguagem: JavaScript. Obviamente as linguagens que compilam para JavaScript podem ser usadas ao se trabalhar com Node.js, mas nativamente não são suportadas, ainda.

Outro ambiente de execução que tem sido muito bem avaliado é a máquina virtual Erlang. No entanto, a linguagem Erlang em si é monstruosamente horrorosa e até o momento a melhor tentativa de ser executar uma outra linguagem sobre essa máquina virtual tem sido a Elixir.

No caso da gigante JVM, já faz algum tempo que a comunidade Java começou a admitir que a linguagem Java é uma linguagem verbosa demais, improdutiva e deficiente em muitos aspectos. Como resposta a isso surgiram Scala, Groove, Clojure, Kotlin. Todas essas, linguagens que são executadas sobre a JVM, trazendo muitas vantagens quando comparadas com sua matriarca, Java. 

No mundo .NET, diversas linguagens em um único ambiente de execução já é algo que existe desde sua concepção e com certeza parte da inspiração para a criação de novas linguagens executando sobre a JVM e compilando para JavaScript vieram dai.

A competição, a necessidade e principalmente a insatisfação tem levado ao surgimento de ao menos uma nova linguagem a cada ano, no entanto falta a essas linguagens, e principalmente a suas máquinas virtuais, a visão de que para ganhar mercado, a linguagem não precisa ser apenas universal e performática, precisa também ser produtiva, agradável de se usar.

Imaginem poder executar CoffeeScript diretamente sobre o Node.js ou nos navegadores web, ou código Ruby ou C# sobre a máquina virtual Erlang. Certamente o crescimento e a popularidade desses ambientes cresceria bastante.

Isso me lembra o projeto Singularity, mas isso fica para um próximo post.

segunda-feira, 3 de junho de 2013

C#, Java e os Enums - Parte 3

No último post apresentei a implementação Java do State OnOff, usando os Enums do Java 1.5.

Abaixo você pode ver a minha implementação para o padrão State em C#, seguindo o mesmo modelo visto na versão Java.
public abstract partial class OnOff {
    public partial class OnState : OnOff {
        public override string DisplayText {
            get { return "Ligado"; }
        }

        public override OnOff Switch() {
            return OnOff.Off;
        }
    }

    public partial class OffState : OnOff {
        public override string DisplayText {
            get { return "Desligado"; }
        }

        public override OnOff Switch() {
            return OnOff.On;
        }
    }

    public abstract OnOff Switch();
    public abstract string DisplayText { get; }
}
Fiquei surpreso em ter conseguido um código aparentemente tão enxuto e tão próximo da versão Java, no entanto o código acima não está completo. Note o uso do modificador partial na declaração das classes e o uso dos valores OnOff.On e OnOff.Off nas implementações do método Switch. A implementação desses dois valores, que são propriedades estáticas da classe OnOff, foi feita em um arquivo separado, como outra parte da classe OnOff, juntamente com muitos outros truques necessários para tornar esse State quase tão simples de se usar quanto a versão Java, provendo ainda alguns recursos extras bem interessantes.

É fácil notar também que não basta declarar as classes OnState e OffState. Como os valores que essas classes representam são de fato disponibilizados e utilizados?

Neste repositório do GitHub você encontra a versão completa dessa implementação e poderá ver com detalhes como foi implementada essa segunda parte da classe, disponível no arquivo OnOff.Partials.Boilerplate.cs. Note também que há uma classe base genérica denominada State<TState, TValues>, que utilizei para encapsular mais código boilerplate necessário para a implementação.

Com tanto código boilerplate para um exemplo tão simples, essa implementação poderia ser considerada inviável, ou no mínimo muito pouco prática, ainda que um gerador de código possa ser implementado para reconstruir o arquivo .Boilerplate.cs a cada vez que o State for alterado.

Ainda assim achei as opções disponíveis para a implementação bastante interessantes e gostei do exercício.

Não quero fazer disso aqui um manual completo de como usar minha implementação, quero apenas apresentá-la. Se tiver se interessado navegue pelo código no GitHub e acredito que encontrará algumas construções bem interessantes.

Encerro com alguns exemplos de uso desse State :

Uso dos valores On e Off:
[Test]
public void TestOnOffSwitches() {
    OnOff on = OnOff.On;
    OnOff off = OnOff.Off;

    OnOff onSwitched = on.Switch();
    OnOff offSwitched = off.Switch();

    Assert.AreEqual(on, offSwitched);
    Assert.AreEqual(off, onSwitched);
}
Uso do State em um bloco Switch:
[Test]
public void TestSwitchStatement() {
    OnOff on = OnOff.On;
    switch (on.Value){
        case OnOff.Values.On:
            break;
        default:
            Assert.Fail();
            break;
    }
    OnOff off = OnOff.Off;
    switch (off.Value) {
        case OnOff.Values.Off:
            break;
        default:
            Assert.Fail();
            break;
    }
}
Conversão do valor do State para um byte:
[Test]
public void TestCastValueToByte()
{
    byte onValueAsByte = (byte)OnOff.On.Value;
    OnOff.Values onValue = (OnOff.Values)onValueAsByte;
    Assert.AreEqual(OnOff.On.Value, onValue);
}
Enumeração dos valores disponíveis para o State:
[Test]
public void TestStates()
{
    IEnumerable<OnOff> states = OnOff.States;
    Assert.NotNull(states);

    OnOff statesOn = states.SingleOrDefault(s => s == OnOff.On);
    Assert.AreEqual(statesOn, OnOff.On);

    OnOff statesOff = states.SingleOrDefault(s => s == OnOff.Off);
    Assert.AreEqual(statesOff, OnOff.Off);
}

quarta-feira, 29 de maio de 2013

C#, Java e os Enums - Parte 2

No último post falei sobre os enums do C#, os enums do Java, suas origens e algumas de suas peculiaridades. Neste post apresentarei um State específico para usarmos como estudo de caso e farei referência a dois repositórios do GitHub que implementam o padrão State do zero em cada uma dessas linguagens.

Abaixo está definido o State OnOff, o qual usaremos como estudo de caso.
Esse State representa dois estados concretos: ligado e desligado. Cada estado possui uma propriedade (displayText) e um manipulador (swtch).
A implementação foi feita em Java, utilizando os enums introduzidos no Java 1.5.

public enum OnOff {
    ON {
        @Override
        public String displayText() {
            return "Ligado";
        }

        @Override
        public OnOff swtch() {
            return OnOff.OFF;
        }
    },

    OFF {
        @Override
        public String displayText() {
            return "Desligado";
        }

        @Override
        public OnOff swtch() {
            return OnOff.ON;
        }
    };

    public abstract OnOff swtch();
    public abstract String displayText();
}
Essa implementação satisfaz ao padrão state e possui a representação enxuta que apresentei no post anterior mas para isso foram necessárias alterações significativas na linguagem.

A mesma implementação sem o uso dos enums do Java 1.5 poderia ser feita conforme pode ser visto neste repositório no GitHub. Não apresentarei o código completo aqui para não tornar o texto extenso demais.

Visitando o repositório acima você verá que seriam necessários três arquivos, um para o estado abstrato e um para cada estado concreto. Uma implementação bastante trabalhosa.

Implementar esse mesmo State em C# não seria muito diferente e tal implementação pode ser encontrada neste outro repositório. No entanto nesse caso apenas um arquivo seria suficiente, contendo os estados concretos como tipos internos ao estado abstrato.

Além disso, algumas outras peculiaridades diferem a implementação Java da implementação C#. No próximo post falarei um pouco a respeito dessas peculiaridades e apresentarei alguns recursos da linguagem C# que podem tornar essa implementação bem diferenciada.

sexta-feira, 24 de maio de 2013

C#, Java e os Enums - Parte 1

Enums, ou enumerações, são tipos de dados cujo valor é atribuído a exatamente um elemento de um conjunto finito.

Nos velhos tempos do Delphi, enums eram muito conhecidos e usados, sendo declarados conforme abaixo:
type
   TSuit = (Hearts, Diamonds, Clubs, Spades);

var ASuit : TSuit;

ASuit := Hearts;
Uma variável declarada como sendo do tipo TSuit poderia assumir exclusivamente um dos valores determinados em tal conjunto.

Com o advento da linguagem Java, enums não se mostraram presentes, e foram uma das grandes faltas sentidas por aqueles que migraram para essa nova linguagem.

Posteriormente, com o surgimento da linguagem C#, enums foram trazidos de volta à cena, com características bem semelhantes ao antigo enum do Delphi.
enum Suit { Hearts, Diamonds, Clubs, Spades }

Suit suit = Suit.Hearts;
Junto com a simplicidade herdada do Delphi, vieram suas limitações. Não era possível declarar métodos em um enum, nem para o tipo como um todo e nem para seus valores. Não era possível também sobrescrever seus operadores, um importante recurso apresentado como diferencial pela linguagem C#.

A linguagem Java resistiu à introdução dos enums durante algum tempo, mas quando a trouxe, o fez de forma que enums poderiam tanto ser vistos como um simples conjunto de valores:
enum Suit { HEARTS, DIAMONDS, CLUBS, SPADES }

Suit suit = HEARTS;
Quanto uma implementação completa do padrão de projeto State:
enum ShippingMethod {
 FIRST_CLASS {
  public double shippingCost(double weight, double distance) {
   ...
  }
 },
 FED_EX {
  public double shippingCost(double weight, double distance) {
   ...
  }  
 },
 UPS {
  public double shippingCost(double weight, double distance) {
   ...
  }   
 };
 
 public abstract double shippingCost(double weight, double distance);
};
O que possibilita construções bastante elaboradas, sem dúvida algo muito mais rico e útil que os enums do C#.

Implementar o padrão de projeto State em C# é semelhante a implementá-lo em Java, sem fazer o uso de seus enums, claro. No entanto a construçao é tão elaborada que torna seu uso bastante desestimulante, principalmente diante dos simples enums que a linguagem oferece.

Lançando mão de recursos como generics e classes parciais, realizei um implementação um pouco mais elaborada do padrão State em C#, algo que remete bastante ao formato visto nos enums do Java.

Nos próximos posts apresentarei essa implementação e farei algumas comparações entre ela e a implementação java.

sexta-feira, 3 de maio de 2013

Windows Azure e Nuvens Privadas

Não represento de nenhuma maneira a Microsoft, mas gostaria de falar um pouco aqui sobre Windows Azure e Nuvens Privadas.

As vezes quando converso com colegas sobre Windows Azure, ouço os clássicos questionamentos: Nuvem não é segura. Trabalhamos para governo, não podemos colocar software em servidores de uma empresa estadunidense. Para quê vou aprender algo que quase ninguém quer usar e só funciona na nuvem?

O fato é que aplicações implantadas em nuvem podem trazer vantagens que não podem ser ignoradas apenas com base em questionamentos como esses. A plataforma Windows Azure por exemplo tem crescido a cada dia, e cada vez novos recursos são acrescentados. Para um desenvolvedor, ou empresa, que tem o .NET Framework como sua principal plataforma de desenvolvimento, abdicar dessas vantagens pode significar abrir mão de uma grande vantagem competitiva.

Mas e os questionamentos acima? Como ter as vantagens da computação em nuvem sem ter que hospedar as aplicações num ambiente público e controlado por empresas de fora do país?

A alternativa são as nuvens privadas. No caso das plataformas Microsoft, ambientes baseados em Windows System Center 2012 ou Windows Server 2012, bastante semelhantes ao Windows Azure e que tem o modelo de desenvolver de aplicações bastante semelhante, se não idêntico, em muitos casos.

Na próxima vez que estiver considerando alternativas para aplicações robustas e escaláveis em plataforma Microsoft, não deixe de considerar essa opção.

E como desenvolvedor, não ignore o Windows Azure apenas por que a empresa onde trabalha se mostra resistente a ele. Conheça seus benefícios, as alternativas, e quem sabe até os convença a investir na plataforma.

Mais informações: http://msdn.microsoft.com/en-us/library/windowsazure/jj136831.aspx