Work Effectivetly With Legacy Code - Part 1

79
Working effectivetly with legacy code Written by Michael C. Feathers

description

Palestra Apresentada por André "Bolha" Bastos na Bluesoft em Dezembro de 2009. Veja o Vídeo da Palestra em http://vimeo.com/8848710. Para mais palestras visite http://blog.bluesoft.com.br

Transcript of Work Effectivetly With Legacy Code - Part 1

Page 1: Work Effectivetly With Legacy Code - Part 1

Working effectivetly with legacy code

Written by Michael C. Feathers

Page 2: Work Effectivetly With Legacy Code - Part 1

Chapter 1 - Changing Software

Page 3: Work Effectivetly With Legacy Code - Part 1

Etapas de alterações em software costumam ser:

adicionar nova funcionalidade

correção de bugs

melhoria da arquitetura

otimização de uso dos recursos do sistema.

Page 4: Work Effectivetly With Legacy Code - Part 1

A maior diferença entre corrigir bugs e novas funcionalidades é que uma altera o comportamento antigo e novas funcionalidade acresce novo comportamento ao já existente. "Behavior is the most important thing about software. It is what users depend on. Users like it when we add new behavior (provided it is what they really wanted), but if we change or remove behavior they depend on (introduce bugs), they stop trusting us."

Page 5: Work Effectivetly With Legacy Code - Part 1

Segue um exemplo: public class CdPlayer { public void addTrackListing(Track track) { ... }

public void replaceTrackListing(String name, Track track) { ... } }

Page 6: Work Effectivetly With Legacy Code - Part 1

Adotar técnicas que facilitem o entendimento e a manutenabilidade, mantendo o comportamento.

Melhorar o desing removendo e alterar o comportamento antigo se chama bug. O oposto disso se chama refactoring.

Improving design

Page 7: Work Effectivetly With Legacy Code - Part 1

Alterações representam muito menos riscos que as reformas, e em geral deve ser o caminho a ser seguido ao se trabalha com código legado.

Alterações sem grandes riscos devem ser feitas em pequenas parcelas de código e com cobertura de testes para garantir o comportamento.

No entanto, muitas vezes a tentação de alterar um código é grande, mas aprender as técnicas certas são de suma importância.

Refactoring

Page 8: Work Effectivetly With Legacy Code - Part 1

Optimization

Tem como objetivo usar menos recursos, aumentar a performance, usar ferramentas que facilitam o trabalho(frameworks).

Testes também podem garantir que algumas otimizações mais invasivas não mudem o comportamento do sistema.

Page 9: Work Effectivetly With Legacy Code - Part 1

Adding a feature

Fixing a Bug Refactoring Optimizing

Structure Alterações Alterações Alterações

Funcionality Alterações

New funcionality Alterações

Resource usage Alterações

Área de atuação das alterações

Page 10: Work Effectivetly With Legacy Code - Part 1

Adicionar novas funcionalidades parece-se muito mais com refactoring e otimização do que com correção de bugs

Em geral tem de se alterar algumas funcionalidades e até alguns comportamentos, mas deve-se manter muito mais comportamentos do que alterar algum.

Page 11: Work Effectivetly With Legacy Code - Part 1

Chapter 2 - Working with Feedback

Page 12: Work Effectivetly With Legacy Code - Part 1

Em muitas equipes de software existem algumas reações

Edit and pray(Edite e reze)

Cover and modify (Cubra e modifique)Em geral uma equipe de testes escreve um teste contra o código e roda-o contra o código(geralmente a noite)

Covering SoftwareSoftwares cobertos por testes que dá um feedback rápido sobre as alterações.

Software ViseSoftwares com comportamento fixado por testes.

Page 13: Work Effectivetly With Legacy Code - Part 1

•Testes que verificam o comportamentos de componentes de forma isolada devem testar o comportamento a nível "atômico".

•Dão feedback rápido do resultado pois rodam rapidamente.

•Test Harness: Termo utilizado para definir um sistema sob uma espécie de “armadura de testes”.

Teste unitários

Page 14: Work Effectivetly With Legacy Code - Part 1

Não costumam ser muito eficientes pois costumam ser difícieis de entender e de manter

Dificulta a localização exata do erro pois muitas vezes tem comportamentos aninhados.

São executados de forma lenta, possuem diversas funcionalidades ambíguas.

Difícil de terem boa cobertura porque tende a ter seu comportamento alterado de forma indireta muitas vezes não coberto por um outro teste.

