1 of 47

Código Duplicado

Repetição é sinal de maturidade�Repetição é sinal de maturidade

Repetição é sinal de maturidade

Repetição é sinal de maturidade

Repetição é sinal de maturidade

06/2023

2 of 47

Código Duplicado

Repetição é sinal de maturidade�Repetição é sinal de maturidade

Repetição pode ser sinal de maturidade

06/2023

3 of 47

Vinítius Salomão

Staff Software Engineer

@vinitius

@vinitius

/vinitius

4 of 47

Zero Hash

Crypto-as-a-Service�Leader

Trading

Blockchain�Intercom

Real time�data

5 of 47

Number one in the stink parade is duplicated code. If you see the same code structure in more than one place, you can be sure that your program will be better if you find a way to unify them.

Martin Fowler & Kent Beck - Refactoring

6 of 47

D.R.Y

Don't Repeat Yourself

7 of 47

D.R.Y

Don't Repeat Yourself

8 of 47

9 of 47

"Duplicação sai muito mais barato do que lidar com a abstração errada"

10 of 47

"Duplicação sai muito mais barato do que lidar com a abstração errada"

11 of 47

Generalização Prematura

12 of 47

"This is really going to be a clean framework. I'll make an ABSTRACT CLASS out of this part so that folks can SUBCLASS it later, and I'll put in a bunch of well-commented OVERRIDABLE hooks in the concrete SUBCLASSES so that folks can use them as TEMPLATES, and just in case somebody ever needs to build special debug SUBCLASSES, I'll put in extra STUBS over there (somebody will thank me for 'em one of these days). Yeah, this is really going to be neat."

https://wiki.c2.com/?PrematureGeneralization

13 of 47

Uma função sem um nome bem definido

Um parâmetro com sempre o mesmo valor

Métodos com sobrecarga sem nenhuma similaridade entre si

Classe Abstrata com apenas 1 descendente

Uma biblioteca utilizada apenas por 1 programa

14 of 47

W.E.T

15 of 47

W.E.T

Write Every Time

16 of 47

Duplicação Acidental

17 of 47

18 of 47

BaseController extends <SomeFrameworkNativeController> {

.....

(métodos descolados que reduzirão a duplicidade)

.....

}

19 of 47

CheckoutController extends BaseController {

.....

(métodos descolados que reduzirão ainda mais a duplicidade para um fluxo específico)

.....

}

20 of 47

CartController extends CheckoutController {

@Override

public void doIt(it Something<T>) {

this.justDoIt(it);

}

}

21 of 47

22 of 47

23 of 47

Identificar o comportamento exato do Controller contendo a implementação concreta se tornou extremamente mais complexo

24 of 47

Novos membros integrados agora devem suportar a carga cognitiva do Framework utilizado assim como da abstração (desnecessária)

25 of 47

Em muitos desses casos, a duplicação inicial é meramente Acidental, pois a lógica de negócio e sintaxe poderá evoluir de formas completamente diferentes.

26 of 47

function saveFile(moduleName: string, fileName: string, json: any) {

try {

const path = `${toFolderName(moduleName)}/${toFileName(fileName)}`

fs.writeFileSync(`./${path}.json`, JSON.stringify(json));

} catch(err) {

console.error(err);

}

}

https://medium.com/@mariusbongarts/when-you-should-duplicate-code-b0d747bc1c67

27 of 47

function toFileName(fileName:string) {

return fileName.split(/(?=[A-Z])/).join('_').toLowerCase();

}

function toFolderName(moduleName: string) {

return moduleName.split(/(?=[A-Z])/).join('_').toLowerCase();

}

28 of 47

function toFileOrFolderName(fileOrFolderName:string) {

return fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();

}

function saveFile(moduleName: string, fileName: string, json: any) {

try {

const path = `${toFileOrFolderName(moduleName)}/${toFileOrFolderName(fileName)}`

fs.writeFileSync(`./${path}.json`, JSON.stringify(json));

} catch(err) {

console.error(err);

}

}

29 of 47

Os arquivos devem conter no nome o timestamp do momento em que foram salvos. E Agora?

30 of 47

function toFileOrFolderName(fileOrFolderName:string, isFile: boolean) {

const underScoreName = fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();

if (isFile) {

return `${new Date().getTime()}_${underScoreName}`

}

return underScoreName;

}

31 of 47

function toFileOrFolderName(fileOrFolderName:string, isFile: boolean) {

const underScoreName = fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();

if (isFile) {

return `${new Date().getTime()}_${underScoreName}`

}

return underScoreName;

}

32 of 47

function toUnderscore(camelCase: string) {

return camelCase.split(/(?=[A-Z])/).join('_').toLowerCase();

}

function toFileName(fileName:string) {

const timeStamp = new Date().getTime();

return `${timeStamp}_${toUnderscore(fileName)}`;

}

function toFolderName(moduleName: string) {

return toUnderscore(moduleName);

}

33 of 47

Three strikes and you refactor

34 of 47

WhiteDwarfException

35 of 47

Perspectiva Arquitetural

36 of 47

37 of 47

Entidades de Domínio

38 of 47

Bibliotecas "Utilitárias"

39 of 47

Frameworks em cima de Frameworks

40 of 47

Analisadores Estáticos

41 of 47

Pensamentos Finais

42 of 47

Código "Molhado"

43 of 47

Atenção às nuances e tradeoffs de cada contexto

44 of 47

Cuidado com bibliotecas utilitárias

45 of 47

Duplicação > Acoplamento (99% dos casos)

46 of 47

Clean Code != Clever Code

47 of 47

Perguntas?

Muito Obrigado!