Large Tests

Page 15: Work Effectivetly With Legacy Code - Part 1

Identificação de change points(Locais onde a alteração ocorrerá)

Encontrar os test points

Quebra dependências

Escrever os testes

Fazer as alterações e refatorações necessárias.

O passo a passo de alterações de código legado

Page 16: Work Effectivetly With Legacy Code - Part 1

Chapter 3 - Sensing and separation

Page 17: Work Effectivetly With Legacy Code - Part 1

Sensing: Quebrar dependências quando não se pode acessar determinados valores através de testes.

Separation: Quebrar dependências quando não se pode rodar um determinado teste isoladamente.

Page 18: Work Effectivetly With Legacy Code - Part 1

Faking Colaborator e Mock Objects Segue o exemplo abaixo:

public classe Sale { private Display display; public Sale(Display display) { this.display = display; }

public void scan(String barCode) { ... display.showLine(itemName); ... } }

A classe display recebe um código de barras e o exibe em um display de preços.

Page 19: Work Effectivetly With Legacy Code - Part 1

Classes como a anterior são difíceis de testar por possuirem uma interface de usuário. Usa-se então um fake colaborator para simular a saída.

public class FakeDisplay implements Display { private String lastLine = "";

public void showLine(String line) { this.lastLine = line; }

public String getLastLine() { return lastLine;

} }

Page 20: Work Effectivetly With Legacy Code - Part 1

Segue o teste: public class SaleTest { @Test public void displayAnItemShouldShowTheNameAndPrice() { FakeDisplay fakeDisplay = new FakeDisplay(); Sale sale = new Sale(fakeDisplay);

sale.scan("152"); assertEquals("Lixo $1,59", display.getLastLine()); } }

Page 21: Work Effectivetly With Legacy Code - Part 1

Mock objects

São objetos poderosos que simulam um objeto para abstrair o comportamento dos objetos que não estão sendo testados.

Page 22: Work Effectivetly With Legacy Code - Part 1

Chapter 4 - The Seam Model

Page 23: Work Effectivetly With Legacy Code - Part 1

Seam é um local onde se pode mudar o comportamento de um programa mais sem alterar o local original.

A maior vantagem de seam model é que muitas vezes não é necessário alterar nada que mude o comportamento no método original.

Exemplo: bool CAsyncSslRec::init() { ... if (!m_bFailureSent) { m_bFailureSent = TRUE; PostReceiveError(SOCKETCALLBACK, SSL_FAILURE); } ... }

Page 24: Work Effectivetly With Legacy Code - Part 1

O método PostReceiveError é um método global pode-se criar uma implementação desse método na própria classe podemos ter uma com o método original e uma com um método vazio, sem comportamento. Com o comportamento original: void CAsyncSslRec::PostReceiveError(UINT type, UINT errorCode) { ::PostReceiveError(type, errorCode); }

Comportamento para o teste:

void TestingAsyncSslRec:: public CAsyncSslRec { virtual void PostReceiveError(UINT tyoe, UINT errorCode) { //nothing here! } }

Page 25: Work Effectivetly With Legacy Code - Part 1

A maior vantagem da técnica Seam é que ao trabalhar com código legado

onde muitas vezes quebrar dependências pode ser complicado, esse é uma maneira rápida e com pouca alteração ou nenhuma na classe original sendo a maioria delas na classe(ou classes) para teste.

Vantagem no uso do seam

Page 26: Work Effectivetly With Legacy Code - Part 1

Enabling points

São locais onde escolhemos qual comportamento usar. Por exemplo, podemos ter um comportamento padrão para o ambiente e um outro comportamento para testes por exemplo.

Page 27: Work Effectivetly With Legacy Code - Part 1

Algumas linguagens como o C e o C++ ao compilar possuem um estágio de

build anterior a compilação final.

Pode-se criar macros com operadores condicionais para compilar de forma diferentes usando #if de configurações diferentes entre teste e no ambiente e produção.

O enable point são as macros que mudaram as definições antes da compilação.

Preprocessing Seams

Page 28: Work Effectivetly With Legacy Code - Part 1

Locais onde se podem mudar o caminho de um conjunto de classes no ambiente.

Classes com mesmo nome e caminho podem ser testadas fazendo um “switch” através do classpath por exemplo.

Link Seams

Page 29: Work Effectivetly With Legacy Code - Part 1

package fitnesse; ... import fit.Parse; import fit.Fixture; ... public class FitFilter { ... tables = new Parse(input) fixture.doTables(tables); .. tables.print(output);

}

As classes ft.Parse e fit.Fixture podem ser determinadas no classpath no ambiente de testes que ao rodar usará uma classe fake que possivelmente terá os mesmo métodos para facilitar a escrita de testes.

Page 30: Work Effectivetly With Legacy Code - Part 1

É quando usamos uma classe como parâmetro para abstrair um comportamento.

Segue o exemplo:

public class AnyThing { public void doSomething() { Something something = new EspecificSomething("something here"); something.do(); } }

Object Seams

Page 31: Work Effectivetly With Legacy Code - Part 1

Após pequena refatoração será possível sobrescrever o método doSomething no momento do teste.

public classe AnyThing extends OtherThing { public void doSomething(Something something) { ... do(something); ... }

protected static void do(Something something) { ... } }

Dentre as técnicas apresentadas Object seam é a melhor escolha entre as demais.

Page 32: Work Effectivetly With Legacy Code - Part 1

Chapter 5 - Tools

Page 33: Work Effectivetly With Legacy Code - Part 1

refactoring – A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing existing behavior.

Page 34: Work Effectivetly With Legacy Code - Part 1

Ferramentas de refactoring automático são úteis para refactoring rápidos, mas se atente, use apenas as ferramentas que garantam que o comportamento do código não será alterado.

Page 35: Work Effectivetly With Legacy Code - Part 1

Classe original

public class A { private int alpha = 0; private int getValue () { alpha++; return 12; }

private void doSomething() { int v = getValue(); int total = 0; for (int n =0; n < 10; n++) { total +=v; } } }

Exemplo de refactoring automático mal sucedido

Page 36: Work Effectivetly With Legacy Code - Part 1

após refactoring:

public class A { private int alpha = 0; private int getValue () { alpha++; return 12; }

private void doSomething() { int total = 0; for (int n =0; n < 10; n++) { total +=getValue(); } } }

O método getValue() incrementára 10 vezes o valor original

Page 37: Work Effectivetly With Legacy Code - Part 1

São objetos que simulam o comportamento de outro.

Extremamente úteis em código legado, pois esse tipo de código costuma possuir muitas dependências.

Sempre que possível quebre algumas dependências quando algum método contiver muitas responsabilidades antes de usar mocks.

Existem diversas ferramentas de mock como o jMock, Mockito para java, Mockpp e GoogleMock para C++ .

Mock Objects

Page 38: Work Effectivetly With Legacy Code - Part 1

Ferramentas de teste unitário

XunitUma das primeira ferramentas de teste unitário, escrito originalmente em

Smaltalk por Kent Beck e depois portado para o Java por Kent Beck e Erich Gamma. Foi escrito em diversas linguagens.

Junit

Ferramenta de teste poderosa, rápida e intuitiva para Java No jUnit 3 estendia-se a classe TestCase e dos métodos tinha o prefixo test. No jUnit 4 usa-se a anotation @Test - no teste em si entre outras como @Before @BeforeClass @After @AfterClass para usar recursos e desmontar recursos em comum entre os testes.

Page 39: Work Effectivetly With Legacy Code - Part 1

CpunitLite Ferramenta para criar testes no C++. No entanto mais trabalhosa e bem menos intuitiva que o JUnit por exemplo. NUnit Ferramenta de teste para plataformas .NET e em C#. Muito similar ao JUnit onde a classe e métodos possuem uma “marca” para representarem testes.

Page 40: Work Effectivetly With Legacy Code - Part 1

Framework for Integrated tests (Fit)

Desenvolvido por Ward Cunninghan, basicamente se cria e salva documentos htmls escrita em uma linguagem acessível.

Os valores a serem testados são exibidos em uma tabela html. Testes falhos exibem células em vermelho com valor esperado e em verde ao passarem.

Mesmo leigos em programação podem escrever um testes com as expectativas dos respectivos valores.

Um programador ou designer invocará o método verdadeiro e apontará onde o resultado será mostrado.

Outras informações http://fit.c2.com

Ferramentas de teste global

Page 41: Work Effectivetly With Legacy Code - Part 1

Chapter 6 - I don't have much time and I have to change it

Page 42: Work Effectivetly With Legacy Code - Part 1

Algumas refactorings podem parecer perda de tempo, mas se ela for feita com as técnicas corretas a médio prazo os benefícios já começaram a serem vistos.

Lembre-se, mesmo trabalhando com prazos apertados, "Remember, code is your house, and you have live in it."

Ao contrário do que possa parecer testes podem fazer com que o trabalho fique mais rápido, pois o feedback é instantâneo e as chances de ajustes ou correções de bugs nesses locais costumam cair drasticamente.

Citação do autor: "Boy, we aren't going back to that again." (Rapazes, nós não voltaremos para aquilo novamente).

Com prazo apertado, surge dilemas, especialmente quando não se há testes. Gastar um pouco mais agora, ou gastar muito no futuro.

Page 43: Work Effectivetly With Legacy Code - Part 1

Usa-se quando o método possui trechos de código que tem responsabilidades totalmente distintas.

Muito usada quando há laços for por exemplo e para “aproveitar” o laço mesmo laço coloca-se responsabilidades distintas que dependem dos mesmos valores.

Verifica-se quais são as variáveis locais necessárias e passe-as como parâmetros para o novo método.

Sprout method

Page 44: Work Effectivetly With Legacy Code - Part 1

Comente a linha com o trecho onde o novo método será chamado e no novo método retorno o valor de mesmo tipo.

Use preferencialmente TDD para criar esse novo método

Rode os testes

Chame o método novo no método no de origem e remova os comentários deixados nesse método antigo.

Page 45: Work Effectivetly With Legacy Code - Part 1

Vantagens

Em geral a maior vantagem é a legibilidade, geralmente é uma reforma rápida, pois os novos métodos devem ter as mesmas funcionalidades do antigo separadamente.

Novos métodos se tornam testáveis

Page 46: Work Effectivetly With Legacy Code - Part 1

Desvantagens

• Como se trata basicamente de uma reforma, soa muitas vezes como desperdício de tempo

• O método original nem sempre ficará facilmente testável

• Obviamente se perde um pouco de tempo, no entanto, facilidade no entendimento poderá justificar o uso.

Page 47: Work Effectivetly With Legacy Code - Part 1

São como os sprout methods, mas a nível de classe.

Usada quando um há um mesmo comportamento no sistema diversas vezes.

Cria-se uma nova classe com os métodos repetitivos e os invoca no lugar.

Passe as variáveis locais como construtor da nova classe.

Use comentários antes de remover os métodos originais.

Utilize TDD preferencialmente para criar novos métodos.

Após a substituição, remova os comentários e código duplicado.

Sprout class

Page 48: Work Effectivetly With Legacy Code - Part 1

Vantagens

• Código bem intuitivo aos olhos do programador e a novas funcionalidades ficam em um único lugar

• Extremante fácil de testar devido a remoção das repetições e similaridades.

Page 49: Work Effectivetly With Legacy Code - Part 1

Desvantagens

• Difícil de determinar, pois pode se tornar algo abstrato e a equipe deve entender bem essa abstração para saber que ela está disponível no sistema.

• Generalizar demais uma funcionalidade pode dificultar o uso de funcionalidades muito similares.

Page 50: Work Effectivetly With Legacy Code - Part 1

Wrap method

Renomeia-se o antigo método antigo.

Cria-se um novo com a mesma assinatura do antigo.

O novo método deve invocar o antigo.

Coloque as novas funcionalidades no método novo

Recomenda-se usar a técnica do Extract method que muitas IDEs possuem e apenas renomear para um nome mais apropriado.

Page 51: Work Effectivetly With Legacy Code - Part 1

public class Employee {

...

public void pay() {

Money amout = new Money();

...

payDispatcher.pay(this, date, amount);

}

...

}

Page 52: Work Effectivetly With Legacy Code - Part 1

public class Employee {

...

public void dispatchPayment() {

Money amout = new Money();

...

payDispatcher.pay(this, date, amount);

}

public void pay() {

logPayment();

dispatchPayment();

}

...

}

Page 53: Work Effectivetly With Legacy Code - Part 1

Vantagens

O método antigo renomeado não crescerá em tamanho.

Usa-se o princípio de conservação de parâmetros(Preserve signatures) evitando-se os erros de compilação e alteração do comportamento.

Page 54: Work Effectivetly With Legacy Code - Part 1

Desvantagens

Os métodos em código legado costumam ter nomes e assinaturas ruins, nesse caso é sempre mantido as antigas.

Geralmente usa-se essa técnica quando não se possui testes, apenas para evitar que se quebre a antiga funcionalidade.

O código ainda se mantém pobre e frágil como no antigo.

Page 55: Work Effectivetly With Legacy Code - Part 1

Essa técnica também é chamada de 'decorator pattern'.

Recomenda quando se quer adicionar novo comportamento a uma mesma funcionalidade e continuar com comportamento antigo

Cria-se uma classe abstrata que estenda e recebe no construtor a classe com as funcionalidades principais.

Na classe abstrata sobrescreve-se os métodos da superclasse e invoca-os os métodos de mesmo nome na classe passada no construtor.

Wrap class

Page 56: Work Effectivetly With Legacy Code - Part 1

Classes que necessitarem dessas funcionalidades estenderão a classe decorator e receberão a classe principal no construtor.

As classe filhas sempre deverão herdar da classe abstrata e passada no construtor novas classes com as novas funcionalidades e invoca-se o construtor da superclasse.

Page 57: Work Effectivetly With Legacy Code - Part 1

Exemplo: Main class:

public class ToolController { public ToolController() { }

public void on() { //anything here }

public void off() { //anything here } }

Page 58: Work Effectivetly With Legacy Code - Part 1

A classe abstrata:

public abstract class ToolControllerDecorator extends ToolController { protected Controller controller; public ToolControllerDecorator(ToolController controller) { this.controller = controller; }

public void on() {controller.on();} public void off() {controller.off();} }

Page 59: Work Effectivetly With Legacy Code - Part 1

public class LogController extends ToolControllerDecorator { private Logger logger;

public LogController(ToolController controller, Logger logger) { super(controller); this.logger = logger; } public void on() { // anything method in the logger class

controller.on(); } ... }

Page 60: Work Effectivetly With Legacy Code - Part 1

Sumário

Embora muitas vezes seja um pouco difícil separar as responsabilidades de uma classe, ao utilizar essas técnicas se tornará uma tarefa cada vez mais fácil.

Recomendado-se também, que além da melhora visual, comece sempre a testar o novo código para não proliferar códigos sem testes.

Page 61: Work Effectivetly With Legacy Code - Part 1

Chapter 7: it takes forever to make a change

Page 62: Work Effectivetly With Legacy Code - Part 1

Quando é preciso alterar código, inicialmente precisamos entender o que ele faz. Especialmente ao lidar com código no qual não se está muito familiarizado há um sentimento de insegurança

Page 63: Work Effectivetly With Legacy Code - Part 1

Understanding( Entendimento)

Na maioria das vezes ao olhar um código saberemos se ele é um código legado ou com boa manutenabilidade.

Boa manutenabilidade(well-maintained): Mais segurança e confiança para novas features ou alterações.

Legacy code: Desespero, muitas vezes piora-se o código pois não o compreendemos bem.

Page 64: Work Effectivetly With Legacy Code - Part 1

Tempo que se leva após fazer uma alteração saber qual a resposta o sistema teve a essa alteração.

Sem testes, é necessário subir o sistema, e testar como um usuário diversas vezes, e sempre que algo dá errado tudo de novo, isso costuma ser frustrante em muitos casos.

Lag time

Page 65: Work Effectivetly With Legacy Code - Part 1

A mente humana trabalha melhor quando se tem um feedback rápido de pequenas alterações por vez e isso culminará em um entendimento muito melhor com o todo.

Imagine que código sem teste é como o robo Spirit que esteve em Marte. O comando parte da Terra e somente 7 minutos depois a máquina responderá ao comando, e só saberá se ela realmente respondeu 14 minutos depois.

No aspecto de tempo de resposta, as linguagens interpretadas costumam levar vantagens perante as compiladas.

Page 66: Work Effectivetly With Legacy Code - Part 1

Quebrar dependências em código legado muitas vezes é um desafio.

Detectar interception points antes da alteração.

Existem alguns técnicas como PassNull, FakeConnections e getInstance.

Ao simular um comportamento evite fazê-las no ambiente de produção e sim no ambiente de testes.

Breaking Dependencies

Page 67: Work Effectivetly With Legacy Code - Part 1

Interception point

Um simples ponto onde se pode detectar os efeitos de uma simples alteração.

Métodos as vezes um tanto confusos quando detectados os interceptions points, facilita o entendimento e o uso de testes, mesmo que indiretamente.

Page 68: Work Effectivetly With Legacy Code - Part 1

Por exemplo: Um método que calcule preço e taxas que variam de estado para estado com essa lógica juntas no mesmo método

public class Invoice { ... public Money getValue() {

Money total = itemsSum(); if (billing.after(someDate)) { if (originator.getState().equals('NY') { total.add(getLocalShipping() ); //--> Interception point here }else { total.add(getDefaultShipping() ); //--> Interception point here } }else{ total.add( getDefaultShipping() ) ; //--> Interception point here } total.add(getTax()); return total; } ... }

Page 69: Work Effectivetly With Legacy Code - Part 1

Pinch points

Um pinch point é uma pequena área de um equema, métodos que ao serem testados podem detectar alterações em vários outros. O termo pinch point muitas vezes é difícil de se entender. Seria como um funil e é justamente nesse "afunilamento" que as bases dos testes serão criadas.

Pinch point é o extremo do encapsulamento.

Page 70: Work Effectivetly With Legacy Code - Part 1

Build Dependencies

Quebrar o sistema em pacotes com menos classes acelera o processo de building dos testes.

Usar interfaces ao invés de classes concretas. Para facilitar isso, muitas IDEs possui as opções Extract implementor and Extract interface.

Quebrar diversas classes com responsabilidades distintas, diminui tempo de build dos testes. Isso poderá fazer com que os testes em geral rodem mais rápido.

Page 71: Work Effectivetly With Legacy Code - Part 1

Extract Interface

É uma das técnicas mais úteis para se trabalhar com código legado.

Consiste em criar uma interface e os métodos que se deseja testar coloque os na interface com a mesma assinatura.

Substituir as chamadas que usem a classe concreta pela interface.

Outra boa razão de usar interfaces e que em geral interfaces sofrem poucas alterações diminuindo o risco de erros de compilação.

Muitas IDEs possuem Extract Interface automático, onde e necessário informar apenas o nome da interface e selecionar os métodos que se deseja implementar.

Page 72: Work Effectivetly With Legacy Code - Part 1

Extract Method

Outra técnica bem útil e prática para se trabalhar com código legado.

Seleciona-se um trecho de código, cria-se um método e cole o conteúdo antigo nesse método.

Passe como parâmetro todas as variáveis locais utilizadas no novo método.

Comente o código no método antigo, invoque o método novo e então rode os testes.

Remova todas os comentários e códigos duplicados se houver.

Page 73: Work Effectivetly With Legacy Code - Part 1

Inversão de dependência

Geralmente quando usamos interfaces ao invés de classes concretas utilizamos o princípio da inversão de dependência.

Em geral essas interfaces são passadas no construtor ou setter ao invés de serem construídas dentro da própria classe.

Muitas vezes usar muitas interfaces pode soar confuso, pelo menos dois arquivos, mas os benefícios para tempo de rebuild e quebra de dependência valem o preço.

Page 74: Work Effectivetly With Legacy Code - Part 1

Sumário

O autor recomenda ler o livro Agile Software Development: Principles, Patterns, and Pratices de Robert C. Martin's. Lá há diversas técnicas além das mostradas nesse livro.

Page 75: Work Effectivetly With Legacy Code - Part 1

Outras técnicas abordadas nesse livro

Page 76: Work Effectivetly With Legacy Code - Part 1

• Notes/Sketching

• Listing markup

• Scratch Refactoring

• Delete Unused Code

• Adapt parameter

• Encapsule Global References

• Extract and Override Call

Page 77: Work Effectivetly With Legacy Code - Part 1

• Extract and Factory Method

• Introduce Instance Delagator

• Link Substitution

• Parameterize Contructor

• Parameterize Method

• Extract Implementor

Page 78: Work Effectivetly With Legacy Code - Part 1

Michael Feathers Senior Trainer, Mentor and Consultant

Michael Feathers is a senior member of Object Mentor team. He provides training, coaching and mentoring services in Agile/XP programming practices, test-driven development, refactoring, object-oriented design, Java, C#, and C++.

Michael has over 12 years of experience in developing world-class software solutions. Prior to joining Object Mentor, Michael designed a proprietary programming language and compiler as well as a large multi-platform class library and a framework for instrumentation control.

Page 79: Work Effectivetly With Legacy Code - Part 1

Michael is an active member of the Agile/XP community. As a contribution to this community, he developed and maintains the CPPUnit — an open source C++ port of the JUnit testing framework. He is a member of the ACM and IEEE. He regularly speaks at software conferences around the world and has been the acting chair for the Codefest event at the last three OOPSLA conferences.

When Michael isn't engaged with a team, he spends his time investigating new ways of altering design over time in codebases. His key passion is helping teams surmount problems in large legacy code bases and connecting with what makes developing software fun and enriching.