From 4ca4c8071edbc8ca331b855b4bff7f033c9477ce Mon Sep 17 00:00:00 2001 From: carlosschults Date: Fri, 2 Aug 2024 13:11:09 +0000 Subject: [PATCH] jekyll build from Action 268a9eabd136927ef0b0a2466ede88dd2eda8cc4 --- .nojekyll | 0 AJ21/index.html | 247 ++ CNAME | 1 + about/index.html | 188 + browserconfig.xml | 2 + busca/index.html | 174 + como-aprender-ingles/index.html | 187 + css/main.css | 286 ++ css/main.css.map | 18 + .../index.html | 559 +++ .../index.html | 601 +++ .../index.html | 449 +++ en/cargo-cult-programming/index.html | 581 +++ en/code-review-vs-pair-programming/index.html | 551 +++ .../index.html | 533 +++ en/csharp-7-features-part-2/index.html | 584 +++ en/csharp-7-features/index.html | 510 +++ en/csharp-8-features/index.html | 600 +++ en/csharp-regex.html | 673 ++++ en/csharp-unit-testing-intro-tdd/index.html | 859 +++++ en/fivel-levels-readable-code/index.html | 654 ++++ en/functional-programming-csharp/index.html | 606 +++ en/git-basics-for-tfs-users.html | 688 ++++ en/git-beautiful-history/index.html | 665 ++++ en/git-create-branch.html | 564 +++ en/how-to-choose-good-names/index.html | 545 +++ en/linq-join-operator.html | 758 ++++ en/mutation-testing/index.html | 499 +++ en/null-is-evil.html | 577 +++ en/reduce-cyclomatic-complexity/index.html | 558 +++ en/share-what-you-learn/index.html | 465 +++ en/sharpen-the-saw/index.html | 534 +++ en/types-of-comments-to-avoid/index.html | 539 +++ .../index.html | 556 +++ .../index.html | 696 ++++ en/value-objects-tool/index.html | 541 +++ .../index.html | 495 +++ en/value-reference-types-in-csharp/index.html | 542 +++ favicon.ico | Bin 0 -> 1150 bytes feed.xml | 2462 ++++++++++++ footprints/index.html | 213 ++ git-bisect-intro/index.html | 713 ++++ img/android-icon-144x144.png | Bin 0 -> 20963 bytes img/android-icon-192x192.png | Bin 0 -> 30154 bytes img/android-icon-36x36.png | Bin 0 -> 3176 bytes img/android-icon-48x48.png | Bin 0 -> 4712 bytes img/android-icon-72x72.png | Bin 0 -> 7676 bytes img/android-icon-96x96.png | Bin 0 -> 11652 bytes img/apple-icon-114x114.png | Bin 0 -> 14746 bytes img/apple-icon-120x120.png | Bin 0 -> 15896 bytes img/apple-icon-144x144.png | Bin 0 -> 20963 bytes img/apple-icon-152x152.png | Bin 0 -> 22322 bytes img/apple-icon-180x180.png | Bin 0 -> 28518 bytes img/apple-icon-57x57.png | Bin 0 -> 5625 bytes img/apple-icon-60x60.png | Bin 0 -> 5958 bytes img/apple-icon-72x72.png | Bin 0 -> 7676 bytes img/apple-icon-76x76.png | Bin 0 -> 8380 bytes img/apple-icon-precomposed.png | Bin 0 -> 30726 bytes img/apple-icon.png | Bin 0 -> 30726 bytes img/configuracao-dotnet/azure-identity.webp | Bin 0 -> 40650 bytes .../azure-managed-identities.webp | Bin 0 -> 30074 bytes .../configuration-overview.webp | Bin 0 -> 280904 bytes .../configuration-providers-layers.webp | Bin 0 -> 16896 bytes .../options-lifetimes.webp | Bin 0 -> 57414 bytes img/diff.png | Bin 0 -> 28913 bytes img/favicon-16x16.png | Bin 0 -> 1738 bytes img/favicon-32x32.png | Bin 0 -> 2815 bytes img/favicon-96x96.png | Bin 0 -> 11652 bytes img/foto.jpg | Bin 0 -> 59282 bytes img/git-beautiful-history/img1.png | Bin 0 -> 18781 bytes img/git-beautiful-history/img2.png | Bin 0 -> 22105 bytes img/git-beautiful-history/img3.png | Bin 0 -> 35920 bytes img/git-beautiful-history/img4.png | Bin 0 -> 155640 bytes img/git-beautiful-history/img5.png | Bin 0 -> 82913 bytes img/git-beautiful-history/img6.png | Bin 0 -> 30654 bytes img/git-beautiful-history/img7.png | Bin 0 -> 27513 bytes img/git-beautiful-history/img8.png | Bin 0 -> 30240 bytes img/levels.jpg | Bin 0 -> 85021 bytes img/ms-icon-144x144.png | Bin 0 -> 20963 bytes img/ms-icon-150x150.png | Bin 0 -> 21929 bytes img/ms-icon-310x310.png | Bin 0 -> 62765 bytes img/ms-icon-70x70.png | Bin 0 -> 7483 bytes index.html | 247 ++ manifest.json | 41 + pt/4-erros-comuns-datetime-csharp/index.html | 606 +++ pt/afiando-a-serra/index.html | 581 +++ pt/basicos-do-git-usuarios-tfvc.html | 734 ++++ pt/blogs-desenvolvimento-portugues/index.html | 530 +++ pt/boas-praticas-sem-tempo/index.html | 582 +++ pt/cargo-cult-programming/index.html | 644 ++++ pt/cinco-niveis-codigo-legivel.html | 701 ++++ pt/como-aprender-ingles-parte-1.html | 620 +++ pt/como-aprender-ingles-parte-2.html | 672 ++++ pt/como-escolher-bons-nomes/index.html | 595 +++ pt/compartilhe-o-que-voce-aprende/index.html | 516 +++ pt/configuracao-dotnet.html | 1354 +++++++ pt/csharp-expressoes-regulares.html | 722 ++++ pt/escrevendo-codigo-bom/index.html | 561 +++ pt/funcionalidades-csharp-7-parte-2.html | 623 +++ pt/funcionalidades-csharp-7/index.html | 557 +++ pt/funcionalidades-csharp8/index.html | 647 ++++ pt/git-bisect-intro/index.html | 759 ++++ pt/git-criar-branch.html | 623 +++ pt/git-historico-bonito/index.html | 713 ++++ pt/index.html | 258 ++ pt/metodos-privados-code-smell/index.html | 696 ++++ pt/null-problematico.html | 626 +++ pt/operador-linq-join.html | 804 ++++ pt/programacao-funcional-csharp/index.html | 660 ++++ pt/programar-portugues-ou-ingles/index.html | 597 +++ .../index.html | 606 +++ .../index.html | 498 +++ .../index.html | 603 +++ pt/testes-de-mutacao/index.html | 546 +++ .../index.html | 907 +++++ pt/testes-unitarios-iniciantes-parte-2.html | 748 ++++ pt/testes-unitarios-iniciantes-parte1.html | 611 +++ pt/tipos-de-comentarios-a-evitar/index.html | 588 +++ .../index.html | 551 +++ .../index.html | 581 +++ pt/traducao-fases-estabilizacao/index.html | 551 +++ pt/value-objects-ferramenta/index.html | 584 +++ readings/index.html | 202 + rss.xml | 3209 ++++++++++++++++ search/index.html | 176 + sitemaps.xml | 3378 +++++++++++++++++ sobre/index.html | 185 + tag/agile/index.html | 442 +++ tag/automated-testing/index.html | 430 +++ tag/automated-tests/index.html | 434 +++ tag/beginners/index.html | 454 +++ tag/best practices/index.html | 450 +++ tag/best-practices/index.html | 450 +++ tag/blog/index.html | 422 ++ tag/blogging/index.html | 426 +++ tag/boas praticas/index.html | 422 ++ "tag/boas pr\303\241ticas/index.html" | 422 ++ tag/boas-praticas/index.html | 422 ++ "tag/boas-pr\303\241ticas/index.html" | 422 ++ tag/book review/index.html | 426 +++ tag/career-advice/index.html | 426 +++ tag/cargo cult programming/index.html | 426 +++ tag/carreira/index.html | 422 ++ tag/cobertura-de-codigo/index.html | 422 ++ tag/code review/index.html | 426 +++ tag/code smell/index.html | 426 +++ tag/code-coverage/index.html | 426 +++ tag/code-smell/index.html | 426 +++ "tag/coment\303\241rios/index.html" | 422 ++ tag/comments/index.html | 426 +++ tag/compartilhar/index.html | 422 ++ tag/configuracao/index.html | 422 ++ tag/controle-de-versao/index.html | 422 ++ tag/csharp/index.html | 482 +++ tag/ddd/index.html | 426 +++ tag/dotnet/index.html | 426 +++ tag/engenharia-de-software/index.html | 422 ++ tag/expressoes_regulares/index.html | 422 ++ tag/first post/index.html | 426 +++ tag/functional-programming/index.html | 426 +++ tag/git/index.html | 438 +++ tag/ingles/index.html | 422 ++ "tag/ingl\303\252s/index.html" | 422 ++ tag/iniciantes/index.html | 422 ++ .../index.html" | 422 ++ tag/legibilidade/index.html | 422 ++ tag/linq/index.html | 426 +++ tag/livros/index.html | 422 ++ tag/metodologias ageis/index.html | 422 ++ "tag/metodologias \303\241geis/index.html" | 422 ++ tag/metodologias-ageis/index.html | 422 ++ tag/modelagem-de-software/index.html | 422 ++ tag/mutation-testing/index.html | 426 +++ tag/oop/index.html | 438 +++ tag/orientacao-a-objetos/index.html | 422 ++ tag/pair programming/index.html | 426 +++ tag/primeiro post/index.html | 422 ++ tag/programacao cargo cult/index.html | 422 ++ tag/programacao em par/index.html | 422 ++ tag/programacao funcional/index.html | 422 ++ tag/programacao/index.html | 422 ++ "tag/programa\303\247\303\243o/index.html" | 422 ++ tag/programming/index.html | 430 +++ tag/readability/index.html | 426 +++ tag/recomendacoes/index.html | 422 ++ tag/regex/index.html | 426 +++ tag/regular_expressions/index.html | 426 +++ tag/revisao de codigo/index.html | 422 ++ tag/serie-testes-unitarios/index.html | 422 ++ tag/sharing/index.html | 426 +++ tag/software-design/index.html | 426 +++ tag/software-engineering/index.html | 434 +++ tag/software-testing/index.html | 442 +++ tag/tdd/index.html | 426 +++ tag/tempo/index.html | 422 ++ tag/testes automatizados/index.html | 422 ++ tag/testes de software/index.html | 422 ++ tag/testes-automatizados/index.html | 422 ++ tag/testes-de-mutacao/index.html | 422 ++ tag/testes-de-software/index.html | 422 ++ tag/testes-unitarios/index.html | 422 ++ tag/tfs/index.html | 426 +++ tag/tfvcs/index.html | 426 +++ tag/time/index.html | 426 +++ tag/tipagem/index.html | 422 ++ tag/traducoes/index.html | 422 ++ "tag/tradu\303\247\303\265es/index.html" | 422 ++ tag/tutorial/index.html | 430 +++ tag/type system/index.html | 430 +++ tag/unit-testing-series/index.html | 434 +++ tag/unit-testing/index.html | 442 +++ tag/version-control-system/index.html | 426 +++ tag_ptbr/agile/index.html | 480 +++ tag_ptbr/automated-testing/index.html | 480 +++ tag_ptbr/automated-tests/index.html | 480 +++ tag_ptbr/beginners/index.html | 480 +++ tag_ptbr/best practices/index.html | 480 +++ tag_ptbr/best-practices/index.html | 480 +++ tag_ptbr/blog/index.html | 484 +++ tag_ptbr/blogging/index.html | 480 +++ tag_ptbr/boas praticas/index.html | 500 +++ "tag_ptbr/boas pr\303\241ticas/index.html" | 496 +++ tag_ptbr/boas-praticas/index.html | 504 +++ "tag_ptbr/boas-pr\303\241ticas/index.html" | 488 +++ tag_ptbr/book review/index.html | 480 +++ tag_ptbr/career-advice/index.html | 480 +++ tag_ptbr/cargo cult programming/index.html | 480 +++ tag_ptbr/carreira/index.html | 484 +++ tag_ptbr/cobertura-de-codigo/index.html | 484 +++ tag_ptbr/code review/index.html | 480 +++ tag_ptbr/code smell/index.html | 484 +++ tag_ptbr/code-coverage/index.html | 480 +++ tag_ptbr/code-smell/index.html | 484 +++ "tag_ptbr/coment\303\241rios/index.html" | 484 +++ tag_ptbr/comments/index.html | 480 +++ tag_ptbr/compartilhar/index.html | 484 +++ tag_ptbr/configuracao/index.html | 484 +++ tag_ptbr/controle-de-versao/index.html | 484 +++ tag_ptbr/csharp/index.html | 560 +++ tag_ptbr/ddd/index.html | 484 +++ tag_ptbr/dotnet/index.html | 488 +++ tag_ptbr/engenharia-de-software/index.html | 492 +++ tag_ptbr/expressoes_regulares/index.html | 484 +++ tag_ptbr/first post/index.html | 480 +++ tag_ptbr/functional-programming/index.html | 480 +++ tag_ptbr/git/index.html | 496 +++ tag_ptbr/ingles/index.html | 484 +++ "tag_ptbr/ingl\303\252s/index.html" | 488 +++ tag_ptbr/iniciantes/index.html | 512 +++ .../index.html" | 484 +++ tag_ptbr/legibilidade/index.html | 484 +++ tag_ptbr/linq/index.html | 484 +++ tag_ptbr/livros/index.html | 484 +++ tag_ptbr/metodologias ageis/index.html | 484 +++ .../metodologias \303\241geis/index.html" | 488 +++ tag_ptbr/metodologias-ageis/index.html | 492 +++ tag_ptbr/modelagem-de-software/index.html | 484 +++ tag_ptbr/mutation-testing/index.html | 480 +++ tag_ptbr/oop/index.html | 480 +++ tag_ptbr/orientacao-a-objetos/index.html | 496 +++ tag_ptbr/pair programming/index.html | 480 +++ tag_ptbr/primeiro post/index.html | 484 +++ tag_ptbr/programacao cargo cult/index.html | 484 +++ tag_ptbr/programacao em par/index.html | 484 +++ tag_ptbr/programacao funcional/index.html | 484 +++ tag_ptbr/programacao/index.html | 484 +++ .../programa\303\247\303\243o/index.html" | 484 +++ tag_ptbr/programming/index.html | 480 +++ tag_ptbr/readability/index.html | 480 +++ tag_ptbr/recomendacoes/index.html | 484 +++ tag_ptbr/regex/index.html | 484 +++ tag_ptbr/regular_expressions/index.html | 480 +++ tag_ptbr/revisao de codigo/index.html | 484 +++ tag_ptbr/serie-testes-unitarios/index.html | 492 +++ tag_ptbr/sharing/index.html | 480 +++ tag_ptbr/software-design/index.html | 480 +++ tag_ptbr/software-engineering/index.html | 480 +++ tag_ptbr/software-testing/index.html | 480 +++ tag_ptbr/tdd/index.html | 484 +++ tag_ptbr/tempo/index.html | 484 +++ tag_ptbr/testes automatizados/index.html | 484 +++ tag_ptbr/testes de software/index.html | 484 +++ tag_ptbr/testes-automatizados/index.html | 500 +++ tag_ptbr/testes-de-mutacao/index.html | 484 +++ tag_ptbr/testes-de-software/index.html | 500 +++ tag_ptbr/testes-unitarios/index.html | 500 +++ tag_ptbr/tfs/index.html | 484 +++ tag_ptbr/tfvcs/index.html | 484 +++ tag_ptbr/time/index.html | 480 +++ tag_ptbr/tipagem/index.html | 488 +++ tag_ptbr/traducoes/index.html | 488 +++ "tag_ptbr/tradu\303\247\303\265es/index.html" | 484 +++ tag_ptbr/tutorial/index.html | 492 +++ tag_ptbr/type system/index.html | 480 +++ tag_ptbr/unit-testing-series/index.html | 480 +++ tag_ptbr/unit-testing/index.html | 480 +++ tag_ptbr/version-control-system/index.html | 480 +++ unifai2017/index.html | 216 ++ unifai2018/index.html | 185 + 299 files changed, 131249 insertions(+) create mode 100644 .nojekyll create mode 100644 AJ21/index.html create mode 100644 CNAME create mode 100644 about/index.html create mode 100644 browserconfig.xml create mode 100644 busca/index.html create mode 100644 como-aprender-ingles/index.html create mode 100644 css/main.css create mode 100644 css/main.css.map create mode 100644 en/4-common-datetime-mistakes-csharp/index.html create mode 100644 en/are-private-methods-a-code-smell/index.html create mode 100644 en/book-review-pragmatic-programmer/index.html create mode 100644 en/cargo-cult-programming/index.html create mode 100644 en/code-review-vs-pair-programming/index.html create mode 100644 en/coding-best-practices-short-time/index.html create mode 100644 en/csharp-7-features-part-2/index.html create mode 100644 en/csharp-7-features/index.html create mode 100644 en/csharp-8-features/index.html create mode 100644 en/csharp-regex.html create mode 100644 en/csharp-unit-testing-intro-tdd/index.html create mode 100644 en/fivel-levels-readable-code/index.html create mode 100644 en/functional-programming-csharp/index.html create mode 100644 en/git-basics-for-tfs-users.html create mode 100644 en/git-beautiful-history/index.html create mode 100644 en/git-create-branch.html create mode 100644 en/how-to-choose-good-names/index.html create mode 100644 en/linq-join-operator.html create mode 100644 en/mutation-testing/index.html create mode 100644 en/null-is-evil.html create mode 100644 en/reduce-cyclomatic-complexity/index.html create mode 100644 en/share-what-you-learn/index.html create mode 100644 en/sharpen-the-saw/index.html create mode 100644 en/types-of-comments-to-avoid/index.html create mode 100644 en/unit-testing-for-beginners-part1/index.html create mode 100644 en/unit-testing-for-beginners-part2/index.html create mode 100644 en/value-objects-tool/index.html create mode 100644 en/value-reference-types-in-csharp-part-2/index.html create mode 100644 en/value-reference-types-in-csharp/index.html create mode 100644 favicon.ico create mode 100644 feed.xml create mode 100644 footprints/index.html create mode 100644 git-bisect-intro/index.html create mode 100644 img/android-icon-144x144.png create mode 100644 img/android-icon-192x192.png create mode 100644 img/android-icon-36x36.png create mode 100644 img/android-icon-48x48.png create mode 100644 img/android-icon-72x72.png create mode 100644 img/android-icon-96x96.png create mode 100644 img/apple-icon-114x114.png create mode 100644 img/apple-icon-120x120.png create mode 100644 img/apple-icon-144x144.png create mode 100644 img/apple-icon-152x152.png create mode 100644 img/apple-icon-180x180.png create mode 100644 img/apple-icon-57x57.png create mode 100644 img/apple-icon-60x60.png create mode 100644 img/apple-icon-72x72.png create mode 100644 img/apple-icon-76x76.png create mode 100644 img/apple-icon-precomposed.png create mode 100644 img/apple-icon.png create mode 100644 img/configuracao-dotnet/azure-identity.webp create mode 100644 img/configuracao-dotnet/azure-managed-identities.webp create mode 100644 img/configuracao-dotnet/configuration-overview.webp create mode 100644 img/configuracao-dotnet/configuration-providers-layers.webp create mode 100644 img/configuracao-dotnet/options-lifetimes.webp create mode 100644 img/diff.png create mode 100644 img/favicon-16x16.png create mode 100644 img/favicon-32x32.png create mode 100644 img/favicon-96x96.png create mode 100644 img/foto.jpg create mode 100644 img/git-beautiful-history/img1.png create mode 100644 img/git-beautiful-history/img2.png create mode 100644 img/git-beautiful-history/img3.png create mode 100644 img/git-beautiful-history/img4.png create mode 100644 img/git-beautiful-history/img5.png create mode 100644 img/git-beautiful-history/img6.png create mode 100644 img/git-beautiful-history/img7.png create mode 100644 img/git-beautiful-history/img8.png create mode 100644 img/levels.jpg create mode 100644 img/ms-icon-144x144.png create mode 100644 img/ms-icon-150x150.png create mode 100644 img/ms-icon-310x310.png create mode 100644 img/ms-icon-70x70.png create mode 100644 index.html create mode 100644 manifest.json create mode 100644 pt/4-erros-comuns-datetime-csharp/index.html create mode 100644 pt/afiando-a-serra/index.html create mode 100644 pt/basicos-do-git-usuarios-tfvc.html create mode 100644 pt/blogs-desenvolvimento-portugues/index.html create mode 100644 pt/boas-praticas-sem-tempo/index.html create mode 100644 pt/cargo-cult-programming/index.html create mode 100644 pt/cinco-niveis-codigo-legivel.html create mode 100644 pt/como-aprender-ingles-parte-1.html create mode 100644 pt/como-aprender-ingles-parte-2.html create mode 100644 pt/como-escolher-bons-nomes/index.html create mode 100644 pt/compartilhe-o-que-voce-aprende/index.html create mode 100644 pt/configuracao-dotnet.html create mode 100644 pt/csharp-expressoes-regulares.html create mode 100644 pt/escrevendo-codigo-bom/index.html create mode 100644 pt/funcionalidades-csharp-7-parte-2.html create mode 100644 pt/funcionalidades-csharp-7/index.html create mode 100644 pt/funcionalidades-csharp8/index.html create mode 100644 pt/git-bisect-intro/index.html create mode 100644 pt/git-criar-branch.html create mode 100644 pt/git-historico-bonito/index.html create mode 100644 pt/index.html create mode 100644 pt/metodos-privados-code-smell/index.html create mode 100644 pt/null-problematico.html create mode 100644 pt/operador-linq-join.html create mode 100644 pt/programacao-funcional-csharp/index.html create mode 100644 pt/programar-portugues-ou-ingles/index.html create mode 100644 pt/reduzir-complexidade-ciclomatica/index.html create mode 100644 pt/resenha-livro-programador-pragmatico/index.html create mode 100644 pt/revisao-codigo-vs-programacao-em-par/index.html create mode 100644 pt/testes-de-mutacao/index.html create mode 100644 pt/testes-unitarios-csharp-intro-tdd/index.html create mode 100644 pt/testes-unitarios-iniciantes-parte-2.html create mode 100644 pt/testes-unitarios-iniciantes-parte1.html create mode 100644 pt/tipos-de-comentarios-a-evitar/index.html create mode 100644 pt/tipos-valor-referencia-em-csharp-parte-2/index.html create mode 100644 pt/tipos-valor-referencia-em-csharp/index.html create mode 100644 pt/traducao-fases-estabilizacao/index.html create mode 100644 pt/value-objects-ferramenta/index.html create mode 100644 readings/index.html create mode 100644 rss.xml create mode 100644 search/index.html create mode 100644 sitemaps.xml create mode 100644 sobre/index.html create mode 100644 tag/agile/index.html create mode 100644 tag/automated-testing/index.html create mode 100644 tag/automated-tests/index.html create mode 100644 tag/beginners/index.html create mode 100644 tag/best practices/index.html create mode 100644 tag/best-practices/index.html create mode 100644 tag/blog/index.html create mode 100644 tag/blogging/index.html create mode 100644 tag/boas praticas/index.html create mode 100644 "tag/boas pr\303\241ticas/index.html" create mode 100644 tag/boas-praticas/index.html create mode 100644 "tag/boas-pr\303\241ticas/index.html" create mode 100644 tag/book review/index.html create mode 100644 tag/career-advice/index.html create mode 100644 tag/cargo cult programming/index.html create mode 100644 tag/carreira/index.html create mode 100644 tag/cobertura-de-codigo/index.html create mode 100644 tag/code review/index.html create mode 100644 tag/code smell/index.html create mode 100644 tag/code-coverage/index.html create mode 100644 tag/code-smell/index.html create mode 100644 "tag/coment\303\241rios/index.html" create mode 100644 tag/comments/index.html create mode 100644 tag/compartilhar/index.html create mode 100644 tag/configuracao/index.html create mode 100644 tag/controle-de-versao/index.html create mode 100644 tag/csharp/index.html create mode 100644 tag/ddd/index.html create mode 100644 tag/dotnet/index.html create mode 100644 tag/engenharia-de-software/index.html create mode 100644 tag/expressoes_regulares/index.html create mode 100644 tag/first post/index.html create mode 100644 tag/functional-programming/index.html create mode 100644 tag/git/index.html create mode 100644 tag/ingles/index.html create mode 100644 "tag/ingl\303\252s/index.html" create mode 100644 tag/iniciantes/index.html create mode 100644 "tag/integra\303\247\303\243o cont\303\255nua/index.html" create mode 100644 tag/legibilidade/index.html create mode 100644 tag/linq/index.html create mode 100644 tag/livros/index.html create mode 100644 tag/metodologias ageis/index.html create mode 100644 "tag/metodologias \303\241geis/index.html" create mode 100644 tag/metodologias-ageis/index.html create mode 100644 tag/modelagem-de-software/index.html create mode 100644 tag/mutation-testing/index.html create mode 100644 tag/oop/index.html create mode 100644 tag/orientacao-a-objetos/index.html create mode 100644 tag/pair programming/index.html create mode 100644 tag/primeiro post/index.html create mode 100644 tag/programacao cargo cult/index.html create mode 100644 tag/programacao em par/index.html create mode 100644 tag/programacao funcional/index.html create mode 100644 tag/programacao/index.html create mode 100644 "tag/programa\303\247\303\243o/index.html" create mode 100644 tag/programming/index.html create mode 100644 tag/readability/index.html create mode 100644 tag/recomendacoes/index.html create mode 100644 tag/regex/index.html create mode 100644 tag/regular_expressions/index.html create mode 100644 tag/revisao de codigo/index.html create mode 100644 tag/serie-testes-unitarios/index.html create mode 100644 tag/sharing/index.html create mode 100644 tag/software-design/index.html create mode 100644 tag/software-engineering/index.html create mode 100644 tag/software-testing/index.html create mode 100644 tag/tdd/index.html create mode 100644 tag/tempo/index.html create mode 100644 tag/testes automatizados/index.html create mode 100644 tag/testes de software/index.html create mode 100644 tag/testes-automatizados/index.html create mode 100644 tag/testes-de-mutacao/index.html create mode 100644 tag/testes-de-software/index.html create mode 100644 tag/testes-unitarios/index.html create mode 100644 tag/tfs/index.html create mode 100644 tag/tfvcs/index.html create mode 100644 tag/time/index.html create mode 100644 tag/tipagem/index.html create mode 100644 tag/traducoes/index.html create mode 100644 "tag/tradu\303\247\303\265es/index.html" create mode 100644 tag/tutorial/index.html create mode 100644 tag/type system/index.html create mode 100644 tag/unit-testing-series/index.html create mode 100644 tag/unit-testing/index.html create mode 100644 tag/version-control-system/index.html create mode 100644 tag_ptbr/agile/index.html create mode 100644 tag_ptbr/automated-testing/index.html create mode 100644 tag_ptbr/automated-tests/index.html create mode 100644 tag_ptbr/beginners/index.html create mode 100644 tag_ptbr/best practices/index.html create mode 100644 tag_ptbr/best-practices/index.html create mode 100644 tag_ptbr/blog/index.html create mode 100644 tag_ptbr/blogging/index.html create mode 100644 tag_ptbr/boas praticas/index.html create mode 100644 "tag_ptbr/boas pr\303\241ticas/index.html" create mode 100644 tag_ptbr/boas-praticas/index.html create mode 100644 "tag_ptbr/boas-pr\303\241ticas/index.html" create mode 100644 tag_ptbr/book review/index.html create mode 100644 tag_ptbr/career-advice/index.html create mode 100644 tag_ptbr/cargo cult programming/index.html create mode 100644 tag_ptbr/carreira/index.html create mode 100644 tag_ptbr/cobertura-de-codigo/index.html create mode 100644 tag_ptbr/code review/index.html create mode 100644 tag_ptbr/code smell/index.html create mode 100644 tag_ptbr/code-coverage/index.html create mode 100644 tag_ptbr/code-smell/index.html create mode 100644 "tag_ptbr/coment\303\241rios/index.html" create mode 100644 tag_ptbr/comments/index.html create mode 100644 tag_ptbr/compartilhar/index.html create mode 100644 tag_ptbr/configuracao/index.html create mode 100644 tag_ptbr/controle-de-versao/index.html create mode 100644 tag_ptbr/csharp/index.html create mode 100644 tag_ptbr/ddd/index.html create mode 100644 tag_ptbr/dotnet/index.html create mode 100644 tag_ptbr/engenharia-de-software/index.html create mode 100644 tag_ptbr/expressoes_regulares/index.html create mode 100644 tag_ptbr/first post/index.html create mode 100644 tag_ptbr/functional-programming/index.html create mode 100644 tag_ptbr/git/index.html create mode 100644 tag_ptbr/ingles/index.html create mode 100644 "tag_ptbr/ingl\303\252s/index.html" create mode 100644 tag_ptbr/iniciantes/index.html create mode 100644 "tag_ptbr/integra\303\247\303\243o cont\303\255nua/index.html" create mode 100644 tag_ptbr/legibilidade/index.html create mode 100644 tag_ptbr/linq/index.html create mode 100644 tag_ptbr/livros/index.html create mode 100644 tag_ptbr/metodologias ageis/index.html create mode 100644 "tag_ptbr/metodologias \303\241geis/index.html" create mode 100644 tag_ptbr/metodologias-ageis/index.html create mode 100644 tag_ptbr/modelagem-de-software/index.html create mode 100644 tag_ptbr/mutation-testing/index.html create mode 100644 tag_ptbr/oop/index.html create mode 100644 tag_ptbr/orientacao-a-objetos/index.html create mode 100644 tag_ptbr/pair programming/index.html create mode 100644 tag_ptbr/primeiro post/index.html create mode 100644 tag_ptbr/programacao cargo cult/index.html create mode 100644 tag_ptbr/programacao em par/index.html create mode 100644 tag_ptbr/programacao funcional/index.html create mode 100644 tag_ptbr/programacao/index.html create mode 100644 "tag_ptbr/programa\303\247\303\243o/index.html" create mode 100644 tag_ptbr/programming/index.html create mode 100644 tag_ptbr/readability/index.html create mode 100644 tag_ptbr/recomendacoes/index.html create mode 100644 tag_ptbr/regex/index.html create mode 100644 tag_ptbr/regular_expressions/index.html create mode 100644 tag_ptbr/revisao de codigo/index.html create mode 100644 tag_ptbr/serie-testes-unitarios/index.html create mode 100644 tag_ptbr/sharing/index.html create mode 100644 tag_ptbr/software-design/index.html create mode 100644 tag_ptbr/software-engineering/index.html create mode 100644 tag_ptbr/software-testing/index.html create mode 100644 tag_ptbr/tdd/index.html create mode 100644 tag_ptbr/tempo/index.html create mode 100644 tag_ptbr/testes automatizados/index.html create mode 100644 tag_ptbr/testes de software/index.html create mode 100644 tag_ptbr/testes-automatizados/index.html create mode 100644 tag_ptbr/testes-de-mutacao/index.html create mode 100644 tag_ptbr/testes-de-software/index.html create mode 100644 tag_ptbr/testes-unitarios/index.html create mode 100644 tag_ptbr/tfs/index.html create mode 100644 tag_ptbr/tfvcs/index.html create mode 100644 tag_ptbr/time/index.html create mode 100644 tag_ptbr/tipagem/index.html create mode 100644 tag_ptbr/traducoes/index.html create mode 100644 "tag_ptbr/tradu\303\247\303\265es/index.html" create mode 100644 tag_ptbr/tutorial/index.html create mode 100644 tag_ptbr/type system/index.html create mode 100644 tag_ptbr/unit-testing-series/index.html create mode 100644 tag_ptbr/unit-testing/index.html create mode 100644 tag_ptbr/version-control-system/index.html create mode 100644 unifai2017/index.html create mode 100644 unifai2018/index.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/AJ21/index.html b/AJ21/index.html new file mode 100644 index 00000000..ad92e3e9 --- /dev/null +++ b/AJ21/index.html @@ -0,0 +1,247 @@ + + + + + + + + Informações Sobre Conteúdos Ministrados Para ETEC Amim Jundi em 2021 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + pt +
+ + +
+
+
+ +
+

Informações Sobre Conteúdos Ministrados Para ETEC Amim Jundi em 2021

+
+ +
+

Informações sobre a palestra “Healthy Developer: Como Conciliar Sua Carreira na Tecnologia Com Um Estilo de Vida Saudável?” e vídeos de introdução a testes de software automatizados.

+ +

Esta página agrega todo o conteúdo relevante relativo à palestra ministrada por mim no dia 21 de maio de 2021, como parte da programação da Semana de Empreendedorismo Virtual da ETEC Amim Jundi. A página também incorpora vídeos que elaborei para os alunos da ETEC, como forma de introdução a testes automatizados de software.

+ +

Vídeos de Introdução a Testes Automatizados

+ +

Introdução a Testes Automatizados, Parte 1: Fundamentos

+ +

Vídeo

+ + + + + + +

Introdução a Testes Automatizados, Parte 2: Testes Unitários

+ +

Vídeo

+ + + + + + +

Introdução a Testes Automatizados, Parte 3: Selenium WebDriver

+ +

Vídeo

+ + + + + + + +

Introdução a Testes Automatizados, Parte 4: Selenium IDE

+ +

Vídeo

+ + + + + + +

Healthy Developer: Como Conciliar Sua Carreira na Tecnologia Com Um Estilo de Vida Saudável?

+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..3795b7be --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +carlosschults.net diff --git a/about/index.html b/about/index.html new file mode 100644 index 00000000..1f37c085 --- /dev/null +++ b/about/index.html @@ -0,0 +1,188 @@ + + + + + + + + About | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+
+ +
+

About

+
+ +
+

Hi. I’m Carlos.

+ +

Welcome to my blog! My name is Carlos Schults, a software engineer and technical writer based in Brazil.

+ +

While C# is the language I’m most experienced with, I worked with several technologies during my career, including Java, Python, PHP, and even VB.NET. Despite having +experience with frontend development (particularly with React as a framework and Typescript as a language), I specialize in backend software development.

+ +

Sporadically, I work as a freelancer technical author. Most of my work on that space has been done in partnership with Hit Subscribe, having written more than 200 posts for clients such as NDepend, NCrunch, Submain, Testim.io, TechBeacon, and many more.

+ +

I’m a firm believer in the thesis that if you really want to learn something, you have to teach it. In a nutshell, this blog exists so I can share helpful tidbits on software development in the hope they help someone else and in the hope I learn more in the process.

+ +

Open Invite

+ +

If you’d like to talk to me about software development or technology in general, then I want to talk to you. Here are some ways we can connect:

+ +
    +
  • If you’re a junior developer looking for mentorship, I can help you.
  • +
  • Found a typo or any type of mistake in one of my posts? Or even just disagree with something I’ve written? Let me know!
  • +
  • Do you want to review a piece of writing (e.g., a blog post) before you publish? I’d be happy to help.
  • +
  • If you have recommendations for interesting books, posts, articles, or podcasts, please send them my way!
  • +
  • Or anything, really. Feel free to contact me at:
  • +
+ +

carlos at carlosschults dot net

+ +

I look forward to hearing from you!

+ +
+ +
+ +
+
+ + + + + + + + diff --git a/browserconfig.xml b/browserconfig.xml new file mode 100644 index 00000000..c5541482 --- /dev/null +++ b/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/busca/index.html b/busca/index.html new file mode 100644 index 00000000..bdf1937a --- /dev/null +++ b/busca/index.html @@ -0,0 +1,174 @@ + + + + + + + + Busca | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+
+ +
+

Busca

+
+ +
+ + + + +
+ +
+ +
+
+ + + + + + + + diff --git a/como-aprender-ingles/index.html b/como-aprender-ingles/index.html new file mode 100644 index 00000000..7e41a862 --- /dev/null +++ b/como-aprender-ingles/index.html @@ -0,0 +1,187 @@ + + + + + + + + Sobre | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + pt +
+ + +
+
+
+ +
+

Sobre

+
+ +
+

Como Aprender Inglês : Apêndice

+ +

O objetivo desta página é reunir recursos relacionados ao aprendizado de inglês, conforme abordo na minha série de duas partes.

+ +

Curso “Inglês Para Desenvolvedores”

+ + +

Série Como Aprender Inglês - Um Guia Para Desenvolvedores

+ + +

Sites

+ + +

Canais no Youtube

+ + +
+ +
+ +
+
+ + + + + + + + diff --git a/css/main.css b/css/main.css new file mode 100644 index 00000000..4322f9a9 --- /dev/null +++ b/css/main.css @@ -0,0 +1,286 @@ +/** Reset some basic elements */ +body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; } + +/** Basic styling */ +body { font: 400 16px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; color: #111; background-color: #fdfdfd; -webkit-text-size-adjust: 100%; -webkit-font-feature-settings: "kern" 1; -moz-font-feature-settings: "kern" 1; -o-font-feature-settings: "kern" 1; font-feature-settings: "kern" 1; font-kerning: normal; } + +/** Set `margin-bottom` to maintain vertical rhythm */ +h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, dl, figure, .highlight { margin-bottom: 15px; } + +/** Images */ +img { max-width: 100%; vertical-align: middle; } + +/** Figures */ +figure > img { display: block; } + +figcaption { font-size: 14px; } + +/** Lists */ +ul, ol { margin-left: 30px; } + +li > ul, li > ol { margin-bottom: 0; } + +/** Headings */ +h1, h2, h3, h4, h5, h6 { font-weight: 400; } + +/** Links */ +a { color: #2a7ae2; text-decoration: none; } + +a:visited { color: #1756a9; } + +a:hover { color: #111; text-decoration: underline; } + +/** Blockquotes */ +blockquote { color: #828282; border-left: 4px solid #e8e8e8; padding-left: 15px; font-size: 18px; letter-spacing: -1px; font-style: italic; } + +blockquote > :last-child { margin-bottom: 0; } + +/** Code formatting */ +pre, code { font-size: 15px; border: 1px solid #e8e8e8; border-radius: 3px; background-color: #eef; } + +code { padding: 1px 5px; } + +pre { padding: 8px 12px; overflow-x: auto; } + +pre > code { border: 0; padding-right: 0; padding-left: 0; } + +table { border-collapse: collapse; border-spacing: 3px; border: 2px solid black; margin-bottom: 10px; } + +th { border: 2px solid #000000; } + +td { border: 1px solid #000000; } + +/** Wrapper */ +.wrapper { max-width: -webkit-calc(800px - (30px * 2)); max-width: calc(800px - (30px * 2)); margin-right: auto; margin-left: auto; padding-right: 30px; padding-left: 30px; } + +@media screen and (max-width: 800px) { .wrapper { max-width: -webkit-calc(800px - (30px)); max-width: calc(800px - (30px)); padding-right: 15px; padding-left: 15px; } } + +/** Clearfix */ +.footer-col-wrapper:after, .wrapper:after { content: ""; display: table; clear: both; } + +/** Icons */ +.icon > svg { display: inline-block; width: 16px; height: 16px; vertical-align: middle; } + +.icon > svg path { fill: #828282; } + +/* Styles for callouts */ +.callout { border-left: 5px solid #0074d9; padding: 10px; margin: 10px 0; border-radius: 5px; background-color: #f8f8f8; position: relative; } + +.callout .callout-title { font-weight: bold; margin-top: 0; margin-bottom: 10px; display: flex; align-items: center; } + +.callout .callout-icon { margin-right: 10px; font-size: 1.5em; } + +.callout-info { border-left-color: #0074d9; } + +.callout-warning { border-left-color: #ff851b; } + +.callout-success { border-left-color: #2ecc40; } + +.callout-error { border-left-color: #ff4136; } + +.callout-question { border-left-color: #8a2be2; } + +.callout-tip { border-left-color: #2e8b57; /* Dark-ish green color */ } + +/** Site header */ +.site-header { border-top: 5px solid #424242; border-bottom: 1px solid #e8e8e8; min-height: 56px; background: #2D3339; position: relative; } + +.site-title { font-size: 26px; font-weight: 300; line-height: 56px; letter-spacing: -1px; margin-bottom: 0; float: left; } + +.site-title, .site-title:visited { color: #ccc; } + +.site-nav { float: right; line-height: 56px; } + +.site-nav .menu-icon { display: none; } + +.site-nav .page-link { color: #fff; line-height: 1.5; } + +.site-nav .page-link:not(:last-child) { margin-right: 20px; } + +@media screen and (max-width: 600px) { .site-nav { position: absolute; top: 9px; right: 15px; background-color: #2D3339; border: 1px solid #e8e8e8; border-radius: 5px; text-align: right; } .site-nav .menu-icon { display: block; float: right; width: 36px; height: 26px; line-height: 0; padding-top: 10px; text-align: center; } .site-nav .menu-icon > svg { width: 18px; height: 15px; } .site-nav .menu-icon > svg path { fill: #424242; } .site-nav .trigger { clear: both; display: none; } .site-nav:hover .trigger { display: block; padding-bottom: 5px; } .site-nav .page-link { display: block; padding: 5px 10px; margin-left: 20px; } .site-nav .page-link:not(:last-child) { margin-right: 0; } } + +/** Site footer */ +.site-footer { border-top: 1px solid #e8e8e8; padding: 30px 0; } + +.footer-heading { font-size: 18px; margin-bottom: 15px; } + +.contact-list, .social-media-list { list-style: none; margin-left: 0; } + +.footer-col-wrapper { font-size: 15px; color: #828282; margin-left: -15px; } + +.footer-col { float: left; margin-bottom: 15px; padding-left: 15px; } + +.footer-col-1 { width: -webkit-calc(35% - (30px / 2)); width: calc(35% - (30px / 2)); } + +.footer-col-2 { width: -webkit-calc(20% - (30px / 2)); width: calc(20% - (30px / 2)); } + +.footer-col-3 { width: -webkit-calc(45% - (30px / 2)); width: calc(45% - (30px / 2)); } + +@media screen and (max-width: 800px) { .footer-col-1, .footer-col-2 { width: -webkit-calc(50% - (30px / 2)); width: calc(50% - (30px / 2)); } .footer-col-3 { width: -webkit-calc(100% - (30px / 2)); width: calc(100% - (30px / 2)); } } + +@media screen and (max-width: 600px) { .footer-col { float: none; width: -webkit-calc(100% - (30px / 2)); width: calc(100% - (30px / 2)); } } + +/** Page content */ +.page-content { padding: 30px 0; } + +.page-heading { font-size: 20px; } + +.post-list { margin-left: 0; list-style: none; } + +.post-list > li { margin-bottom: 30px; } + +.post-meta { font-size: 14px; color: #828282; } + +.post-link { display: block; font-size: 24px; } + +/** Posts */ +.post-header { margin-bottom: 30px; } + +.post-title { font-size: 42px; letter-spacing: -1px; line-height: 1; } + +@media screen and (max-width: 800px) { .post-title { font-size: 36px; } } + +#disqus_thread { margin-top: 100px; } + +.post-content { margin-bottom: 30px; } + +.post-content a.previous { margin-top: 30px; display: block; float: left; } + +.post-content a.next { margin-top: 30px; display: block; float: right; } + +.post-content h2 { font-size: 32px; } + +@media screen and (max-width: 800px) { .post-content h2 { font-size: 28px; } } + +.post-content h3 { font-size: 26px; } + +@media screen and (max-width: 800px) { .post-content h3 { font-size: 22px; } } + +.post-content h4 { font-size: 20px; } + +@media screen and (max-width: 800px) { .post-content h4 { font-size: 18px; } } + +/** Syntax highlighting styles */ +.highlight { background: #fff; } + +.highlighter-rouge .highlight { background: #eef; } + +.highlight .c { color: #998; font-style: italic; } + +.highlight .err { color: #a61717; background-color: #e3d2d2; } + +.highlight .k { font-weight: bold; } + +.highlight .o { font-weight: bold; } + +.highlight .cm { color: #998; font-style: italic; } + +.highlight .cp { color: #999; font-weight: bold; } + +.highlight .c1 { color: #998; font-style: italic; } + +.highlight .cs { color: #999; font-weight: bold; font-style: italic; } + +.highlight .gd { color: #000; background-color: #fdd; } + +.highlight .gd .x { color: #000; background-color: #faa; } + +.highlight .ge { font-style: italic; } + +.highlight .gr { color: #a00; } + +.highlight .gh { color: #999; } + +.highlight .gi { color: #000; background-color: #dfd; } + +.highlight .gi .x { color: #000; background-color: #afa; } + +.highlight .go { color: #888; } + +.highlight .gp { color: #555; } + +.highlight .gs { font-weight: bold; } + +.highlight .gu { color: #aaa; } + +.highlight .gt { color: #a00; } + +.highlight .kc { font-weight: bold; } + +.highlight .kd { font-weight: bold; } + +.highlight .kp { font-weight: bold; } + +.highlight .kr { font-weight: bold; } + +.highlight .kt { color: #458; font-weight: bold; } + +.highlight .m { color: #099; } + +.highlight .s { color: #d14; } + +.highlight .na { color: #008080; } + +.highlight .nb { color: #0086B3; } + +.highlight .nc { color: #458; font-weight: bold; } + +.highlight .no { color: #008080; } + +.highlight .ni { color: #800080; } + +.highlight .ne { color: #900; font-weight: bold; } + +.highlight .nf { color: #900; font-weight: bold; } + +.highlight .nn { color: #555; } + +.highlight .nt { color: #000080; } + +.highlight .nv { color: #008080; } + +.highlight .ow { font-weight: bold; } + +.highlight .w { color: #bbb; } + +.highlight .mf { color: #099; } + +.highlight .mh { color: #099; } + +.highlight .mi { color: #099; } + +.highlight .mo { color: #099; } + +.highlight .sb { color: #d14; } + +.highlight .sc { color: #d14; } + +.highlight .sd { color: #d14; } + +.highlight .s2 { color: #d14; } + +.highlight .se { color: #d14; } + +.highlight .sh { color: #d14; } + +.highlight .si { color: #d14; } + +.highlight .sx { color: #d14; } + +.highlight .sr { color: #009926; } + +.highlight .s1 { color: #d14; } + +.highlight .ss { color: #990073; } + +.highlight .bp { color: #999; } + +.highlight .vc { color: #008080; } + +.highlight .vg { color: #008080; } + +.highlight .vi { color: #008080; } + +.highlight .il { color: #099; } + +/*# sourceMappingURL=main.css.map */ \ No newline at end of file diff --git a/css/main.css.map b/css/main.css.map new file mode 100644 index 00000000..ca88275a --- /dev/null +++ b/css/main.css.map @@ -0,0 +1,18 @@ +{ + "version": 3, + "file": "main.css", + "sources": [ + "main.scss", + "_sass/_base.scss", + "_sass/_layout.scss", + "_sass/_syntax-highlighting.scss" + ], + "sourcesContent": [ + "@charset \"utf-8\";\n\n\n\n// Our variables\n$base-font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n$base-font-size: 16px;\n$base-font-weight: 400;\n$small-font-size: $base-font-size * 0.875;\n$base-line-height: 1.5;\n\n$spacing-unit: 30px;\n\n$text-color: #111;\n$background-color: #fdfdfd;\n$brand-color: #2a7ae2;\n\n$grey-color: #828282;\n$grey-color-light: lighten($grey-color, 40%);\n$grey-color-dark: darken($grey-color, 25%);\n\n// Width of the content area\n$content-width: 800px;\n\n$on-palm: 600px;\n$on-laptop: 800px;\n\n\n\n// Use media queries like this:\n// @include media-query($on-palm) {\n// .wrapper {\n// padding-right: $spacing-unit / 2;\n// padding-left: $spacing-unit / 2;\n// }\n// }\n@mixin media-query($device) {\n @media screen and (max-width: $device) {\n @content;\n }\n}\n\n\n\n// Import partials from `sass_dir` (defaults to `_sass`)\n@import\n \"base\",\n \"layout\",\n \"syntax-highlighting\"\n;\n", + "/**\n * Reset some basic elements\n */\nbody, h1, h2, h3, h4, h5, h6,\np, blockquote, pre, hr,\ndl, dd, ol, ul, figure {\n margin: 0;\n padding: 0;\n}\n\n\n\n/**\n * Basic styling\n */\nbody {\n font: $base-font-weight #{$base-font-size}/#{$base-line-height} $base-font-family;\n color: $text-color;\n background-color: $background-color; \n -webkit-text-size-adjust: 100%;\n -webkit-font-feature-settings: \"kern\" 1;\n -moz-font-feature-settings: \"kern\" 1;\n -o-font-feature-settings: \"kern\" 1;\n font-feature-settings: \"kern\" 1;\n font-kerning: normal;\n}\n\n\n\n/**\n * Set `margin-bottom` to maintain vertical rhythm\n */\nh1, h2, h3, h4, h5, h6,\np, blockquote, pre,\nul, ol, dl, figure,\n%vertical-rhythm {\n margin-bottom: $spacing-unit / 2;\n}\n\n\n\n/**\n * Images\n */\nimg {\n max-width: 100%;\n vertical-align: middle;\n}\n\n\n\n/**\n * Figures\n */\nfigure > img {\n display: block;\n}\n\nfigcaption {\n font-size: $small-font-size;\n}\n\n\n\n/**\n * Lists\n */\nul, ol {\n margin-left: $spacing-unit;\n}\n\nli {\n > ul,\n > ol {\n margin-bottom: 0;\n }\n}\n\n\n\n/**\n * Headings\n */\nh1, h2, h3, h4, h5, h6 {\n font-weight: $base-font-weight;\n}\n\n\n\n/**\n * Links\n */\na {\n color: $brand-color;\n text-decoration: none;\n\n &:visited {\n color: darken($brand-color, 15%);\n }\n\n &:hover {\n color: $text-color;\n text-decoration: underline;\n }\n}\n\n\n\n/**\n * Blockquotes\n */\nblockquote {\n color: $grey-color;\n border-left: 4px solid $grey-color-light;\n padding-left: $spacing-unit / 2;\n font-size: 18px;\n letter-spacing: -1px;\n font-style: italic;\n\n > :last-child {\n margin-bottom: 0;\n }\n}\n\n\n\n/**\n * Code formatting\n */\npre,\ncode {\n font-size: 15px;\n border: 1px solid $grey-color-light;\n border-radius: 3px;\n background-color: #eef;\n}\n\ncode {\n padding: 1px 5px;\n}\n\npre {\n padding: 8px 12px;\n overflow-x: auto;\n\n > code {\n border: 0;\n padding-right: 0;\n padding-left: 0;\n }\n}\n\ntable{\n border-collapse: collapse;\n border-spacing: 3px;\n border:2px solid black;\n margin-bottom: 10px;\n}\n\nth{\n border:2px solid #000000;\n}\n\ntd{\n border:1px solid #000000;\n}\n\n\n\n/**\n * Wrapper\n */\n.wrapper {\n max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2));\n max-width: calc(#{$content-width} - (#{$spacing-unit} * 2));\n margin-right: auto;\n margin-left: auto;\n padding-right: $spacing-unit;\n padding-left: $spacing-unit;\n @extend %clearfix;\n\n @include media-query($on-laptop) {\n max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit}));\n max-width: calc(#{$content-width} - (#{$spacing-unit}));\n padding-right: $spacing-unit / 2;\n padding-left: $spacing-unit / 2;\n }\n}\n\n\n\n/**\n * Clearfix\n */\n%clearfix {\n\n &:after {\n content: \"\";\n display: table;\n clear: both;\n }\n}\n\n/**\n * Icons\n */\n .icon {\n\n > svg {\n display: inline-block;\n width: 16px;\n height: 16px;\n vertical-align: middle;\n\n path {\n fill: $grey-color;\n }\n }\n}\n\n/* Styles for callouts */\n.callout {\n border-left: 5px solid #0074d9;\n padding: 10px;\n margin: 10px 0;\n border-radius: 5px;\n background-color: #f8f8f8;\n position: relative;\n }\n \n .callout .callout-title {\n font-weight: bold;\n margin-top: 0;\n margin-bottom: 10px;\n display: flex;\n align-items: center;\n }\n \n .callout .callout-icon {\n margin-right: 10px;\n font-size: 1.5em;\n }\n \n .callout-info {\n border-left-color: #0074d9;\n }\n \n .callout-warning {\n border-left-color: #ff851b;\n }\n \n .callout-success {\n border-left-color: #2ecc40;\n }\n \n .callout-error {\n border-left-color: #ff4136;\n }\n \n .callout-question {\n border-left-color: #8a2be2;\n }\n \n .callout-tip {\n border-left-color: #2e8b57; /* Dark-ish green color */\n }\n ", + "/**\n * Site header\n */\n.site-header {\n border-top: 5px solid $grey-color-dark;\n border-bottom: 1px solid $grey-color-light;\n min-height: 56px;\n background: #2D3339;\n \n // Positioning context for the mobile navigation icon\n position: relative;\n}\n\n.site-title {\n font-size: 26px;\n font-weight: 300;\n line-height: 56px;\n letter-spacing: -1px;\n margin-bottom: 0;\n float: left;\n\n &,\n &:visited {\n color: #ccc;\n }\n}\n\n.site-nav {\n float: right;\n line-height: 56px;\n\n .menu-icon {\n display: none;\n }\n\n .page-link {\n color: #fff;\n line-height: $base-line-height;\n\n // Gaps between nav items, but not on the last one\n &:not(:last-child) {\n margin-right: 20px;\n }\n }\n\n @include media-query($on-palm) {\n position: absolute;\n top: 9px;\n right: $spacing-unit / 2;\n background-color: #2D3339; \n border: 1px solid $grey-color-light;\n border-radius: 5px;\n text-align: right;\n\n .menu-icon {\n display: block;\n float: right;\n width: 36px;\n height: 26px;\n line-height: 0;\n padding-top: 10px;\n text-align: center;\n\n > svg {\n width: 18px;\n height: 15px;\n\n path {\n fill: $grey-color-dark;\n }\n }\n }\n\n .trigger {\n clear: both;\n display: none;\n }\n\n &:hover .trigger {\n display: block;\n padding-bottom: 5px;\n }\n\n .page-link {\n display: block;\n padding: 5px 10px;\n\n &:not(:last-child) {\n margin-right: 0;\n }\n margin-left: 20px;\n }\n }\n}\n\n\n\n/**\n * Site footer\n */\n.site-footer {\n border-top: 1px solid $grey-color-light;\n padding: $spacing-unit 0; \n}\n\n.footer-heading {\n font-size: 18px;\n margin-bottom: $spacing-unit / 2;\n}\n\n.contact-list,\n.social-media-list {\n list-style: none;\n margin-left: 0;\n}\n\n.footer-col-wrapper {\n font-size: 15px;\n color: $grey-color;\n margin-left: -$spacing-unit / 2;\n @extend %clearfix;\n}\n\n.footer-col {\n float: left;\n margin-bottom: $spacing-unit / 2;\n padding-left: $spacing-unit / 2;\n}\n\n.footer-col-1 {\n width: -webkit-calc(35% - (#{$spacing-unit} / 2));\n width: calc(35% - (#{$spacing-unit} / 2));\n}\n\n.footer-col-2 {\n width: -webkit-calc(20% - (#{$spacing-unit} / 2));\n width: calc(20% - (#{$spacing-unit} / 2));\n}\n\n.footer-col-3 {\n width: -webkit-calc(45% - (#{$spacing-unit} / 2));\n width: calc(45% - (#{$spacing-unit} / 2));\n}\n\n@include media-query($on-laptop) {\n .footer-col-1,\n .footer-col-2 {\n width: -webkit-calc(50% - (#{$spacing-unit} / 2));\n width: calc(50% - (#{$spacing-unit} / 2));\n }\n\n .footer-col-3 {\n width: -webkit-calc(100% - (#{$spacing-unit} / 2));\n width: calc(100% - (#{$spacing-unit} / 2));\n }\n}\n\n@include media-query($on-palm) {\n .footer-col {\n float: none;\n width: -webkit-calc(100% - (#{$spacing-unit} / 2));\n width: calc(100% - (#{$spacing-unit} / 2));\n }\n}\n\n\n\n/**\n * Page content\n */\n.page-content {\n padding: $spacing-unit 0;\n}\n\n.page-heading {\n font-size: 20px;\n}\n\n.post-list {\n margin-left: 0;\n list-style: none;\n\n > li {\n margin-bottom: $spacing-unit;\n }\n}\n\n.post-meta {\n font-size: $small-font-size;\n color: $grey-color;\n}\n\n.post-link {\n display: block;\n font-size: 24px;\n}\n\n\n\n/**\n * Posts\n */\n.post-header {\n margin-bottom: $spacing-unit;\n}\n\n.post-title {\n font-size: 42px;\n letter-spacing: -1px;\n line-height: 1;\n\n @include media-query($on-laptop) {\n font-size: 36px;\n }\n}\n\n#disqus_thread {\n margin-top: 100px;\n}\n\n.post-content {\n margin-bottom: $spacing-unit;\n\n a.previous {\n margin-top: 30px;\n\tdisplay:block;\n\tfloat: left;\n }\n\n a.next {\n margin-top: 30px;\n\tdisplay: block;\n\tfloat: right;\n }\n\n h2 {\n font-size: 32px;\n\n @include media-query($on-laptop) {\n font-size: 28px;\n }\n }\n\n h3 {\n font-size: 26px;\n\n @include media-query($on-laptop) {\n font-size: 22px;\n }\n }\n\n h4 {\n font-size: 20px;\n\n @include media-query($on-laptop) {\n font-size: 18px;\n }\n }\n}\n", + "/**\n * Syntax highlighting styles\n */\n.highlight {\n background: #fff;\n @extend %vertical-rhythm;\n\n .highlighter-rouge & {\n background: #eef;\n }\n\n .c { color: #998; font-style: italic } // Comment\n .err { color: #a61717; background-color: #e3d2d2 } // Error\n .k { font-weight: bold } // Keyword\n .o { font-weight: bold } // Operator\n .cm { color: #998; font-style: italic } // Comment.Multiline\n .cp { color: #999; font-weight: bold } // Comment.Preproc\n .c1 { color: #998; font-style: italic } // Comment.Single\n .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special\n .gd { color: #000; background-color: #fdd } // Generic.Deleted\n .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific\n .ge { font-style: italic } // Generic.Emph\n .gr { color: #a00 } // Generic.Error\n .gh { color: #999 } // Generic.Heading\n .gi { color: #000; background-color: #dfd } // Generic.Inserted\n .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific\n .go { color: #888 } // Generic.Output\n .gp { color: #555 } // Generic.Prompt\n .gs { font-weight: bold } // Generic.Strong\n .gu { color: #aaa } // Generic.Subheading\n .gt { color: #a00 } // Generic.Traceback\n .kc { font-weight: bold } // Keyword.Constant\n .kd { font-weight: bold } // Keyword.Declaration\n .kp { font-weight: bold } // Keyword.Pseudo\n .kr { font-weight: bold } // Keyword.Reserved\n .kt { color: #458; font-weight: bold } // Keyword.Type\n .m { color: #099 } // Literal.Number\n .s { color: #d14 } // Literal.String\n .na { color: #008080 } // Name.Attribute\n .nb { color: #0086B3 } // Name.Builtin\n .nc { color: #458; font-weight: bold } // Name.Class\n .no { color: #008080 } // Name.Constant\n .ni { color: #800080 } // Name.Entity\n .ne { color: #900; font-weight: bold } // Name.Exception\n .nf { color: #900; font-weight: bold } // Name.Function\n .nn { color: #555 } // Name.Namespace\n .nt { color: #000080 } // Name.Tag\n .nv { color: #008080 } // Name.Variable\n .ow { font-weight: bold } // Operator.Word\n .w { color: #bbb } // Text.Whitespace\n .mf { color: #099 } // Literal.Number.Float\n .mh { color: #099 } // Literal.Number.Hex\n .mi { color: #099 } // Literal.Number.Integer\n .mo { color: #099 } // Literal.Number.Oct\n .sb { color: #d14 } // Literal.String.Backtick\n .sc { color: #d14 } // Literal.String.Char\n .sd { color: #d14 } // Literal.String.Doc\n .s2 { color: #d14 } // Literal.String.Double\n .se { color: #d14 } // Literal.String.Escape\n .sh { color: #d14 } // Literal.String.Heredoc\n .si { color: #d14 } // Literal.String.Interpol\n .sx { color: #d14 } // Literal.String.Other\n .sr { color: #009926 } // Literal.String.Regex\n .s1 { color: #d14 } // Literal.String.Single\n .ss { color: #990073 } // Literal.String.Symbol\n .bp { color: #999 } // Name.Builtin.Pseudo\n .vc { color: #008080 } // Name.Variable.Class\n .vg { color: #008080 } // Name.Variable.Global\n .vi { color: #008080 } // Name.Variable.Instance\n .il { color: #099 } // Literal.Number.Integer.Long\n}\n" + ], + "names": [], + "mappings": "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" +} \ No newline at end of file diff --git a/en/4-common-datetime-mistakes-csharp/index.html b/en/4-common-datetime-mistakes-csharp/index.html new file mode 100644 index 00000000..f3c9d0d5 --- /dev/null +++ b/en/4-common-datetime-mistakes-csharp/index.html @@ -0,0 +1,559 @@ + + + + + + + + 4 Common Datetime Mistakes in C# — And How to Avoid Them | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

4 Common Datetime Mistakes in C# — And How to Avoid Them

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the SubMain blog. You can check out the original here, at their site. While you’re there, have a look at CodeIt.Right, which can help you with time-related issues and much more.

+ +

Do you remember the “falsehoods programmers believe about X” meme that became popular among software blogs a few years ago? The first one was about names, but several others soon followed, covering topics such as addresses, geography, and online shopping.

+ +

My favorite was the one about time. I hadn’t thought deeply about time and its intricacies up until that point, and I was intrigued by how a fundamental domain could be such a fertile ground for misunderstandings.

+ +

Now even though I like the post, I have a problem with it: it lists wrong assumptions, and then it basically stops there. The reader is likely to leave the article wondering:

+ +
    +
  • Why are these assumptions falsehoods?
  • +
  • How likely is it that I’ll get in trouble due to one of these assumptions?
  • +
  • What’s the proper way of dealing with these issues?
  • +
+ +

The article is interesting food for thought, but I think it’d make sense to provide more actionable information.

+ +

That’s what today’s post is about. I’m going to show you four common mistakes C#/.NET developers make when dealing with time. And that’s not all. I’ll also show what you should do to avoid them and make your code safer and easier to reason about.

+ +

1. Naively Calculating Durations

+ +

Consider the code below:

+ + + +

Will this code work? It depends on where and when it’s going to run.

+ +

When you use DateTime.Now, the DateTime you get represents the current date and time local to your machine (i.e., it has the Kind property set to Local).

+ +

If you live in an area that observes DST (Daylight Saving Time), you know there’s one day in the year when all clocks must be moved forward a certain amount of time (generally one hour, but there are places that adjust by other offsets). Of course, there’s also the day when the opposite happens.

+ +

Now picture this: today is March 12th, 2017, and you live in New York City. You start using the program above. The StartMatch() method runs at exactly 01:00 AM. One hour and 15 minutes later, the EndMatch() method runs. The calculation is performed, and the following text is shown:

+ +

Duration of the match: 00:02:15

+ +

I bet you’ve correctly guessed what just happened here: when clocks were about to hit 2 AM, DST just kicked in and moved them straight to 3 AM. Then EndMatch got back the current time, effectively adding a whole hour to the calculation. If the same had happened at the end of DST, the result would’ve been just 15 minutes!

+ +

Sure, the code above is just a toy example, but what if it were a payroll application? Would you like to pay an employee the wrong amount?

+ +

What to Do?

+ +

When calculating the duration of human activities, use UTC for the start and end dates. That way, you’ll be able to** unambiguously point to an instant in time**. Instead of using the Now property on DateTime, use `UtcNow to retrieve the date time already in UTC to perform the calculations:

+ + + +

What if the DateTime objects you already have are set to Local? In that case, you should use the ToUniversalTime() method to convert them to UTC:

+ + + +

A Little Warning About ToUniversalTime()

+ +

The usage of ToUniversalTime() — and its sibling, ToLocalTime()— can be a little tricky. The problem is that these methods make assumptions about what you want based on the value of the Kind property of your date, and that can cause unexpected results.

+ +

When calling ToUniversalTime(), one of the following things will happen:

+ +
    +
  • If Kind is set to UTC, then the same value is returned.
  • +
  • On the other hand, if it’s set to Local, the corresponding value in UTC is returned.
  • +
  • Finally, if Kind is set to Unspecified,** then it’s assumed the datetime is meant to be local, **and the corresponding UTC datetime is returned.
  • +
+ +

The problem we have here is that local times don’t roundtrip. They’re local as long as they don’t leave the context of your machine. If you save a local datetime to a database and then retrieve it back, the information that’s supposed to be local is lost: now it’s unspecified.

+ +

So, the following scenario can happen:

+ +
    +
  • You retrieve the current date and time using DateTime.UtcNow.
  • +
  • You save it to the database.
  • +
  • Another part of the code retrieves this value and, unaware that it’s supposed to already be in UTC, calls ToUniversalTime() on it.
  • +
  • Since the datetime is unspecified, the method will treat it as Local and perform an unnecessary conversion, generating a wrong value.
  • +
+ +

How do you prevent this? It’s a recommended practice to use UTC to record the time when an event happened. My suggestion here is to follow this advice and also to make it explicit that you’re doing so. Append the “UTC” suffix to every database column and class property that holds a UTC datetime. Instead of Created, change it to CreatedUTC and so on. It’s not as pretty, but it’s definitely more clear.

+ +

2. Not Using UTC When It Should Be Used (and Vice Versa)

+ +

We could define this as a universal rule: use UTC to record the time when events happened. When logging, auditing, and recording all types of timestamps in your application, UTC is the way to go.

+ +

So, use UTC everywhere! …Right? Nope, not so fast.

+ +

Let’s say you need to be able to reconstruct the local datetime — to the user’s perspective — of when something happened, and the only information you have is a timestamp in UTC. That’s a piece of bad luck.

+ +

In cases like this, it’d make more sense to either (a) store the datetime in UTC along with the user’s time zone or (b) use the DateTimeOffset type, which will record the local date along with the UTC offset, enabling you to reconstruct the UTC date from it when you need it.

+ +

Another common use case where UTC is not the right solution is scheduling future local events. You wouldn’t want to wake up one hour later or earlier in the days of DST transitions, right? That’s exactly what would happen if you’d set your alarm clock by UTC.

+ +

3. Not Validating User Input

+ +

Let’s say you’ve created a simple Windows desktop app that lets users set reminders for themselves. The user enters the date and time at which they want to receive the reminder, clicks a button, and that’s it.

+ +

Everything seems to be working fine until a user from Brazil emails you, complaining the reminder she set for October 15th at 12:15 AM didn’t work. What happened?

+ +

DST Strikes Back

+ +

The villain here is good old Daylight Saving Time again. In 2017, DST in Brazil started at midnight on October 15th. (Remember that Brazil is in the southern hemisphere.) So, the date-time combination the user supplied simply didn’t exist in her time zone!

+ +

Of course, the opposite problem is also possible. When DST ends and clocks turn backward by one hour, this generates ambiguous times.

+ +

What Is the Remedy?

+ +

How do you deal with those issues as a C# developer? The TimeZoneInfo class has got you covered. It not only represents a time zone but it also provides methods to check for a datetime validity:

+ + + +

What should you do then? What should replace the “do something” comments in the snippets above?

+ +

You could show the user a message saying the input date is invalid. Or you could preemptively choose another date for the user.

+ +

Let’s talk about invalid times first. Your options: move forward or backward. It’s somewhat of an arbitrary decision, so which one should you pick? For instance, the Google Calendar app on Android chooses the former. And it makes sense when you think about it. That’s exactly what your clocks already did due to DST. Why shouldn’t you do the same?

+ +

And what about ambiguous times? You also have two options: choose between the first and second occurrences. Then again, it’s somewhat arbitrary, but my advice is to pick the first one. Since you have to choose one, why not make things simpler?

+ +

4. Mistaking an Offset for a Time Zone

+ +

Consider the following timestamp: 1995-07-14T13:05:00.0000000-03:00. When asked what the -03:00 at the end is called, many developers answer, “a time zone.”

+ +

Here’s the thing. They probably correctly assume that the number represents the offset from UTC. Also, they’d probably see that you can get the corresponding time in UTC from the offset. (Many developers fail to understand that in a string like this, the offset is already applied: to get the UTC time, you should invert the offset sign. Only then should you add it to the time.)

+ +

The mistake is in thinking that the offset is all there is to a time zone. It’s not. A time zone is a geographical area, and it consists of many pieces of information, such as:

+ +
    +
  • One or more offsets. (DST is a thing, after all.)
  • +
  • The dates when DST transitions happen. (These can and do change whenever governments feel like it.)
  • +
  • The amount of time applied when transitions happened. (It’s not one hour everywhere.)
  • +
  • The historical records of changes to the above rules.
  • +
+ +

In short: don’t try to guess a time zone by the offset. You’ll be wrong most of the time.

+ +

It’s About Time…You Learn About Time!

+ +

This list is by no means exhaustive. I only wanted to give you a quick start in the fascinating and somewhat bizarre world of datetime issues. There are plenty of valuable resources out there for you to learn from, such as the time zone tag on Stack Overflow or blogs such as Jon Skeet’s and Matt Johnson’s, who are authors of the popular NodaTime library.

+ +

And of course, always use the tools at your disposal. For instance, SubMain’s CodeIt.Right has a rule to force you to specify a IFormatProvider in situations where it’s optional, which can save you from nasty bugs when parsing dates.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/are-private-methods-a-code-smell/index.html b/en/are-private-methods-a-code-smell/index.html new file mode 100644 index 00000000..5fa76bfb --- /dev/null +++ b/en/are-private-methods-a-code-smell/index.html @@ -0,0 +1,601 @@ + + + + + + + + Are private methods a code smell? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Are private methods a code smell?

+ +
+ +
+

+ +

Some people believe private methods should be avoided. Are they right? +

+ +

A couple of months ago, Marcos Douglas published a post about how the use of rules and constraints can help you keep your code clean and maintainable*. This premise keeps showing up again and again around the web, and I totally agree with it.

+ +

Marcos lays out several useful guidelines such as the ideal number of arguments in a method, the ideal numbers of methods in a class, and so on. The post is very good, and I think you should all check it out, but it is not the focus of today’s post.

+ +

Instead, I want to talk about a subject that showed up in the comment’s thread: private methods as a code smell.

+ +

Since I’d never heard something along those lines, I was naturally surprised and decided to do some research.

+ +

What’s the matter with private methods?

+ +

First, let’s try to understand why would private methods be a problem.

+ +

One common argument is that private methods violate the Single Responsibility Principle. The SRP states that each class should do only one thing. If you’re tempted to create private methods, the argument follows, that’s a sign that your class is doing too much.

+ +
+

Private helper methods indicate classes are doing too many things. Moving private helper methods to different classes, including creating new classes if necessary, splits the original responsibilities across multiple classes leading to simpler, better designs.

+ +

Kent R Spillner, in Private Methods are a Code Smell

+
+ +

Here is another similar view:

+ +
+

Private methods are not inherently bad, but they are a sign that you might be missing out on an opportunity to make a useful abstraction. If you have a private method that calls another private method, then there is almost certainly an area of responsibility that remains unidentified.

+ +

John McDowall, in Break. It. Up! – Private Method Access Modifiers as Code Smells

+
+ +

Another argument is that private methods make unit testing difficult:

+ +
+

Make it public!

+ +

[…]This is probably the simplest way to overcome the problem of untestability.[…] There’s a reason for that: testability is a perfectly good reason to make something public. And you should test most of your code.

+
+ +
+

Jason M Baker, in Enemies of Test Driven Development part I: encapsulation

+
+ +

Finally, people also argue that private methods play an important role in messing with internal states in objects, which can get you in real trouble.

+ +
+

Functional programming teaches that state (in the form of member variables) is evil, because it makes your code more complex and harder to test.

+ +

Ryan Ginstrom, in Three reasons to avoid private class members

+
+ +

I’ve just outlined some of the common arguments against the creation of private methods, so now it’s time to show my opinions on this.

+ +

Private methods are not necessarily SRP violations

+ +

The first argument presented states that private methods violate the Single Responsibility Principle.

+ +
+

Private helper methods indicate classes are doing too many things.

+
+ +

I don’t think that’s the case. At least, not always. It depends on what the private method is doing.

+ +

You probably shouldn’t add a method called ValidateEmailAddress to your Customer class, whether private or not. After all, a customer is not the only entity that can have an email address. Instead, create an Email class and put all the pertinent validations in it.

+ +

On the other hand, let’s say you’re creating a Sort method for a custom data structure. In this case, it’d make a lot of sense to keep the Sort method public, and have some auxiliary private methods, such as CompareItems and Swap.

+ +
+

Moving private helper methods to different classes, including creating new classes if necessary, splits the original responsibilities across multiple classes leading to simpler, better designs.

+
+ +

My main issue with this argument is not that small classes are generally better than large ones, which I agree.

+ +

My problem is that I don’t agree that creating new classes and public methods just for the sake of avoiding private methods will automatically lead to “simpler, better designs”. It sure can; but it can lead you to worse designs as well. Each situation is unique.

+ +

I don’t buy testability for testability’s sake

+ +

I really like unit tests (and automated tests in general). I helped evangelize unit testing in my workplace, and I’m currently supervising the team that is adding unit and integration tests to our codebase.

+ +

And one of the first questions that people ask when you’re teaching unit testing to them is: How do I unit test private methods?

+ +

+ +

My answer usually is: you shouldn’t. IMHO, it’s just not that productive to put a lot of effort into testing private methods: since they are called by the public ones, they’re going to be exercised by your tests anyway.

+ +

The goal of a unit test should be to test and document a “unit” (a class) by using its public API. Which leads us to the next point.

+ +

Your public API should be stable!

+ +

API stands for “Application Programming Interface”. This term can mean a bunch of things, but in this context, think of the API as the set of all public classes and methods that your application exposes to consumers.

+ +

The API acts as a kind of contract between you and your consumers. It’s a deal. If you alter the deal, the other party won’t be happy.

+ +

+ +

Your public API should be as stable as possible. This is specially true when you’re writing a web service, a library, or any kind of tool that other parties depend on.

+ +

By the way, this third party doesn’t have to be geographically distant from you. It’s common for a medium to large company to have several teams that depend on code provided by each other. What would happen if each team constantly made drastic changes in their APIs? Chaos.

+ +

When you expose a method publicly, from that moment on you’re “forced” to keep that method working and honoring its contract; otherwise, your consumers will suffer with breaking changes in their code!

+ +

A good usage of private methods can help ensure proper encapsulation in your design.

+ +

Here’s yet another quote from Kent R Spillner:

+ +
+

Sometimes, private methods are created just to give pieces of functionality more descriptive names. Although descriptive names are desirable, creating private methods to provide descriptive names for things is still a smell. Moving these methods to collaborators and making them public creates opportunities for future reuse without reducing the clarity of the original code.

+
+ +

This is one of the points I most vehemently disagree with. I often create private methods for the exact reason Kent R Spillner criticizes here, i.e. giving descriptive names for chunks of code, a habit I developed after reading Robert C. Martin’s book Clean Code.

+ +

Mr. Spillner defends that the proper way to deal with this should be to move these methods to other classes and make them public.

+ +

But in doing that, I’ve just added a new public method to the public API of my system! Now it’s one more method to document, test and support, even though it was never meant to be part of the public API.

+ +

Here we have a definition for access modifiers that I think is spot on:

+ +
+

public - this method is part of the published API and will not change within major versions of the class

+ +

[…]

+ +

private - this method was refactored out of a well tested public or protected method for reasons of clarity or internal re-use. This method may absolutely change, even in patch releases, and should not be relied upon to even exist.

+
+ +

I subscribe to this definition. Thus, in my opinion:

+ +
    +
  • Private methods are not necessarily a bad thing to be avoided at all costs.
  • +
  • Making private methods public don’t automatically lead to better design; it can also lead to an unnecessary inflated API, weak encapsulation, and increased maintenance overhead.
  • +
  • Testability is a noble goal, but should be pursued pragmatically. Well tested and documented public methods should be enough, for most cases.
  • +
+ +

Private methods can be good or bad; learn to tell them apart

+ +

All being said, I do think there are cases in which private methods are used in a wrong way. Like any other tool, they can be abused. You should probably watch out for some red flags.

+ +

If a private method is at a different level of abstraction than the public ones in a class, it’s a sign that it belongs in another class. Reading/writing to a file is at a lower level than calculating an employee’s monthly payment, for instance.

+ +

When a private method is so complex that you really, really wished you could unit test it…then it probably should be made public. (Before you point out my apparent contradiction, I’m not saying that every private method should be made public in order to become testable…just the ones who cross some threshold of complexity).

+ + + + +

What about a private method that contains duplicated code, as in, copied and pasted from another class…? Get rid of the duplication immediately!

+ +

So, here is the thing: two out of the three signs I’ve just outlined are somewhat subjective. At some point, you have to make some choices. How complex is complex enough for a private method to need unit testing? How to properly tell about different levels of abstractions?

+ +

The best tip I can offer is: Use an extra pair of eyes. Always have another person look and examine your code before you check it in. Pair-programming and/or code review are great techniques, not only for improving design and catching bugs, but also for spreading knowledge across a team. Not only technical knowledge, but domain knowledge as well, and that can make the difference when the time comes to make those tough decisions.

+ +

In conclusion

+ +

Although private methods can be used in bad ways, I think it’s premature to automatically label them as a bad thing and something to be avoided.

+ +

It seems to me that some of the people that claim to be arguing against private methods are in fact arguing against issues that are orthogonal to private methods; you can violate SRP with and without private methods; you can mess with internal mutable state with and without private methods, and so on.

+ +

Software development is an art, full of trade-offs and uncertainty. And while rules-of-thumbs can be useful, they should not be followed blindly.

+ +

This post turned out way longer than I intended. Thanks if you’ve made this far. See you next time!

+ +

References

+ + + +

* The author has given me permission to translate the article to English. Here is the original version, in Portuguese.

+ + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/book-review-pragmatic-programmer/index.html b/en/book-review-pragmatic-programmer/index.html new file mode 100644 index 00000000..f44851fe --- /dev/null +++ b/en/book-review-pragmatic-programmer/index.html @@ -0,0 +1,449 @@ + + + + + + + + Book Review: The Pragmatic Programmer | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Book Review: The Pragmatic Programmer

+ +
+ +
+

+If I had to choose one book, just one book, to elect as the number one must-read to every programmer, I’d choose “The Pragmatic Programmer”. It’s a no-brainer. It’s just that good. +

+ +

The Pragmatic Programmer: From Journeyman to Master is a book about software engineering by Andrew Hunt and David Thomas, published in October 1999. The book is organized in short, self-contained chapters, that you can read in any order you’d like. Each chapter features tips (there are 70 in total) that offer advice on several subjects, like estimating, testing, debugging, how to prototype, how to communicate effectively, best practices about exception handling, and a whole lot more.

+ +

Each chapter also has exercises and/or challenges. What’s the difference? All the exercises have answers, and you can find them in the appendix in the end of the book. The challenges, on the other hand, are not supposed to have clear answers. They are designed to make you think, reflect and (guess what!) challenge yourself and the way you currently do things.

+ +

One thing I really like about this book is that it is very practical. Of course theory has its value and its place, and I personally believe that a lot of programmers lack knowledge in the fundamentals of Computer Science and that really hurts our industry. That said, I think it’s awesome that two programmers took the time to translate their years of experience and knowledge into a book that goes straight to the point with very practical advice that you can put in use right away!

+ +

Another point I’d like to highlight is how easy and fun it is to read this book. Its chapters and sections are short, providing a very comfortable pace. It also has a great sense of humor. Not the type that makes you laugh hysterically, but the type that makes you feel at ease, as if the book was a conversation. But I think the number one thing I love about “The Pragmatic Programmer” is that it isn’t really focused on code, or tied to a particular technology, or to particular tools. Sure, it has its fair share of code samples (mostly Java and C/C++). Yeah, it mentions some particular tools and applications. But for the most part, this book is about a mindset. A certain way of thinking, a way of approaching problems and challenges. Once this mindset, this “ +Pragmatic Philosophy” is really ingrained in your way of thinking, you’ll be able to apply it to a lot of areas in your professional life, not just coding. And I think this is the real strength of this book. Had it been focused on tools or a specific language, I probably wouldn’t be writing about it now, almost 17 year later.

+ +

A little bit of cons

+ +

Of course, now that I have sang the many praises of this book, let me talk about some bad things in it. And, to be honest, it’s not that easy to find something bad to say about it.But if there’s one thing that I think most readers would agree, is that some parts of it are somewhat outdated.

+ +

I mean, come on! It’s been almost two decades! It’s amazing for a software development book to remain influential for this long. Of course at least some parts must be outdated. For example, one of the tips is to always use version control. Nowadays, version control is something that we take for granted, every developer worth his/her salt knows what Github is, so it’s almost funny to read that recommendation. It is like when you watch Steve Jobs giving the first iPhone presentation, and the audience is mesmerized about its capabilities, that are weak by today’s standards, but were amazing for them at the time. (Yeah, I know there are companies out there in which developers don’t even know about version control. My tip is: if you work in a place like this, try to evangelize version control to them. If you succeed, great! If you don’t, get out as soon as possible.)

+ +

In another point of the book, they explain a technique called “tracer-bullet development”. The name may be a little strange, but when they start to explain it, you may find that it sounds a lot like the “minimum viable product” concept, that you may be familiar with from the agile methodologies.

+ +

Which shouldn’t be a surprise at all, since Andy Thomas and Dave Hunt were among the signatories of the now legendary Manifesto For Agile Software Development.

+ +

Conclusion

+ +

That’s why is so hard to find anything wrong with this book. You see, it may seem a little outdated today, but that’s just because the authors were way ahead of their time. Some things that are commonplace and obvious today, we’re totally non-obvious and even counter-intuitive almost 20 years ago. It took a lot of vision to write this book, and for this, and all of the above, I think it’s a very worth read.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/cargo-cult-programming/index.html b/en/cargo-cult-programming/index.html new file mode 100644 index 00000000..b51a4a43 --- /dev/null +++ b/en/cargo-cult-programming/index.html @@ -0,0 +1,581 @@ + + + + + + + + Cargo Cult Programming Is The Art of Programming by Coincidence | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Cargo Cult Programming Is The Art of Programming by Coincidence

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the NDepend blog. You can check out the original here, at their site. While you’re there, download NDepend and give it a try.

+ +

I first learned about cargo cult programming a few years ago. I remember thinking back then, “What a strange name for a programming-related concept.”

+ +

If you share my past self’s astonishment, then today’s post is for you!

+ +

First, you’ll see what cargo cult programming is and why you should care. Then, we’re going to look at some practical examples, using the C# language. Finally, we’ll close with advice about what you can do, as a developer, to avoid falling into this trap.

+ +

Cargo Cult Programming: Doing Stuff Just Because

+ +

According to Wikipedia, “Cargo cult programming is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose.”

+ +

In other words, it’s when a developer writes code without really understanding it. The developer may use a very trial-and-error approach—maybe copy and paste some code from somewhere else and then tweak it and test it until works, or sort of works. Then the developer will stop tweaking the code, for fear it will stop working. In the process, maybe they leave some lines of code that don’t do anything.

+ +

Or maybe they tried to use an idiom they picked up from another developer while failing to understand that the contexts are different and it’s useless in the current situation.

+ +

Finally, it might just be lack of education: maybe the developer has a poor mental model of how the tools they’re using really work.

+ +

Why is Cargo Cult Programming a Problem?

+

As Eric Lippert puts it, cargo cult programmers struggle to make meaningful changes to a program and end up using a trial-and-error approach since they don’t understand the inner workings of the code they’re about to change.

+ +

This is not so different from what the Pragmatic Bookshelf calls “programming by coincidence”:

+ +
+

Fred doesn’t know why the code is failing because he didn’t know why it worked in the first place. It seemed to work, given the limited “testing” that Fred did, but that was just a coincidence.

+
+ +

That single sentence pretty much sums it up for me: if you don’t know how or why your code works, neither will you understand what happened when it no longer works.

+ +

Origin of the Term

+

Although practices that are considered cargo cult today have been recorded as early as the late 19th century, the term itself dates from 1945, when it was first used to describe practices that emerged during and after World War II between Melanesian islanders.

+ +

These islanders would mimic the soldiers’ behavior, such as dressing up as flight controllers and waving sticks, hoping that airplanes would descend from the skies with a lot of cargo.

+ +

Since then, the term cargo cult has been used in a variety of contexts to mean to imitate form without content—to perfectly copy the superficial elements while failing to understand the deeper meanings and workings of whatever one’s trying to emulate.

+ +

Talk is Cheap; Show Me the Code!

+

Enough with the history lesson. Time to see some code! I’m going to show you five examples of cargo cult programming in the C# language.

+ +

Checking a Non-Nullable Value Type for Null

+

This one is a pet peeve of mine since I see it a lot in production code. It goes like this:

+ +
	public Product Find(int id)
+	{
+   	   if (id != null) // this check is useless
+	   {
+	       Console.WriteLine("This line will always get reached.");
+	   }
+	
+	   return new Product();
+	}
+ +

Here we have a developer that probably doesn’t grok the difference between value and reference types. It would be completely forgivable, in the case of a junior developer, except for the fact that the compiler warns you about that.

+ +

You could argue that I’m nitpicking. After all, the code will run fine in spite of this. In fact, the check won’t even be included in the resulting IL, as you can see from this print of a decompiling tool:

+ +

An image depicting a code excerpt that does not contain the null check.

+ +

You can see in this code snippet that the compiler has optimized the null check out.

+ +

There are plenty of worse problems, granted. Yes, the application won’t crash because of this. So what’s the big deal?

+ +

Well, for starters, I’d be worried about a development shop where the sole quality measure was “it runs without crashing.” But the real problem is that this type of code shows a lack of understanding of some fundamental characteristics of the language and platform that can bite you in the future.

+ +

Unnecessary Use of ToList() in LINQ to Object Queries

+

Like the previous one, this is something I routinely see in production code. Consider the code below:

+ +
	var result = users.ToList()
+	.Where(x => x.PremiumUser)
+	.ToList()
+	.Select(x => new { Name = x.Name, Birth = x.DateOfBirth })
+	.ToList();
+ +

The problem we have here is that these calls to ToList() are completely unnecessary (except maybe the last one, if you really needed the result to be a List and not only an IEnumerable).

+ +

In my experience, this happens when the developer doesn’t understand the nature of LINQ; they erroneously think that the LINQ methods belong to the concrete type List<T> instead of being extension methods that can be used with any IEnumerable<T> implementation.

+ +

By calling ToList() several times like this, the developer creates several new lists, which can be detrimental to the performance of the application.

+ +

You could rewrite the code above like this:

+ +
	var result = users.Where(x => x.PremiumUser).Select(x => new { Name = x.Name, Birth = x.DateOfBirth });
+ +

Unnecessary Conversions

+

Consider the following line:

+ +
	DateTime creationDate = DateTime.Parse(row["creation_date"].ToString());
+ +

Here we have not only one but two unnecessary conversions. First, the developer creates a new string and then parses it to DateTime when a simple cast would have sufficed:

+ +
	DateTime creationDate = (DateTime)row["creation_date"];
+ +

This example assumes that the underlying database type is some specific type for dealing with dates (for instance, date or datetime in SQL Server). Of course, if you were using an inadequate type (such as varchar) then this would be a problem of its own.

+ +

Try-Catch Everywhere

+

Also known as Pokémon syndrome (“Gotta catch ’em all!”), the anti-pattern here is to add a try-catch block to every single line that could possibly throw an exception.

+ +

Bonus points if the code is attempting to catch System.Exception instead of a more specific exception, thus blurring the distinction between expected and unexpected errors.

+ +

More bonus points if the catch block doesn’t contain any code at all!

+ +

The general advice here is this: never catch unless you have a very specific reason for doing so. Otherwise, just the let the exception bubble up until it’s dealt with by the top-level exception handler.

+ +

If this advice seems vague (“How would I know if I have the right reason for catching an exception?”), that’s because it is vague. It’s beyond the scope of this post to go deeper into this matter, but Eric Lippert’s excellent article called “Vexing Exceptions” will greatly improve your understanding of exception handling.

+ +

Using StringBuilder Everywhere

+

It’s the stuff of superhero movies: after reading somewhere that concatenating strings by using the ‘+’ operator is incredibly inefficient, the well-meaning developer takes upon themselves the Herculean task of updating every single concatenation in the codebase to StringBuilder.

+ +

The reasoning for this is, of course, that System.String is immutable. So every time you “modify” a string, you’re in fact creating a new instance in memory, which can hurt performance pretty badly.

+ +

Well, guess what? The compiler is pretty smart. Let’s say you have the following line:

+ +
	string a = "Hello " + "World";
+ +

This, in fact, gets translated to

+ +
	string a = "Hello World";
+ +

The fast rule of thumb is it’s fine to use the simple concatenation when you know the number of strings to append in compile time. Otherwise, a StringBuilder probably makes more sense.

+ +

Of course, some scenarios aren’t that clear-cut. The only advice worth giving here is to do your homework. When in doubt, research and benchmark to your heart’s content.

+ +

I’ll leave you with more sound advice from Eric Lippert:

+ +
+

Unnecessary code changes are expensive and dangerous; don’t make performance-based changes unless you’ve identified a performance problem.

+
+ +

Is There a Remedy?

+

I’d say it’s fair to assume that more inexperienced developers are more prone to commit mistakes due to cargo cult programming. But no developer is really immune to it, independent of their knowledge or experience.

+ +

We’re only human after all. Tiredness, deadlines, cognitive biases, and (to be really honest) the eventual laziness can turn even the best developer into a cargo cult programmer.

+ +

Unfortunately, there’s no 100% guaranteed way of preventing this from happening. Yet there are some measures you could take to, at least, decrease the odds.

+ +

Let’s take a look at some of them.

+ +

Use Code Review/Pair Programming

+

The first measure you could take to avoid cargo cult programming is to simply get a second pair of eyes on your code. The benefits of having a second person reviewing each line of code before it goes to production can’t be overstated. And while code review and pair programming aren’t perfect equivalents, both of these practices will bring you this benefit.

+ +

Always Test Your Hypothesis

+

Write unit tests (and other types of tests as well). Monitor your application in production. If something doesn’t perform well, benchmark the heck out of it. Don’t just assume things. Testing your hypothesis can bring valuable insights and save you when your intuition gets it wrong.

+ +

Read Other People’s Code

+

Reading other people’s code is a great way to learn. It’s a perfect tool to compare your own ideas and assumptions against what other developers are doing, exposing you to novel concepts that can force you to gain a deeper understanding of the issues at hand.

+ +

In the era of GitHub, there isn’t much of an excuse for not doing that.

+ +

Learn From Your Tools

+

There are currently a plethora of tools that can help your team improve the quality of their code. Here’s the thing, though: you shouldn’t just use these tools. You should also learn from them. If you use NDepend, read about its rules. Try and understand the rationale behind them. What are the principles and best practices that guided its authors when coming up with the rules?

+ +

The same goes for other types of tools—and even the warnings the compiler gives you.

+ +

Computer Science, Not Computer Superstition

+

Even though no one is immune to cargo cult programming, we should strive to overcome it. There’s hard-earned industry wisdom at our disposal, slowly generated over more than seven decades. Let’s use it. Let’s understand our tools and our craft and write better software.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/code-review-vs-pair-programming/index.html b/en/code-review-vs-pair-programming/index.html new file mode 100644 index 00000000..2545f9c5 --- /dev/null +++ b/en/code-review-vs-pair-programming/index.html @@ -0,0 +1,551 @@ + + + + + + + + Code Review vs Pair-Programming: Which One Should Your Team Pick? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Code Review vs Pair-Programming: Which One Should Your Team Pick?

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the SubMain blog. You can check out the original here, at their site. While you’re there, have a look at CodeIt.Right, which can help you with automated code reviews.

+ +

Some weeks ago, I was browsing Twitter when I saw this:

+ + + + +

This prompted a brief discussion between the author and me. He made good arguments, but I left unconvinced that pair programming was the obvious winner.

+ +

As someone who’s implemented code review with success and also paired to some extent, I could see how both practices can be valuable. But is one of them clearly better than the other? Are code review and pair programming interchangeable, or are there scenarios in which one clearly shines?

+ +

That’s what I’m going to answer today. Let’s dive in.

+ +

What I Mean By Code Review

+ +

Picture this: you’re a young programmer on your first development job. After you finish your first assignment, they call you to a meeting room; there you find your tech lead and three senior developers. There’s also a large monitor displaying your code. Time for review!

+ +

For two-and-a-half excruciating hours, they scrutinize your work while you sweat profusely. From criticizing your high-level design decisions to nitpicking over the most trivial stylistic preferences, nothing gets a free pass.

+ +

Is this the scene your mind conjures when you see the words “code review”?

+ +

Good news, then. That’s not the kind of review I’m talking about. Instead, think of a very informal and lightweight process. You submit your code for review by creating a pull request or maybe using some embedded functionality on your IDE.

+ +

The Good

+ +

After touching briefly on the what and how of a code review, let’s get to the why. Why should your team adopt this practice? What are the benefits?

+ +

The first reason is, not surprisingly, to catch bugs. I’d bet you’re familiar with that old piece of software wisdom that says that the later a defect is found, the higher the cost of fixing it. Then why not use a relatively cheap process that can catch up to 60% of defects?

+ +

Here’s another reason your company should perform code reviews: to improve the readability of the code. Trying to read and understand some new piece of code frequently leads to the discovery of issues such as

+ + + +

The reviewer could also spot overlooked corner cases or help the author assess how performative their code is.

+ +

And here’s one last reason. A well-done code review can spread knowledge throughout the team. This improves the product’s quality by destroying knowledge silos.

+ +

The Bad

+ +

While some say code reviews are the number one practice you should adopt to improve your code, this kind of enthusiasm is not universal. So, what are the potential drawbacks?

+ +

For the most part, their complaint is time. When you submit some code for review, you’ll have to wait until the reviewer is done.

+ +

What should you do while waiting? Ideally, your team should break up the available work in small, discrete units so it can work on these pieces somewhat independently. That’s not always feasible, though. And by the way, the constant switching of tasks might be detrimental to the developer’s focus and productivity.

+ +

Let’s say Bob spends x hours implementing a feature. Then Alice reviews his work and says his implementation is completely wrong, and he needs to start from scratch. Those x development hours were just thrown away.

+ +

Finally, people sometimes will waste ridiculous amounts of time arguing on pointless stylistic details, such as the position of braces or whether or not to include an underscore before a private field’s name. These debates can unfortunately escalate to levels that turn the workplace toxic.

+ +

Pair Programming: Not Just a Super Code Review

+ +

Pair programming is a technique in which two developers collaborate on the code together, sitting at one workstation.

+ +

They periodically take turns in two roles. The driver writes the code, thinking out loud in order to explain their design decisions and thought process. The navigator observes the driver’s work, giving real-time feedback and advice.

+ +

So, is it just “code review on steroids”, as put by Jeff Atwood?

+ +

Maybe not. One of the basic principles of agile methodologies is the shorter your feedback loop, the better you are. You can see how getting someone to review your code sooner rather than later works in harmony with the principles that make agile so successful.

+ +

The Good

+ +

Well, it should be no surprise that many benefits of pair programming are also benefits of code reviews, such as fewer bugs, improvement in code readability, and knowledge dispersion throughout the team.

+ +

Pair programming may provide exclusive benefits as well, such as:

+ + + +

The Bad

+ +

As in the case of the code review, pair programming is far from being a universally accepted practice. While many developers love it, others don’t have such happy stories to tell. So, what are some of the most cited problems with pairing?

+ +

Let’s start with one common complaint: pair programming can be exhausting. In fact, many claim that pairing is more effective when used for shorter blocks of time—from one and a half to two and a half hours.

+ +

Obviously, an odd number of team members doesn’t work well for pair programming. But a shifting number of available personnel is inevitable.

+ +

Next on our list of problems is the fact that paring isn’t very remote friendly. You can better imagine the issue after hearing what Daniel Kaplan, who wrote “What It’s Like to Pair for a Year,” had to say about pairing:

+ +
+

These scheduling interruptions happen, but on a typical day we avoid them by having the pairs show up at the same time (for breakfast and standup), go to lunch at the same time, and leave at the same time. This maximizes the time the pairs are pairing.

+
+ +

So, pairing requires synchronicity, which might make it a non-option for remote teams (or even co-located teams with flexible hours).

+ +

Some people argue that pairing can undermine creativity and prevent experimentation. While pairing, it’d be rude to waste your pair’s time trying some experimental approach that might ultimately end up not working. So, the safest possible design tends to always prevail, even if it’s not the best possible one.

+ +

Finally, pairing doesn’t really provide one of the key benefits of the after-the-fact code review: a person with zero context analyzing the code. The two developers share a context from the beginning of the session, and the effect this has cannot be underestimated. People tend to overvalue their contributions and get emotionally attached to what they create; that’s why it’s so important to get a second person that doesn’t have this attachment and is thus able to provide a clearer judgment.

+ +

Code Review vs Pair Programming: The Verdict?

+ +

I’ve reached the conclusion that, although code review and pair programming seem equivalent, they’re really not. There is some overlap, but each practice also presents some unique benefits and challenges.

+ +

There’s no getting around that pair programming, despite its benefits, requires an even number of people, working at the same time. If your team consists of developers living across several time zones (or even a co-located team with extremely flexible hours), then it’s a no-brainer: code review to the rescue.

+ +

If your team doesn’t fit the above description, then give pair programming a try. As long as you work hard to accommodate and have empathy for different kinds of personalities and don’t make it mandatory, it can be beneficial to your team.

+ +

Finally, there’s nothing stopping you from using both. You could adopt pair programming as the default MO and leave soloing and code review to fill in the gaps where pair programming doesn’t quite fit so well.

+ +

No Matter What You Do, Embrace Automation

+ +

Imagine you write for a publication, such as a magazine. After you have a draft, you submit it for review. Would it make sense for the editor to spend all their time looking for spelling errors? Of course not! We have automated spell-check for that, freeing the editor to look for more high-level problems, such as poorly chosen words, lack of cohesion, inappropriate tone, and all those things your English teacher kept nagging you about in high school.

+ +

With software, things should not be so different. By using an automated code review tool, you can eliminate a lot of the bickering that often occurs in code reviews or pair programming sessions. There will be no arguing about naming and formatting conventions, the position of brackets, and others pointless trivia.

+ +

You can also employ a static analysis tool to warn you about potential bugs and opportunities for refactoring. That way, the reviewer/navigator is free to focus on the high-level stuff that requires human creativity, intelligence, and empathy.

+ +

Trust and Respect

+ +

While researching for this post, one theme kept reappearing: that code review emerges from a lack of trust in our developers or that pair programming infantilizes them.

+ +

I couldn’t disagree more.

+ +

Precisely because we respect our developers—and our clients—we should employ techniques and tools at our disposal to improve the quality of our work.

+ +

It’s not about lack of trust. It’s about recognizing that programming is hard and sometimes, just one brain isn’t up to the task.

+ + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/coding-best-practices-short-time/index.html b/en/coding-best-practices-short-time/index.html new file mode 100644 index 00000000..2335fb36 --- /dev/null +++ b/en/coding-best-practices-short-time/index.html @@ -0,0 +1,533 @@ + + + + + + + + Coding Best Practices When You’re Short On Time | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Coding Best Practices When You’re Short On Time

+ +
+ +
+

+Photo by Ales Nesetril on Unsplash

+ +

Editorial note: I originally wrote this post for the SubMain blog. You can check out the original here, at their site. While you’re there, download and try their CodeIt.Right product.

+ +

One topic in software development that really fascinates me is coding best practices. I’m always searching for ways to improve my work and deliver value in a fast and consistent manner.

+ +

It can be tricky to define what a “coding best practice” is. Some people are even in favor of downright retiring the term! But one thing pretty much everyone agrees upon is this: coming up with and implementing strategies—by whatever name you call them—to improve the output of one’s work is something that any developer worth his or her salt should be continuously doing.

+ +

Of course, there’s no free lunch. The adoption of a best practice takes time…and sometimes you just don’t have much of that to begin with. And then there’s management, whose buy-in is not always guaranteed.

+ +

So, what to do if your development team is struggling with the poor quality of a codebase while lacking time to implement best practices that would help?

+ +

The answer I offer you today is what I’ll call the “coding best practices emergency pack”: a small list of coding best practices that you can adopt on relatively short notice to get your team and your codebase from utter chaos to a more manageable state.

+ +

Because there’s lots of advice on coding best practices out there, to the point where it’s hard not to feel overwhelmed, I narrowed down my list of emergency-pack best practices by requiring they meet three criteria:

+ +
    +
  • They must be fundamental, in the sense that they’re the building blocks with which you can implement more sophisticated practices later.
  • +
  • You can adopt them in relatively short notice. (I’d say a week is feasible.)
  • +
  • Their cost is free or very low.
  • +
+ +

The practices that follow all fit these parameters. And without further ado, here it is: my coding best practices emergency pack, with items listed in the order they should be implemented and starting with the most critical one.

+ +

Version Control System

+ +

I once worked for a software development shop where no version control system was used. The source files were placed in a shared folder that every developer could access. What was the process we used when editing a file? Yeah, you guessed it:  we’d simply create a copy of the file and rename it to “filename_old.ext” or something like that.

+ +

This was about eight or nine years ago. So maybe things have improved, right? Well, they certainly have, to some extent, but not completely. There are still companies out there that don’t use a VCS.

+ +

How to Proceed?

+ +

From now on, I’ll just assume you agree that a VCS is a fundamental coding best practice. If that’s not the case, there’s plenty of resources out there explaining what a VCS is and why should you use one.

+ +

With that out of the way, it’s time to get to specifics. Which tool should you use? How to go about its adoption?

+ +

Git is a solid choice. And despite having a steeper learning curve for those more used to centralized version control systems, such as Subversion or TFVC, it’s de facto standard in our industry. So by all means, learn it, since not doing so can harm your career in the future.

+ +

But it’s possible that Git is not the best choice for your team right now. Remember, you’re short on time. So we need to get your team to adopt these coding best practices ASAP.

+ +

How do we do this? So, let’s say you have experience with Subversion, having used it at your previous company, but you have no experience with Git at all. If that’s the case, I’d say Subversion is the best choice for you. The overhead of learning a new system and teaching it to your co-workers while putting it into production would be too great.

+ +

Code Review

+ +

I’m not going to lie: I love code reviews—and I’m not alone in that. I’ve witnessed firsthand how a good code review can reduce the number of bugs in a codebase, make the code look and feel more consistent, and perhaps best of all, spread knowledge throughout a development team.

+ +

And here’s a major selling point: a code review practice is relatively easy to implement. Start as simple as you can, and then tweak and experiment with your approach as the need arises.

+ +

What Do I Mean by Code Review?

+ +

Talking about “code review” can be tricky. People sometimes mean widely different things when they use the term, so I think it warrants further clarification.

+ +

I’m not in favor of a highly stressful and bureaucratic code review process, where your code is scrutinized and criticized in public for hours. I don’t believe in public shaming as a tool for achieving quality. On the contrary, the type of code review I advocate for is a lightweight and low-stress process, usually initiated by submitting a pull request or using your favorite IDE.

+ +

How to Proceed 

+ +

Since we’re now on the same page about what a code review should look like, how would one go about implementing the practice? My answer is, not surprisingly, “the simplest way that could possibly work.” 

+ +

For instance, if yours is a .NET shop using TFS/TFVC, you can start by installing a check-in policy that requires a code review for each check-in. If your team uses GitHub, you can use pull requests. Just start performing reviews so you and your team can get used to it. Then, with time, start tuning and perfecting your approach.

+ +

Here are some of the questions that can appear as you refine your process for this:

+ +
    +
  • What’s the goal of a code review? Are we looking for bugs? Trying to improve readability? Checking adherence to the company’s coding standard?
  • +
  • Where do we draw the line between “suggestions” and “impediments”? Is it OK to give a thumbs-down to someone’s code for bad indentation or a slightly off variable name?
  • +
  • What do when reviewer and reviewee can’t come to a consensus? Bring in a mediator to give the final word? And who should be this mediator? The lead developer?
  • +
+ +

The answer to all of these questions can be found in automation. Much of the awkwardness of a code review can be removed when you employ a code analyzer to handle the automatable portions of the process.

+ +

For instance, SubMain’s CodeIt.Right will give you real-time feedback from inside Visual Studio, alerting you of possible coding issues and even automatically fix code smells and violations for you.

+ +

By employing automation, you set your developers free to worry about higher level concerns when performing reviews, such as code clarity or architectural decisions.

+ +

Automated Builds

+ +

You may be thinking that I’ve got it wrong. After all, does it even make sense to talk about automated builds without mentioning automated tests?

+ +

Well, I’m going argue that yes, it does make sense, and for one very simple reason: it eliminates “it works on my machine” syndrome. 

+ +

By having a central place where builds are performed, you shed light on all kinds of problems, from poor management of dependencies to bad test discipline.

+ +

How to Proceed

+ +

My advice here is the same as before: do the simplest thing that could work.

+ +

If your team already uses TFS, then learn how to create a build definition and you’re good to go. On the other hand, if you host your projects on GitHub, you might be interested in taking a look at Travis CI.

+ +

With time, you should improve your strategy. Remember the static code analyzers I mentioned earlier? You can integrate them into your build process. Unit testing and other kinds of automated tests are a very important addition as well.

+ +

Speaking of which…

+ +

Notable Absences

+ +

You might be surprised to see that I haven’t included unit testing in the list of coding best practices, despite being myself a firm believer in the importance of automated testing to the overall quality of a codebase. And why is that?

+ +

Adding unit tests to a legacy application, unfortunately, is hard, to the point that there’s even a famous bookthat focuses solely on this. It’s just not a feasible task for you to tackle quickly.

+ +

In a similar fashion, it’s possible that a portion of readers expected me to talk about clean code or the SOLIDprinciples. I do encourage you to research and learn about these topics,  but I don’t think they’re a good fit for the purpose of this post. They are, as the name already points out, principles. Think of them as philosophical guidelines—useful, but not as easy to break down into simple, actionable advice.

+ +

Deploy Your Package ASAP!

+ +

It’s possible that some of you found these practices to be extremely basic and not post-worthy. “Who doesn’t use version control in twenty-freaking-eighteen???” I hear you saying.

+ +

Well, it really doesn’t take long to find evidence (anecdotal, but still) that things are not all sunshine and rainbows. To believe that even basic coding best practices, such as using version control or automated testing, are universally applied is probably more wishful thinking than what we’d like to believe.

+ +

For the rest of you, I hope this list proves useful.

+ +

You know what they say. “When in a hole, stop digging.” And that’s exactly the type of help I wanted to offer with this post: a quick and easy fix, meant to give you and your teammates just enough sanity that you can focus and regain control of your application, ensuring its long-term health.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/csharp-7-features-part-2/index.html b/en/csharp-7-features-part-2/index.html new file mode 100644 index 00000000..f481c58a --- /dev/null +++ b/en/csharp-7-features-part-2/index.html @@ -0,0 +1,584 @@ + + + + + + + + C# 7 Features Worth Knowing - Part 2 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# 7 Features Worth Knowing - Part 2

+ +
+ +
+

+ +

In this post we’ll see some more new features from C# 7.0. +

+ +

In the first part of this series, we talked about some new features from C#, namely: literal improvements, out variables, more expression-bodied members and throw expressions.

+ +

Today we’ll see: Tuples and Local Functions. But before we go on, I’d like to thank my friend Gunter Italiano Ribeiro for reviewing this article.

+ +

Tuples

+ +

Have you ever felt the need to write a method that returned more than one value? I’d bet you have. In previous versions of the C# language, there were some options available. You could use an out parameter, or even create a type for that, but each one of these had their own problems. Out parameters are non-intuitive and can complicate the design; creating a custom type just for this can be overkill.

+ +

In C# 7.0 you have a new option, by using tuple types and tuple literals. With this feature you can easily declare a method that returns more than one value. Let’s see an example:

+ + + +

You’re probably familiar with the TryXXX pattern, used, for instance, in the System.Int32 BCL type. These sort of methods generally use an out parameter to return the resulting value (or the type default value, in case the parsing operation does not succeed).

+ +

The method above contains a TryParse method in the ZipCode class. Take a look at the method’s signature.

+ +

When you write more than one type in the method’s return, you’re using a tuple type. Don’t worry, you’re going to get used to it.

+ +

Right at the start of the method, we pass the specified text for a private method that actually performs the validation and returns a boolean value.

+ +

After the validation, we return a tuple literal, which consists in a new instance of the ZipCode class and a boolean flag indicating whether the parsing operation succeeded.

+ +

Nice, but what about the other side? How the function caller deals with this sort of return value? Let’s see:

+ + + +

If you hover over the variable name, you’ll see its type described, unsurprisingly, as (ZipCode, bool).

+ +

+ +

You can access each tuple element by using zipParsingResult.Item1, zipParsingResult.Item2, and son on.

+ + + +

However, you’re not forced to use the default names. There’s nothing stopping you from using more descritive naems:

+ + + +

The calling code becomes more readable:

+ + + +

There’s still another way of accessing a tuple’s items. By using a functionality called Deconstruction, you can easily split a tuple’s elements into variables.

+ +

You can declare the variables by using their types:

+ + + +

Type inference also works here, and you have two options: you can use the var keyword for each variable, or to use it just once for all variables, placing it outside the parenthesis.

+ + + +

You don’t even need to declare the variables at the deconstruction moment. It’s perfectly valid to deconstruct a tuple into already existent variables.

+ +

Some notes

+ +

Tuples are Value Types. Equality for tuples works in the way you’d probably expect: two tuples are considered equals if their items have the same values and they return the same HashCode. The names of the items are not relevant

+ + + +

Assignment also works in the intuitive way. As long as they’re assignable to each other, two tuples can freely be assigned to one another. As in the previous case, the item’s names don’t matter.

+ + + +

Currently, for this feature to work, you must install a nuget package called System.ValueTuple. In Visual Studio, go to Tools > NuGet Package Manager > Package Manager Console..

+ +

The Package Manager Console Windows will be shown. Type Install-Package System.ValueTuple and press ENTER.

+ +

But what about System.Tuple?

+ +

Maybe you’re wondering: why so much noise about tuples, if the .Net Framework has had the System.Tuple reference type since its 4.0 version? Why don’t we just stick to the older type?

+ +

Well, this Stack Overflow answers it pretty well, but I’ll try to summarize it here.

+ +

Firstly, as already mentioned, the older type is a reference type, and the new one is a value type, with all the usual implications.

+ +

But the really important differences have to do with convenience and readability. If you use System.Tuple there is no deconstruction; you can only access the items by using the default names, which makes the code harder to read and understand.

+ +

Local Functions

+ +

A Local Function is exactly what its name suggests: a function that can be declared inside another function.

+ + + +

As you’ve noticed, the inner function can access the values available for the outer function.

+ +

Of course, the example shown above is deliberately simple; in production, you’d probably just write the code in Log() in the external methods and be done with it.

+ +

It’d also be possible to use a delegate for that:

+ + + +

It seems that everything we can do with a local function is also possible to do with private methods or delegates. Do we really need this feature?

+ +

Giovani Bassi give us some reasons to use this feature:

+ +
+ +
    +
  • Sintaxe consistente com a já utilizada em métodos;
  • +
  • Não há necessidade de criar um delegate, ou referenciar Func, Action, ou algo parecido;
  • +
  • Lambdas e delegates causam alocações extras, funções locais não;
  • +
  • Ref e out são permitidos;
  • +
  • Tipos genéricos são permitidos;
  • +
  • É possível referenciar funções ainda não declaradas.
  • +
+
+ +

In free translation:

+ +
+ +
    +
  • Sintaxe consistent with the one already used in methods;
  • +
  • No need to create a delegate, or reference Func, Action, or something like that;
  • +
  • Lambdas and delegates cause extra allocations, local functions don’t;
  • +
  • Ref and out are allowed;
  • +
  • Generic types are allowed;
  • +
  • It’s possible to reference functions not yet declared.
  • +
+
+ +

Of course you could just use a private method. But the local function has this nice property of not being acessible to the rest of your class, making it impossible to be accidentally called.

+ +

Mads Torgersen shows us a situation for which local functions are the perfect solution:

+ +
+

As an example, methods implemented as iterators commonly need a non-iterator wrapper method for eagerly checking the arguments at the time of the call. (The iterator itself doesn’t start running until MoveNext is called). Local functions are perfect for this scenario:

+
+ + + +

You could turn Iterator() into a private method, sure, but that would be: 1) redundant and not very elegant, since it would require you to repeat the same signature from the outer function; and 2) less safe, because another part of the code could call the method without performing the validation.

+ +

Conclusion

+ +

Today we’ve talked about Tuples and Local Functions, two new features from C# that, at first sight, can look harmless, but have potential to change the way you write code in interesting ways.

+ +

Local functions? At first, I didn’t really liked it, I must admit. Or rather: I couldn’t understand what would they be useful for. After some research, I understood their use cases.

+ +

With tuples, it’s a whole other story. I believe every C# developer with some experience under their belt has felt the need to return more than one value from a method and was frustrated with the available options. Now using tuples we finally have an elegant, easy-to-use solution, that makes the code less clumsy and more readable.

+ +

Not everything is perfect though. Some developers already express concerns with these features. For instance, local functions could encourage the creation of large methods.

+ +

Tuples, on the other hand, could be over-used in situations that require objects, making the code more procedural.

+ +

My opinion about all of this is very simple: every tool can be abused. It’s up to us, professionals, and to our teams, to exercise our common-sense while using these (and other) features. By the way, as I mentioned in my article about private methods, code review and/or pair-programming can be of invaluable help in situations like these.

+ +

Thanks for reading. See you next time.

+ +

References

+ + + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/csharp-7-features/index.html b/en/csharp-7-features/index.html new file mode 100644 index 00000000..f5b9f67e --- /dev/null +++ b/en/csharp-7-features/index.html @@ -0,0 +1,510 @@ + + + + + + + + C# 7 Features Worth Knowing - Part 1 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# 7 Features Worth Knowing - Part 1

+ +
+ +
+

+ +

C# 7 is finally among us. Time to check out some of its features. +

+ +

In my last post I’ve written about some of the more interesting (for me, at least) features of C# 6. Visual Studio 2017 and C# 7 were officially released the following day, so I guess now it’s the perfect time for us to discuss the new version of the language.

+ +

I think it’s fair to say that the seventh version of C# continues the trend started by its predecessor. Instead of adding radically new capabilities to the language, the design team again chose to include features meant to make your code cleaner and more concise.

+ +

In this version, they “expanded” certain features that made their debut in C# 6. It seems that the previous version acted as a kind of rehearsal for some features; now that the design team knows that those features were well accepted, they can take them to their next level.

+ +

So, without further ado, let’s begin.

+ +

Digit separators and binary literals

+ +

Take a look at the code bellow:

+ + + +

What are those underscores for? Readability, that’s what.

+ +

Large numbers can become quite hard to read. To address this issue, C# 7 lets you to use the _ as a digit separator.

+ +

The separators make no difference on the value. You can place them wherever you like in the number, and in any quantity.

+ +

And in case you’re wondering, you’re not restricted to using them with integers only; they also work with the other numeric types as well.

+ +

The new version of C# also introduces binary literals, as seen in the third line of the example shown above. If you need to write a binary value, just put 0b at the beginning of the number, and that’s it!

+ +

Out variables

+ +

In previous versions of C#, working with out variables has been somewhat inconvenient. You’d have to split their declaration and usage into two steps.

+ +

Now, C# 7 allows you to declare the variable at the argument list:

+ + + +

Some important things to bear in mind:

+ +
    +
  • Even though I’ve explicitly written the type name in the declaration, this is not always required. I could have used var and it would’ve worked just the same.
  • +
  • You may think that the declared variable will go out of scope after we leave the if/else block. That is not the case. The variable continues to be accessible until going out of its normal scope.
  • +
+ + + +

(More) Expression-bodied members

+ +

At the beginning of this post, I said that C# 7 expands some of its predecessor’s features, remember? Well, this is one of those cases.

+ +

In the last post, we’ve seen that C# 6 brought us Expression-bodied members, which is a nice and shorter way of writing members of the class, using the lambda expression syntax.

+ +

However, you could only use this feature with methods, read-only properties and indexers.

+ +

C# 7 changes the game. Now you can use expression-bodied constructors, destructors, and writable properties.

+ + + +

throw Expressions

+ +

This one is very simple. Consider the following code:

+ + + +

That is 9 lines of code for just an assignment. And most of those lines are not performing the assignment itself; they’re just a guard clause. Of course, they’re important, but they tend to pollute your code. What if there was a better way?

+ +

Now there is.

+ +

In the previous versions of C#, throw was a statement. Now, it is an expression, which allows us to throw exceptions in places like the second hand of the Null Coalescing Operator and in conditional expressions.

+ +

Using a throw expression, the example shown above becomes as simple as this:

+ + + +

Of course, there’s nothing stopping us from turning the constructor into an expression-bodied member:

+ + + +

Conclusion

+ +

In this post, we’ve seen some of the new features from the seventh version of C#. This was just the fist part. More parts will come, in which I intend to cover all (or at least most) of the new features.

+ +

As I’ve said earlier, C# 7 kind of continues the path started by C# 6. The design team didn’t just include crazy new features just for the sake of it; instead, they carefully selected the ones that would help all of us to improve the quality of our code.

+ +

That being said, I do consider that this version is a little bit…less shy - for lack of a better word - than its predecessor. Some of the features that I didn’t talk about today show that the language is being pushed to interesting new directions, and I think there is a very exciting ride ahead of us.

+ +

Thanks for reading, and stay tuned for part 2!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/csharp-8-features/index.html b/en/csharp-8-features/index.html new file mode 100644 index 00000000..53131ea9 --- /dev/null +++ b/en/csharp-8-features/index.html @@ -0,0 +1,600 @@ + + + + + + + + C# 8.0 Features: A Glimpse of the Future | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# 8.0 Features: A Glimpse of the Future

+ +
+ +
+

+ +

C# 8.0 is coming and will bring some great new features. Let’s check out what the future holds for us. +

+ +

Editorial note: I originally wrote this post for the NDepend blog. You can check out the original here, at their site. While you’re there, download NDepend and give it a try.

+ +

It’s been almost 20 years since Microsoft released the first version of the C# language. From its inception—when some unjustly deemed it a mere Java copycat—until now, C# has had a remarkable evolution.

+ +

Nowadays, it’s frequently featured in both most used and most loved programming languages lists. You can use it to develop desktop, web, and mobile apps, and you can write code that will run in all the major operating systems. Or you can jump right onto the IOT bandwagon and write code to “smarten” your house. We live in interesting times to be a C# developer indeed.

+ +

If the present is already exciting, what about the future? Would it be possible for us to get a glimpse of what lies ahead for the language?

+ +

Of course it is. Microsoft has developed C# “in the open” for quite a while now. You can just take a look at the GitHub repo to read (and participate—why not?) in the discussions and proposals.

+ +

Today, we’ve selected three feature proposals for C# 8.0 to talk about here: extension everything, default implementations on interfaces, and nullable reference types.

+ +

Extension Everything

+ +

Extension everything is probably the least controversial of these three feature proposals, and in a certain way, it’s the least fleshed out also. So I figured it’d make a good starting point.

+ +

You’re probably familiar with extension methods, introduced in C# 3.0 in 2007. And while it’s totally possible for them to be abused, there’s no denying that extension methods, if used wisely, can be an awesome addition to the C# developer’s toolkit—not to mention they’re essential for LINQ.

+ +

At some point you may have wondered, though: why only extension methods? And you wouldn’t be alone. Extension properties, for instance, have been a desire of C# developers for quite a long time, as evidenced by this 2009 Stack Overflow question or this even older 2007(!) forum thread.

+ +

But now it seems the wait is finally coming to an end. According to Mads Torgersen, the program manager for the C# design team, a Microsoft intern proposed a new syntax for extension methods that will also allow “extension other things.

+ +

Let’s See the Code

+ +

Well, if I were you, I’d be itching to see some code. Here’s an example of an extension method using current syntax:

+ + + +

Nothing surprising here, right? In the original syntax, an extension method is just a static method in a static class, with the this keyword before the first parameter.

+ +

The thing is this syntax only works with methods (and, really, how could it be otherwise, since what would be the first “parameter” of a property?)

+ +

Here comes “extension everything.” This proposal suggests a new type declaration called an “extension”:

+ + + +

The code above is an example; as of the date of this writing, the C# team is yet to settle on a syntax.

+ +

Regardless, the example shows the creation of an extension class that extends “int.” We then declare a property as we normally do, and we’re done.

+ +

Now the caller code would be able to use the property normally:

+ + + +

This new feature is meant to support methods, properties, operators, and static members, at least in the beginning; events and constructors may come later.

+ +

You won’t be able to add additional state to the original instance, i.e., creating a private field in the extension class. According to Torgersen, this would add undesirable complexity in order to keep track of this new state.

+ +

Current Status

+ +

You can follow the feature development on its GitHub issue.

+ +

Default Implementation on Interfaces

+ +

I admit I was surprised—and not exactly happy—when I first heard about default implementation on interfaces in a talk Mads Torgersen gave in May 2017, at the Build 2017 Conference.

+ +

“What about record types?” I thought. “What about immutable objects? What we’re really getting is implementation on interfaces?”

+ +

You can safely guess what this feature is by its name: we’ll be able to add method implementations on interfaces. For instance:

+ + + +

In C# 8.0, the code above would be perfectly legal. A class implementing the interface wouldn’t need to implement the method. If some implementation of the interface decides that the default implementation doesn’t fit its needs, then it can provide its own implementation.

+ +

Besides methods, you’ll also be allowed to add bodies for indexers, properties, and event accessors. Static members such as methods, properties, and indexers will be allowed as well.

+ +

Instance state will not be allowed in interfaces, though. You’ll be able to use static fields but not instance fields. As a consequence of this, auto-implement properties won’t be allowed as well, since they automatically declare a hidden backing-field.

+ +

Use Cases

+ +

As stated in the feature proposal, the primary use case for default interface methods is to enable the developer to safely evolve an interface. You could add new methods to it and, as long as you provided a default implementation, existing clients of the interface wouldn’t be forced to implement it.

+ +

Currently, you could solve this problem with an extension method. This approach is limited, though: what if you wanted to provide a specialized version of the method for one of the implementations? Good luck with that.

+ +

That’s when default implementation shines.

+ +

Another important value proposition of default implementation on interfaces relates to Android and iOS. Since both Java and Swift offer this feature, it’s tricky to use C# to wrap Android/iOS APIs that make use of it. C# 8.0 will make it possible to wrap those APIs more faithfully.

+ +

Will Interfaces Become Abstract Classes?

+ +

Sort of, but not really. As you know, there’s no multiple inheritance in languages like C# and Java, which means you can’t inherit from more than one class. On the other hand, a class is (and will continue to be) able to implement several interfaces.

+ +

Current Status

+ +

This feature is currently being prototyped. You can follow its development on the GitHub issue.

+ +

Nullable Reference Types

+ +

“What?” you may be wondering. “Shouldn’t it be ‘non-nullable reference types’?” The name of this feature can be a bit confusing, indeed. I’ll get back to that soon, but first, let me address why this is even a thing.

+ +

I bet you’re familiar with the phrase “the billion dollar mistake.” On the off-chance you’re not, the phrase refers to the null reference, and it was coined by none other than Sir Tony Hoare, the inventor of the null reference himself.

+ +

But why is that? Why is null so bad?

+ +

You could make several arguments as to why, but the biggest problem is, of course, the risk of getting the infamous null-reference exception (aka null-pointer exception in Java-land). Since everything (“everything” in the context of C# meaning all reference types) can be null, you always run the risk of getting an exception when you try to access some member of the object.

+ +

One of the biggest issues here is that the language itself lacks a syntax that would allow the author to express their intent. It isn’t possible for you to say “This parameter can never be null” or “This property may be null sometimes, and that’s ok.”

+ +

It’s common for functional languages to deal with this by having some type that represents the concept of a potential absent value, often called “Maybe” or “Option.”

+ +

The C# team decided against something like this since, according to them, it’d be the same as adding a new kind of null to the language and it’d probably make things more complex.

+ +

Let’s go back now to the naming issue. You may be thinking that I’ve got it backwards. It makes sense to talk about nullable value types since value types are non-nullable by default. But in the case of reference types, it shouldn’t, right? After all, they’ve been nullable from the beginning.

+ +

Here’s the catch: the C# design team—in a move not free of controversy—intends to make non-nullability the new default for reference types. In that sense, the “new” thing would be the nullable types.

+ +

To keep the language consistent, they propose to use the same syntax that already exists for nullable reference types—in other words, the question mark.

+ +

Enough talking. Let’s see some code!

+ +

I suppose using the infamous “Person” class in an example is the software equivalent of playing “Stairway to Heaven” in a musical instruments store—it may be a little overdone. But using a more elaborate example would be both distracting and unnecessary, so please bear with me.

+ +

Suppose we have a “Person” class with an “Age” property of type “int.” Then, we write the following method:

+ + + +

Even though the code above will gladly compile, it’s fragile since “p” could be null. You probably should add an “if” statement to account for that possibility, but no one will make you do that. You’re completely free to leave the code as it is.

+ +

C# 8 promises to change that by making reference types non-nullable by default. In the example above, trying to access the “Age” property would be safe, since “p” would never be null.

+ +

If you wanted “p” to be nullable, then you’d have to add a question mark to the type, as I’ve mentioned before:

+ + + +

Now that “p” can be null, trying to access Age isn’t safe anymore: you’ll get a warning for doing that. Want to get rid of the warning?

+ +

Just do what you (hopefully) already do today and perform a null check:

+ + + +

That way, a flow analysis will be performed; if the assignment line is reached, the compiler will know for a fact that “p” can’t possibly be null and will leave you alone.

+ +

Here’s another possibility:

+ + + +

In short, you have several options. As soon as you convince the compiler that your code offers no risk of throwing a null reference exception, the warning goes away.

+ +

Preventing Assignment from Nullable to Non-Nullable

+ +

The new version of C# will also prevent assigning from a nullable variable to a non-nullable, so the code below will result in a warning as well:

+ + + +

This feature will come along with a new operator called the null-ignoring operator. You’ll basically use this operator to tell the compiler that “I, the developer, know best.” There will be situations when a variable can’t possibly be null, but the compiler won’t be able to infer that.

+ +

One such example would be the use of the “string.IsNullOrEmpty()” method:

+ + + +

The code above will generate a warning, despite it not being possible for “bar” to be null. That’s when this operator comes in handy:

+ + + +

Keep in my mind that, by using this operator, you’re basically telling the compiler: “Trust me! I know what I’m doing.” So you’d better really know what you’re doing!

+ +

What about backward compatibility?

+ +

I know what you’re probably thinking by now. “That sounds nice and all, but wouldn’t this change break a lot of existing code?”

+ +

Well, of course it would. That’s why this will be an opt-in change, activated on a per-project basis

+ +

Current Status

+ +

This one is already prototyped. If you’re interested, you can download, install, and test a preview for nullable reference types right away.

+ +

As with the previous features, you can stay tuned by following the relevant proposal in GitHub.

+ +

C# Has a Future. And It Looks Awesome

+ +

So now you know a bit more about three of the features we’re probably getting with the next major version of the C# language.

+ +

As you can see, evolving the language is hard work. The language has to remain compatible with the millions (billions?) of lines of code written with it in the last 17 years. At the same time, in order to continue being relevant, it must meet the needs of developers that are facing challenges that were unimaginable years ago. And it must do all of this without losing its essence: being an easy and approachable object-oriented C-like language.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/csharp-regex.html b/en/csharp-regex.html new file mode 100644 index 00000000..13a0caed --- /dev/null +++ b/en/csharp-regex.html @@ -0,0 +1,673 @@ + + + + + + + + C# Regex: How Regular Expressions Work in C#, With Examples | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# Regex: How Regular Expressions Work in C#, With Examples

+ +
+ +
+

+Editorial note: I originally wrote this post for the Stackify blog. You can check out the original here, at their site.

+ +

Text manipulation is one of the most common tasks in programming with virtually all major programming languages usually supporting regex (regular expression) via their standard libraries. C# is no exception, so today we bring you a C# regex guide.

+ +

You’ll learn what regexes are, why you’d want to use them and how to get started in a comprehensive, approachable manner. That way, you can start using regular expressions to solve real problems ASAP.

+ +

Buckle up for your regex learning journey, starting now!

+ +

What Is Regex?

+

A regular expression (regex) is an expression containing one or many characters that expresses a given pattern in text. If that sounds a little vague, an example will help. Consider a date in the following format:

+ +
28-JUL-2023
+
+ +

Using a regex, we can express that format like this:

+ +
[0-9]{2}-[A-Z]{3}-[0-9]{4}
+
+ +

Note that the regular expression above expresses a pattern with:

+ +
    +
  • two numeric digits followed by a hyphen
  • +
  • three upper-case letters followed by a hyphen
  • +
  • four more numbers
  • +
+ +

You’ll learn more about what each part of a regex means in a minute. For now, just bear in mind that the regex above doesn’t know anything about dates. It just happens that we were able to devise a regular expression that matches the pattern or shape of the date. All of the following match with that regex, even though they’re not valid dates:

+ +
32-ABC-7894
+30-FEV-1978
+00-AAA-9999
+
+ +

Is There Regex in C#?

+ +

Yes, of course. But that doesn’t come from the language itself. Instead, regex support comes from .NET’s BCL (Base Class Library), which is essentially C#’s standard library.

+ +

Why Use Regex In C#?

+ +

As you’ve seen, regex is something to use to express a pattern that can match a given text. 

+ +

In practice, all uses of regex in C# or other languages boil down to three reasons: validation, manipulation and extraction.

+ +

Validation

+ +

An incredibly common use case for regex is data validation. For instance, let’s say you have a web form and want to ensure a certain field only accepts inputs in a specific format. How to solve that? Regex comes to the rescue.

+ +

Manipulation

+ +

Sometimes you need to change information within text. Let’s go back to the previous example. Imagine for compliance reasons you need to remove all phone numbers from this body of text and replace them with the word “REDACTED.” Again, regexes would be a perfect fit for this situation.

+ +

Interestingly, programming languages are not alone in using regular expressions to solve problems. Even text editors such as Notepad++ offer find-and-replace features powered by regexes.

+ +

Extraction

+ +

Let’s say you have considerable amounts of text. This text contains telephone numbers that you need to extract. You know the format of those numbers and the fact that they’re inside the text, but that’s the extent of your knowledge.

+ +

How would you go about extracting that information? A neat C# regex would certainly come in handy in that situation.

+ +

How to Use Regex In C#: Getting Started in Practice

+ +

C# is an OOP language, so it shouldn’t be a surprise that you’ll use a class for your C# regex work. More specifically, the class I’m talking about is appropriately called Regex and resides in the System.Text.RegularExpressions namespace.

+ +

C# Regex: A Validation Example

+ +

Let’s start with a simple validation example on how to use regex to validate whether several strings match a given pattern. The first step is to add the following using statement to your code:

+ +

using System.Text.RegularExpressions;

+ +

Now, let’s create an array of strings and populate it with some values:

+ +
var candidates = new[]
+{
+    "28-JUL-2023",
+    "whatever",
+    "89-ABC-1234",
+    "11-JUN-2022",
+    "11-JUN-2022, a date plus other stuff",
+    "This is certainly not a date"
+};
+ +

Finally, we’ll loop through the values and use the IsMatch static method from the Regex class to verify which of the strings matches our desired pattern:

+ +
var pattern = "[0-9]{2}-[A-Z]{3}-[0-9]{4}";
+foreach (var c in candidates)
+{
+    if (Regex.IsMatch(c, pattern))
+    {
+        Console.WriteLine($"The string '{c}' matches the pattern '{pattern}'");
+    }
+}
+ +

Before going further, let’s break down the pattern piece by piece:

+ +
    +
  • [0-9]{2}: The first part means “Match exactly two characters, that must be digits from 0 to 9.”
  • +
  • -: This character matches exactly a hyphen.
  • +
  • [A-Z]{3}: Here, the expression says, “Let’s match exactly three characters, which can be any of the letters from A to Z.”
  • +
  • -: This matches another hyphen
  • +
  • [0-9]{4}: This should be easy to understand by now, right? Exactly four numbers.
  • +
+ +

Now, let’s run the code and see what we get:

+ +
The string '28-JUL-2023' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+The string '89-ABC-1234' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+The string '11-JUN-2022' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+The string '11-JUN-2022, a date plus other stuff' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+
+ +

The first three results probably didn’t surprise you. I even include something that’s not a date but matches the pattern we’re using in order to really drive home the point that regular expressions are about patterns and shapes and not about any semantics of the data we’re looking for.

+ +

However, the fourth result might’ve surprised you. The text indeed starts with data that matches the pattern we’re looking for, but then it has some additional text. And even then, this string matched!

+ +

The explanation for this behavior is simple, and it’s spelled out for us in the summary for the IsMatch method:

+ +
Indicates whether the specified regular expression finds a match in the specified input string.
+
+ +

The regular expression indeed found a match in the specified input string (“11-JUN-2022, a date plus other stuff”), and that’s why it was considered a match.

+ +

But what if we wanted an exact match? In that case, you’d have to change the pattern, adding a circumflex accent (“^”) to the star of the pattern and a dollar sign (“$”) to its end. In other words, here’s how the pattern should look now:

+ +
var pattern = "^[0-9]{2}-[A-Z]{3}-[0-9]{4}$";
+ +

If we run the code now, it displays only the strings that are an exact match with the pattern:

+ +
The string '28-JUL-2023' matches the pattern '^[0-9]{2}-[A-Z]{3}-[0-9]{4}
+
+ +

C# Regex: A Manipulation Example

+ +

Consider you have a body of text containing sensible user data. Due to privacy/compliance concerns, you want to redact those data points. Luckily for you, it’s quite easy to use a regex for that. 

+ +

Let’s start by creating an array containing names and phone numbers for fictitious people:

+ +
var contacts = new[] {
+    "Emily Johnson,(555) 123-4567",
+    "Benjamin Williams,(555) 987-6543",
+    "Olivia Davis,(555) 222-3333",
+    "Alexander Smith,(555) 444-5555",
+    "Sophia Brown,(555) 777-8888",
+    "William Anderson,(555) 111-2222",
+    "Ava Martinez,(555) 666-7777",
+    "James Thompson,(555) 888-9999",
+    "Isabella Wilson,(555) 333-4444",
+    "Michael Taylor,(555) 777-1111"
+};
+ +

Then, let’s create the pattern to match the phone numbers:

+ +
var pattern = @"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}";
+ +

The pattern above is a bit more involved than the ones we used earlier, but it’s still simple. There are a couple of new elements, though:

+ +
    +
  • The backward slash (\): We need it here in order to escape the opening and closing parenthesis, which is a character with meaning in a regular expression. In this instance, we actually do want to match a “(” character, so we need to escape it.
  • +
  • The \s character: matches a single space.
  • +
+ +

Finally, let’s loop through this array and, for each item, use the Regex.Replace method to generate a new string in which the phone number is replaced by all zeroes:

+ +
foreach (var contact in contacts)
+{
+    Console.WriteLine(
+        Regex.Replace(contact, pattern, "(000) 000-0000"));
+}
+ +

Using the Replace static method is easy. Though it has several overloads, the one we use just takes three arguments:

+ +
    +
  • the input string
  • +
  • the pattern you want to match
  • +
  • the replacement string
  • +
+ +

After running the code, here’s the output we get:

+ +
Emily Johnson,(000) 000-0000
+Benjamin Williams,(000) 000-0000
+Olivia Davis,(000) 000-0000
+Alexander Smith,(000) 000-0000
+Sophia Brown,(000) 000-0000
+William Anderson,(000) 000-0000
+Ava Martinez,(000) 000-0000
+James Thompson,(000) 000-0000
+Isabella Wilson,(000) 000-0000
+Michael Taylor,(000) 000-0000
+
+ +

C# Regex: An Extraction Example

+ +

For our last example, let’s extract data from a string using a regular expression. Let’s start by converting the array from the previous example into a single string:

+ +
var contacts =
+    "Emily Johnson+(555) 123-4567" +
+    "\nBenjamin Williams+(555) 987-6543" +
+    "\nOlivia Davis+(555) 222-3333" +
+    "\nAlexander Smith+(555) 444-5555" +
+    "\nSophia Brown+(555) 777-8888" +
+    "\nWilliam Anderson+(555) 111-2222" +
+    "\nAva Martinez+(555) 666-7777" +
+    "\nJames Thompson+(555) 888-9999" +
+    "\nIsabella Wilson+(555) 333-4444" +
+    "\nMichael Taylor+(555) 777-1111";
+ +

Then, we define the pattern again (same one) and use the Matches static method to get all of the matches from the string:

+ +
var pattern = @"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}";
+MatchCollection matches = Regex.Matches(contacts, pattern);
+ +

The MatchCollection class holds all of the strings that matched the pattern we gave to the method. This object is enumerable, so we can loop over it with a foreach:

+ +
Console.WriteLine("Here are the extracted phone numbers:");
+foreach (Match match in matches)
+{
+    Console.WriteLine(match.Value);
+}
+ +

And, finally, our results: 

+ +
Here are the extracted phone numbers:
+(555) 123-4567
+(555) 987-6543
+(555) 222-3333
+(555) 444-5555
+(555) 777-8888
+(555) 111-2222
+(555) 666-7777
+(555) 888-9999
+(555) 333-4444
+(555) 777-1111
+ +

C# Regex: An Indispensable Tool

+ +

As we said in the intro, text manipulation is a staple of programming, and regular expressions make this task easier. In this C# regex guide, you’ve learned what regular expressions are, their most common usage scenarios and how to get started with regular expressions in C#.

+ +

Before departing, a few tips:

+ + + +

Finally, if you want to learn more about C# in general, you’re in the right place. The Stackify blog is full of useful resources. As a suggestion, take a look at the pros and cons of the top 3 unit test frameworks for C#, how to catch exceptions and find application errors in C#, and how C# reflection works next.

+ +

Thanks for reading!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/csharp-unit-testing-intro-tdd/index.html b/en/csharp-unit-testing-intro-tdd/index.html new file mode 100644 index 00000000..3e3cda5d --- /dev/null +++ b/en/csharp-unit-testing-intro-tdd/index.html @@ -0,0 +1,859 @@ + + + + + + + + C# Unit Testing: Getting Started With TDD | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# Unit Testing: Getting Started With TDD

+ +
+ +
+

+ +

This post is part of a series. See all the articles in the series.

+ +

Today I bring you another post to help you get started with C# unit testing. I’ve already covered the basics of unit tests, explaining what they are and why they’re so important. After that, I showed you how to get started with unit testing with a practical example. Today, we go one step further, exploring the TDD methodology.

+ +

You’ve probably have heard of TDD, but you might be confused as to what it is. This isn’t your fault, by the way. There’s quite a lot of misconception surrounding this acronym. Some people even use it interchangeably with unit testing. In this post, you’re going to learn why they’re wrong, and more.

+ +

We start the post with a brief definition of TDD. You’ll learn not only that TDD stands for Test-Driven Development, but also that it’s not a testing technique, despite the name. After that, I explain what TDD is and what its benefits are.

+ +

After the “what” and “why” are both out of our way, we’ll be ready to have some fun. I’m going to show you, in practice, how to get started with TDD, developing a solution for a famous programming exercise. Sounds good? Then, let’s dig in.

+ +

C# Unit Testing & TDD Basics

+ +

I’ve mentioned earlier that TDD is not a testing technique. What is it, though? And how it’s related to C# unit testing (or unit testing in general, for that matter?)

+ +

Defining TDD

+ +

As you’ve seen, TDD stands for Test-Driven Development. It is a technique or methodology of software development that uses unit tests to drive the development of the application.

+ +

Instead of doing the more intuitive thing, which would be writing unit tests after the production code, the TDD methodology states that you should start by writing a failing unit test. Then you write the production code, but only what’s necessary to make the test pass.

+ +

I guess you’re now wondering at least two things:

+ +
    +
  • How does that work in practice?
  • +
  • Why write code in such a weird way?
  • +
+ +

That’s what we’re going to see next.

+ +

The TDD Phases

+ +

Test-driven development relies on the repetition of an incredibly short cycle. This cycle is composed of three phases:

+ +
    +
  1. First, you write a test that represents a specific requirement of the functionality you’re trying to implement.
  2. +
  3. You then make the test pass, writing the minimum amount of production code you can get away with.
  4. +
  5. If necessary, you refactor the code to eliminate duplication or other problems.
  6. +
+ +

Since the functionality doesn’t exist yet, the test you write in step #1 will fail. That is, in languages such as Python or Ruby. In the case of statically typed languages such as Java or C#, the code won’t even compile. For our purposes, code not compiling counts as a test failure.

+ +

In step #2, you have to make the test pass, but nothing beyond that. What I mean is that your goal here isn’t to solve the problem, at least not yet. Instead, your only job is to make the test pass, writing the least possible amount of code. Cheating—for instance, returning a hard-coded value—is not only OK but encouraged, as you’ll soon see.

+ +

Finally, the third phase is the only one that allows you to write production code without having to create a failing test first. But you can’t create new classes or functions; you can only refactor the code you wrote in the previous step, to make it more readable, to eliminate duplication, or to solve another problem. And, of course, the test should still pass.

+ +

People often use refer to the TDD as “red-green-refactor” because most unit testing tools use red to denote failing tests and green for passing tests.

+ +

Why Use TDD?

+ +

The hard thing to understand when getting started with TDD isn’t the how. The “how” is trivial: write a test, make it pass, maybe refactor, rinse, repeat. The troubling part is the “why.” Why develop software in such a non-intuitive way?

+ +

I’ll talk more of the TDD philosophy in future articles. In a nutshell, applying TDD ensures you’ll have testable code from the beginning. It will encourage you to design your code in a simple and modular way.

+ +

But perhaps, the main advantage of TDD is increasing the developer’s confidence on their code. By developing one tiny step at a time, you’ll never be able to get a lot wrong, since you’re doing too little. Knowing that you’re only one failing test away from having working code is reassuring.

+ +

C# Unit Testing & TDD: The Hands-On Guide To Get Started

+ +

I’ve covered how to get started with C# unit testing in the past. I’ve also covered the required tools and how to get started. However, I won’t assume you’ve read those articles. Instead, I’ll cover everything from scratch. So, you’ll be able to follow the tutorial even if you have zero experience with unit testing.

+ +

Our Problem: The String Calculator Kata

+ +

For our tutorial, we’ll write a solution for Roy Osherov’s String Calculator kata. A coding kata is a programming exercise, meant to allow developers to practice fundamental agile software-engineering practices, such as refactoring, and—you’ve guessed it—TDD.

+ +

For simplicity’s sake, I’ll ignore some of the kata’s requirements. What follows are the requirements we’re going to use:

+ +
    +
  1. We’re going to create a class called StringCalculator, with a single static method with the signature static int Add(string numbers);
  2. +
  3. The method takes a string representing numbers separated by a comma, and return their sum.
  4. +
  5. If we pass an empty string, the method should return zero.
  6. +
  7. Passing a single number should result in the number itself.
  8. +
  9. If we pass negative numbers, the method should throw an ArgumentException, with the message “Negative numbers not allowed:” followed by the negatives that were specified.
  10. +
  11. The method should ignore numbers greater than 1000 should. So, “1,2,1000” should result in 1003, but “1,2,1001” should result in 3.
  12. +
+ +

Creating The Production Project

+ +

For this tutorial, I’ll be using the community edition of Visual Studio 2019. If you don’t already have it, you can download it and install it from free.

+ +

Open VS and click on “Create a new project,” like in the following image:

+ +

+ +

In the opened window, choose Class Library (.NET Core) as the template for the new project. Then, click on “Next”:

+ +

+ +

The next screen simply asks you for a name for the project and the solution. I chose” StringCalculatorKata” for both the project and the solution. You’ll also have to provide a location for saving the project files. When you’re done, just click “Create.”

+ +

If everything went well, you should see the default class open for you in Visual Studio. Go to Solution Explorer and delete that class; we’re not going to need it.

+ +

Creating The Test Project

+ +

Now, it’s time to create the test project. We could this in two ways: creating a regular “Class Library” project and then adding the necessary dependencies to it, or creating a unit test project right away. We’ll go with the latter since it makes the whole thing easier.

+ +

You know the drill: right-click the solution, go to “Add,” then “New Project…”. Then, choose the template “NUnit Test Project (.NET Core).”

+ +

Then, you’ll be required to provide a name and a location for the project. I like to follow the naming convention of naming the test project after the production project, with a “.Test” added. So, I pick “StringCalculatorKata.Test.” Finish the creation of the project.

+ +

If everything went right, you should now see a new class that looks like this:

+ +
public class Tests
+{
+    [SetUp]
+    public void Setup()
+    {
+    }
+
+    [Test]
+    public void Test1()
+    {
+        Assert.Pass();
+    }
+}
+ +

Let’s do a few things. First, get rid of the Setup() method. We won’t need it. Then, add a new method with the code below:

+ +
[Test]
+public void Test2()
+{
+    Assert.Fail();
+}
+ +

So, we now have two tests, one that should pass and another that should fail. Let’s run them to see if they’re working correctly. Go to the “Run” menu and click on “Run All Tests.”

+ +

Now, open the Test Explorer window (View -> Test Explorer). It should look like this:

+ +

+ +

It looks like everything is working fine! But before we start doing our coding kata exercise, there are two final steps we need to take. First, let’s rename the test class. Go to the solution explorer, expand the unit test project, and delete its default test class. Then, right-click the test project, go to “Add,” then “New class…” and add a new class called “StringCalculatorKata.” Alternatively, you can rename the existing class.

+ +

The second thing we have to do is to ensure our test project can see our production project. To solve that, we’re adding a reference.

+ +

Go to the solution explorer again, right-click the test project, then go to “Add” and click on “Reference…”.

+ +

In the new window, select “Projects” on the left panel, and then select the StringCalculatorKata project, which should be the only one available:

+ +

+ +

Then, you just have to click on “OK,” and now you’re ready to go.

+ +

Starting Our Coding Kata

+ +

Now, we’re ready to write our first failing test. So, open the StringCalculatorTest class and add the following method to it:

+ +
[Test]
+public void Add_EmptyStringAsParam_ReturnsZero()
+{
+    Assert.AreEqual(0, StringCalculator.Add(string.Empty));
+}
+ +

In our first test case, we test the simplest possible scenario. That is, we call the Add method passing an empty string, which, according to the requirements you saw before, should result in 0. Of course, neither the Add method nor the StringCalculator class exists, so our code doesn’t even compile. Well, congratulations! You’ve successfully performed the first step in the red-green-refactor cycle by writing a failing test! Remember: in statically-typed languages such as C#, failure to compile counts as a failed test.

+ +

So, our first step is to get rid of the compilation error. If you hover over “StringCalculator,” you should see a little pop-up explaining the error and offering possible fixes:

+ +

+ +

Click on “Show potential fixes” and then on “Generate new type…”. You should then see a window prompting you for the details and location of the new type. Change the “access” to “public” and the location to the production project, which is “StringCalculatorKata.” The window should look like this:

+ +

+ +

Click on “OK.” Now, if you open solution explorer and expand the StringCalculatorKata project, you should see the StringCalculator.cs class lurking around there. Cool.

+ +

However, our code still doesn’t compile. And that’s because, despite creating the production class, we didn’t add the Add method to it. So, let’s do it in the same way we did with the class.

+ +

Hover over the “Add” word until the help pop-up shows up with the message “’ StringCalculator’ does not contain a definition for ‘Add.’” Click on Show potential fixes, and then click on “Generate method ‘StringCalculator.Add’.”

+ +

You’ll see that the production class now contains a method called Add, with double as a return type. We want the method to return int, so let’s change that. Let’s also change the parameter name to “numbers” to match the coding kata’s requirements. At this point, your complete StringCalculator class should look like this:

+ +
public class StringCalculator
+{
+    public static int Add(string numbers)
+    {
+        throw new NotImplementedException();
+    }
+}
+ +

Now your code should compile. Run the test again, and you’ll see that it fails, with a message like this:

+ +
+Add_EmptyStringAsParam_ReturnsZero
+   Source: StringCalculatorTest.cs line 8
+   Duration: 43 ms
+
+  Message: 
+    System.NotImplementedException : The method or operation is not implemented.
+  Stack Trace: 
+    StringCalculator.Add(String numbers) line 9
+    StringCalculatorTest.Add_EmptyStringAsParam_ReturnsZero() line 10
+
+
+ +

We have a truly failing test. Are we ready to write production code? Not so fast. Sure, our test fails, but it fails in the wrong way. Since our test contains an assertion, we expected a failed assertion. Instead, what we’ve got is a failure due to the method under test throwing an exception.

+ +

The fix here is simple. Let’s just change the Add method, so it returns any number different from zero:

+ +
public static int Add(string numbers)
+{
+    return -1;
+}
+ +

Now, run the test again, and you’ll see the error message is now this:

+ +
+Add_EmptyStringAsParam_ReturnsZero
+   Source: StringCalculatorTest.cs line 8
+   Duration: 76 ms
+
+  Message: 
+      Expected: 0
+      But was:  -1
+
+ +

Making The Test Pass

+ +

We’re now finally ready to make the test pass. As I’ve said earlier, to make a test pass, you’re not only allowed but encouraged to cheat. In our case, we can simply make the Add method return zero:

+ +
public static int Add(string numbers)
+{
+    return 0;
+}
+ +

Writing The Second Test: A Single Number

+ +

The requirements say that passing a single number should return the number itself. That’s sound like a useful thing to test:

+ +
[Test]
+public void Add_StringContainingSingleNumber_ReturnsTheNumberItself()
+{
+    Assert.AreEqual(5, StringCalculator.Add("5"));
+}
+ +

The test fails with the following message:

+ +
+Add_StringContainingSingleNumber_ReturnsTheNumberItself
+   Source: StringCalculatorTest.cs line 14
+   Duration: 56 ms
+
+  Message: 
+      Expected: 5
+      But was:  0
+
+
+ +

How can we make the test above pass in the laziest possible way? How about this:

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    return 5;
+}
+ +

Testing Two Numbers

+ +

Since we’ve already tested the Add method by passing zero numbers (an empty string) and a single number, it feels like the next natural step for us now would be to write a test for the scenario of adding two numbers. So, let’s do just that.

+ +
[Test]
+public void Add_TwoNumbersSeparatedByComma_ReturnsTheirSum()
+{
+    var numbers = "7,8";
+    var expectedResult = 15;
+    Assert.AreEqual(expectedResult, StringCalculator.Add(numbers));
+}
+ +

The test above naturally fails since our method currently returns 0 when it gets an empty string and five otherwise. How can we change it, so this new test passes, the older tests continue to pass, in a way that doesn’t solve the problem generally?

+ +

This is an idea:

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    return 5;
+}
+ +

Testing Three Numbers

+ +

Have you noticed that, up until now, we haven’t done any refactoring? Well, we’re getting closer to the point when our tests drive us to include some nasty duplication to our code. Then, we’ll use refactoring to change the code in a way that gets closer to a general solution.

+ +

Let’s see if we can do that by testing the scenario with three numbers:

+ +
[Test]
+public void Add_ThreeNumbersSeparatedByComma_ReturnsTheirSum()
+{
+    var numbers = "1, 2, 3";
+    var expected = 6;
+    Assert.AreEqual(expected, StringCalculator.Add(numbers));
+}
+ +

The test will naturally fail. Since the provided string contains commas, we fall into the conditional branch that returns 15. Our challenge now is to change the production method in a way that makes this test pass. Can we do it without going to the general solution to the problem?Let’s see.

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    if (numbers == "1, 2, 3")
+        return 6;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    return 5;
+}
+ +

By comparing the specified param with the exact input used in the test, we can make the test pass while avoiding going for the general solution. However, now we have managed to create code duplication. Can you see it? We’re making two comparisons against the value of numbers, one right after the other. Let’s see if we can get rid of that duplication.

+ +
public static int Add(string numbers)
+{
+    if (numbers == "1, 2, 3")
+        return 6;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    int.TryParse(numbers, out int result);
+    return result;
+}
+ +

By leveraging the TryParse method from the System.Int32 type, I’ve managed to get rid of the first if instruction. We’ve also used a feature introduced in C# 7 called “out variables.” This feature allows us to use out parameters without having to declare them beforehand.

+ +

All tests still pass, so I can’t write more production code. What should the next test be?

+ +

Testing More Than Three Numbers

+ +

The requirements don’t say we should only be able to handle three numbers. So, let’s create another test case to cover the scenarios with 4, 5, or more numbers. While we’re at it, we can also include the requirement of ignoring numbers greater than 1000.

+ +

To do this without having to create a lot of test methods, we’re going to leverage NUnit’s parametrized tests feature, adding a single method with several test cases:

+ +
[TestCase("1,2,3,4", 10)]
+[TestCase("8,7,20", 35)]
+[TestCase("5,0,4,1001", 9)]
+[TestCase("5,0,4,1000", 1009)]
+[TestCase("26,6,90", 122)]
+public void Add_MoreThanThreeNumbersSeparatedByComma_ReturnsTheirSum(
+    string input, int result)
+{
+    Assert.AreEqual(result, StringCalculator.Add(input));
+}
+ +

Notice that the third test case exemplifies the requirement that says we should ignore numbers greater than 1000. The next test case, however, shows that 1000 should not be ignored. If you run the tests, you’ll see that test explorer shows each test case as a distinct test.

+ +

How can we make this test pass? Honestly, by this post, it’s way easier to go for the correct implementation than it is to cheat. So, let’s do just that:

+ +
public static int Add(string numbers)
+{
+    var parts = numbers.Split(',');
+    var result = 0;
+
+    foreach (var part in parts)
+    {
+        int.TryParse(part, outint number);
+
+        if (number <= 1000)
+            result += number;
+    }
+
+    return result;
+}
+ +

The code above should be easy to understand. We just split the string into parts using the comma as the delimiter. Then, for each part, we parse it to an integer, verify whether it’s equal or less than a thousand, and, if so, we add it to the result variable. Finally, we return the result.

+ +

We’re Not Done Yet

+ +

The requirements say that negative numbers shouldn’t be allowed. Let’s add a test for that! For brevity’s sake, we’ll add a single test method with several test cases, so we’re forced to go for the correct implementation right away:

+ +
[TestCase("1,2,3,4,5,-5")]
+[TestCase("-1,1,2,9")]
+[TestCase("5,6,8,-5")]
+public void Add_StringContainingNegativeNumbers_Throws(string numbers)
+{
+    Assert.Throws<ArgumentException>(() => StringCalculator.Add(numbers));
+}
+ +

For this test, we’re asserting not against a return value. Rather, we’re checking whether the method under test throws an exception.

+ +

Remember that the requirements say we should throw an exception with a message saying that negatives are not allowed. We should also include a list of the negatives that were passed. This will require some changes in our method:

+ +
public static int Add(string numbers)
+{
+    var parts = numbers.Split(',');
+    var result = 0; 
+    var negatives = new List<int>();
+
+    foreach (var part in parts)
+    {
+        int.TryParse(part, outint number);
+
+        if (number < 0)
+            negatives.Add(number);
+        elseif (number <= 1000)
+            result += number;
+    }
+
+    if (negatives.Count > 0)
+    {
+        var negativesList = string.Join(',', negatives);
+        var exceptionMessage = $"Negative numbers not allowed: {negativesList}.";
+        throw new ArgumentException(exceptionMessage);
+    }
+    
+    return result;
+}
+ +

As you can see, right at the beginning, we define a List<int> to store the negatives we find while iterating over all the numbers. Inside the loop, we verify whether the current number is negative. If it is, we add it to the list. If it isn’t, we verify whether it’s less than or equals to 1000, in which we case we add it to the result variable.

+ +

After the loop, we verify whether the negatives list has any elements. If it has, we create an exception message that includes the specified negatives and then throw a new ArgumentException. Otherwise, we return the result.

+ +

Conclusion

+ +

This post was a practical guide on how to get started with TDD in C#. So, where do you go from here?

+ +

Well, most things in life you learn by doing. Programming is certainly one of those things. So, if you want the concepts you’ve seen today to really sink in, you’ve got to practice.

+ +

The code I’ve written during this post is available as a public repository on GitHub. Go there, clone it using Git,, and start playing with it.

+ +

You’ll see that I created one commit for each step in the TDD cycle. That way, it becomes easier for future readers to visualize all the steps in the process by going through the project’s history, one commit at a time.

+ +

There are improvements that can be made to the code I shared today. For instance, the final Add method could be written in a shorter, clearer, more efficient way, using LINQ. You could add more test cases. Also, the kata requirements ask for a specific exception message in the case of negative numbers. Even though we’ve implemented the message as specified, we didn’t write a test for it. We could do that as part of your practice.

+ +

Finally, stay tuned to this blog. This post is part of a series, to which I intend to add more parts.

+ +

Thanks for reading, and until the next time!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/fivel-levels-readable-code/index.html b/en/fivel-levels-readable-code/index.html new file mode 100644 index 00000000..30158e3e --- /dev/null +++ b/en/fivel-levels-readable-code/index.html @@ -0,0 +1,654 @@ + + + + + + + + The 5 Levels of Readable Code | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

The 5 Levels of Readable Code

+ +
+ +
+

+ +

Photo by Greyson Joralemon on Unsplash

+ +

Recently I’ve been thinking a lot about code readability. What does it mean for a piece of code to be readable? Is it possible to define readability objectively? Should we attempt to do it?

+ +

These are some of the questions I’ve been thinking about, and in this post, I present my answers in an attempt to start a conversation around readability.

+ +

Here’s the TL;DR version: yes, I believe objectively defining code readability is both possible and desirable, and in this article, I suggest a model for evaluating readability.

+ +

The Importance of a Code Readability Definition

+ +

Readability will always be somewhat subjective and, to some degree, that subjectivity is harmless. However, it can cause problems in some scenarios.

+ +

If we’re working within a team, it’s important to come up with at least some objective guidelines regarding code readability, and that’s because of code reviews. If the team can’t agree on what constitutes readable code, then code review feedback will feel like arbitrary whims.

+ +

In short: teams need conventions. A team should have a vision when it comes to what constitutes good, readable code.

+ +

A Framework For Thinking About Code Readability: Levels

+ +

Not long ago I started thinking about code readability in terms of levels. The levels represent specific concerns regarding readability, and they’re ordered in terms of priority.

+ +

So, level 1 represents the most basic stuff you’ve got to take care of first, before progressing towards higher levels. Tidy up the basics, then go for the advanced stuff. Something like Maslow’s hierarchy of needs, but for code.

+ +

There will be some code examples, and I’ll be using C# for those. However, what I’ll show here applies to any language, unless I explicitly say otherwise.

+ +

Without further ado, here are the five levels of readable code.

+ +

Level 1: Your Code Does The Bare Minimum

+ +

(Yes, level one. Please spare me that “programmers start counting at zero” nonsense.)

+ +

Level 1 of readable code refers to code that does the bare minimum. Think of simple readability guidelines such as:

+ + + +

It’s not hard to learn these kinds of best practices. You can pick up most of these through sheer experience, by listening to the feedback of more experienced engineers during code reviews, or by reading books and even blog posts like the ones listed above.

+ +

Level 2: Your Code Is Idiomatic

+ +

Consider the following C# class:

+ +
public class Person
+{
+    private string _name;
+    private int _age;
+
+    public Person(string name, int age)
+    {
+        _name = name;
+        _age = age;
+    }
+
+    public void SetName(string name)
+    {
+        _name = name;
+    }
+
+    public string GetName() => _name;
+
+    public void SetAge(int age)
+    {
+        _age = age;
+    }
+
+    public int GetAge => _age;
+}
+
+ +

There’s nothing wrong with the above class, at least not technically. The compiler happily compiles it, and the class works as it should.

+ +

However, if you’re at least somewhat experienced with C#, you noticed something weird when you saw the code: the getter and setter methods. The C# development team made the concepts of getters and setters a first-class citizen of the language early on, via the concept of properties. If there’s no additional logic involved in the setting and getting of values, the programmer can make usage of auto-implemented properties with a concise result (even the backing private fields no longer need to be explicitly declared):

+ +
public class Person
+{
+    public Person(string name, int age)
+    {
+        Name = name;
+        Age = age;
+    }
+
+    public string Name { get; set; }
+    public int Age { get; set; }
+}
+
+ +

All of this is to say: that to be readable, a given piece of code needs to be idiomatic to the language it’s written into. If you’re writing C#, follow the coding standards and conventions of the language. The same applies to Java, JavaScript, and any other language.

+ +

The Python community has a wonderful concept to describe Python code that adheres to the standards and philosophies of the language: “pythonic”. A piece of Python code might work, but if it’s not Pythonic, experienced Python engineers will find the code awkward to work with.

+ +

Why does writing idiomatic code matter for readability? When you look at code—in whatever language—that doesn’t look like what it should look, according to the mental model you have of that language, it becomes harder to follow the code.

+ +

Non-idiomatic code increases the cognitive complexity of a code base. It makes it harder to onboard developers who are familiar with the language standards and idioms. If you have an open-source project, too many idiosyncrasies in the code might push away potential contributors.

+ +

Of course, the opposite of all of this is true.

+ +

Level 3: Your Code Reveals Intent Via Tactical Use of Typing

+ +

As the title suggests, this item, unlike the previous two, only applies to statically typed languages—or, perhaps, dynamically typed ones that feature some kind of optional type annotation.

+ +

Let’s start with a simple example. Look at the following lines:

+ +
Canvas.DrawLine(5);
+
+ +

Disregard the magic number, which is itself already a problem. Consider that you know that the DrawLine method has a single parameter, length. The line could’ve been made slightly more readable through the usage of a named argument, but even that wouldn’t solve the biggest issue: what the heck is the unit of measurement?

+ +

Besides harming readability, this problem opens up the possibility of bugs, due to a mismatch of units—a portion of the code “thinks” the unit is centimeters, while others might believe it’s inches.

+ +

What am I advocating instead? Well, use typing to your favor. Here, a good solution would be to create a value object called, let’s say, Length. This type would have several static factory methods named after specific units of measurement, and its constructor would be private. Then, you’d be able to rewrite the previous example to something like this:

+ +
Canvas.DrawLine(Length.FromCentimeters(5));
+
+ +

Another example would be the usage of the TimeSpan type to express durations, instead of using primitive values or employing the Uri class instead of just strings.

+ +

Maybe you’re thinking all of this is simply a convoluted way of saying “avoid primitive obsession.” There’s more to it than that, though.

+ +

To illustrate my point, I’ll share another—maybe a bit contrived, I admit—example. Let’s say you’re solving a problem that calls for the usage of a stack. In this case, nothing is stopping you from using the List<T> class as a stack, right?

+ +
    +
  • The Add method would be your replacement for the push functionality
  • +
  • For the pop functionality, you’d use a combination of getting the last element from the list via its indexer and then using the RemoveAt method to delete the item.
  • +
+ +

The above solution, despite being somewhat convoluted, would work. But I’d vehemently encourage you to just go and use the regular Stack<T> class. Using the more specific type would make the code immediately more readable to anyone who knows what a stack is. It would make the code reveal its intent.

+ +

In short: unless you have a justifiable reason to not do so, always prefer the type that more closely represents the concept or functionality you need. It’ll not only make your code more robust but also more intention-revealing.

+ +

Level 4: Your Code Doesn’t Mix Levels of Abstraction

+ +

Your code shouldn’t mix more than one level of abstraction. Code that lives in the “Business Rules” portion of your codebase shouldn’t mess with code that lives in the “IO concerns” neighborhood, to give you an example.

+ +

Why is this a problem? See the following function:

+ +
public static double CalculateAverageTemperature(string filePath)
+{
+    List<ClimaticReading> readings = new();
+
+    try
+    {
+        using var reader = new StreamReader(filePath);
+        while (!reader.EndOfStream)
+        {
+            var line = reader.ReadLine();
+            var values = line?.Split(',') ?? Array.Empty<string>();
+
+            if (values.Length < 2)
+                continue;
+            
+            if (DateTime.TryParse(values[0], out DateTime date) &&
+                double.TryParse(
+                    values[1],
+                    NumberStyles.Float,
+                    CultureInfo.InvariantCulture,
+                    out double temperature))
+            {
+                var reading = new ClimaticReading
+                {
+                    Date = date,
+                    Temperature = temperature
+                };
+                readings.Add(reading);
+            }
+        }
+    }
+    catch (Exception ex)
+    {
+        throw new InvalidOperationException($"Error reading the CSV file: {ex.Message}");
+    }
+
+    if (readings.Count < 3)
+    {
+        throw new InvalidOperationException("There must be at least 3 readings to calculate the average.");
+    }
+
+    readings = readings.OrderBy(reading => reading.Temperature).ToList();
+
+    readings.RemoveAt(0);
+    readings.RemoveAt(readings.Count - 1);
+
+    double sum = readings.Sum(reading => reading.Temperature);
+    double average = sum / readings.Count;
+
+    return average;
+}
+
+ +

The function reads and parses a .CSV file containing climatic readings. Lines that don’t have the expected two values (date and temperature) are dismissed. Then it sorts the readings, removes the highest and lowest values, and, finally, calculates and returns the average of the remaining values.

+ +

This function mixes at least two abstraction levels:

+ +
    +
  • The “domain logic” level—i.e. the part that makes the calculation
  • +
  • The low level: reading and parsing the .CSV file.
  • +
+ +

You could even make the argument that there are three levels, since the low level could be split into two: file system manipulation and parsing.

+ +

This example function isn’t the hardest thing in the world to read, but it’s certainly harder than it has to be. It mixes domain logic with IO error handling and even parsing. A better solution would be to have a method that gets a collection of ClimaticReading and calculates and returns the average.

+ +

In other words, a better and more elegant solution would be to have a pure function. This new method, besides being more readable, would be more robust, less error-prone, and also deterministic—i.e. always returns the same results for the same input—making it intrinsically unit testable.

+ +

Level 5: Your Code Speaks The Language of The Business

+ +

You’ve reached level 5 when you write code that speaks the language of the business. When you use terms that are the same ones that domain experts use.

+ +

In other words: yeah, I’m pretty much advocating for the same thing that the pragmatic programmers call “program closer to the domain”, or that Eric Evans famously dubbed ubiquitous language in his classical—but definitely not a page-turner—tome, “Domain-Driven Design: Tackling Complexity in the Heart of Software.”

+ +

If your code uses unorthodox terms instead of industry terms, it makes onboarding harder when you bring in new people that are familiar with the business but new to the codebase. If the code uses different jargon than that of stakeholders, communication becomes more taxing, since it requires you to perform a constant mapping between concepts just to stay afloat.

+ +

Level 5 is somewhat of a logical consequence of level 4. If you carefully segregate the concerns of your app, making sure that high level code doesn’t mix with low level code, the tendency is for the high level code to become closer and closer to the domain in terms of naming.

+ +

Level Up The Readability of Your Code

+ +

Most programmers would agree that code readability is vital. But what about agreeing on what “readable code” looks like? That’s a horse of a different color.

+ +

As I said earlier, I think a level of subjectivity when it comes to readability is both inevitable and harmless. However, in the context of a team, there has to be at least some consensus of what readable code is. Otherwise, code reviews become exercises of futility, and team morale sinks.

+ +

I believe that our industry would benefit from a more objective way to reason about readability. In this post, I gave my small contribution, in the form of a readability “checklist”, in prioritized order.

+ +

But again: the idea of this post isn’t to give a definitive answer, but to start a conversation. Do you think the “levels” models make no sense? Or maybe you’d like to share your own levels? I invite you to share your opinion via a comment, or shoot me an e-mail (you can find my address on the about page).

+ +

Special thanks to Mark Seemann, Pedro Barbosa and Peter Morlion for giving feedback on earlier drafts of this post.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/functional-programming-csharp/index.html b/en/functional-programming-csharp/index.html new file mode 100644 index 00000000..94a7219b --- /dev/null +++ b/en/functional-programming-csharp/index.html @@ -0,0 +1,606 @@ + + + + + + + + Functional Programming in C#: Map, Filter, and Reduce Your Way to Clean Code | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Functional Programming in C#: Map, Filter, and Reduce Your Way to Clean Code

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the SubMain blog. You can check out the original here, at their site. While you’re there, have a look at CodeIt.Right, which can help you improve the quality of your code.

+ +

C# is supposed to be an object-oriented language, but it’s possible that you, as a .NET/C# developer, have been using functional programming concepts without even knowing it.

+ +

And that’s what today’s post is about. I’ll just first briefly cover the attractions of functional programming and why it makes sense to apply it even when using a so-called object-oriented language. Then I’ll show you how you’ve already been using some functional style in your C# code, even if you’re not aware of it. I’ll tell you how you can apply functional thinking to your code in order to make it cleaner, safer, and more expressive.

+ +

C# Functional Programming: Why?

+ +

We know the .NET framework offers some functional capabilities in the form of the LINQ extension methods, but should you use them?

+ +

To really answer this, we need to go back a step and understand the attraction of functional programming itself. The way I see it, the easiest path to start understanding the benefits of functional programming is to first understand two topics: pure functions and immutable data

+ +

Pure functions are functions that can only access the data they receive as arguments and, as a consequence, can’t have any side effects. Immutable data are just objects or data structures that, once initialized, can’t have their values changed, making them easier to reason about and automatically thread-safe.

+ +

Fundamental Functional Programming Operations and How to Perform Them Using C#

+ +

With the what and why of functional programming out of the way, it’s time to get to the how.

+ +

l’ll be covering three fundamental functions: map, filter, and reduce. I’ll start by showing some use cases, then I’ll show a traditional, procedural way of solving the problem. And finally, I’ll present the functional way.

+ +

Map

+ +

In simple terms, the “map” operation takes a sequence of items, applies some transformation to each one of those items, and returns a new sequence with the resulting items. Let’s see some examples.

+ +

Suppose you wrote the following code, due to a customer’s demand:

+ +
	static void AddThreeToEachElement(int[] arr)
+	{
+	    for (var i = 0; i < arr.Length; i++)
+	    {
+	       arr[i] += 3;
+	    }
+	}
+ +

It’s a function that adds three to each element of the given array of integers. Pretty straightforward.

+ +

Now a request for a new function comes in. This time, it should add five to each element in an array. Ignoring the rule of three, you jump right ahead into a generalized version, parameterizing the number to be added:

+ +
	static void AddNumberToEachElement(int[] arr, int n)
+	{
+	   for (var i = 0; i < arr.Length; i++)
+	   {
+	        arr[i] += n;
+	   }
+	}
+ +

Then yet another request comes in. Now you must write a function that will multiply each element of the given array by, let’s say, three. I won’t add the code sample now because I’m sure you’ve got the picture. By now, you should know better than to hardcode the number, so you’d probably jump ahead to a general version right away. Even then, some duplication would still exist: the loop itself. Hmm…what if you could keep just the loop and instead parameterize the action to be applied on each item?

+ +

The Functional Way

+ +

Take into consideration what you’ve just read about pure functions—and also your previous knowledge ofprogramming best practices in general—and think of ways the code could be improved.

+ +

From my perspective, the main problems are

+ +
    +
  • The code is too specific. It can’t be easily changed to accommodate other transformations being applied to the array elements. It just performs a sum, and that’s it.
  • +
  • Too much boilerplate. Look at the previous sample again. Count the lines. There are seven, of which only one really concerns itself with carrying through the business logic of the method.
  • +
+ +

How would the functional way improve on this? That’s the way I’d write the first example in F#, for instance:

+ +
	let result = Seq.map (fun x -> x + 3) numbers
+ +

I’m assuming here that “numbers” is a sequence of integers I’ve got somehow. Then I use the map function on the Seq module, passing the sequence as a parameter, along with a function that takes an int and adds three to it.

+ +

The Functional Way, .NET/C# Flavor

+ +

.NET implements the map operation in the form of the “Select” LINQ extension method. So you could rewrite the F# example above like this:

+ +

var result = numbers.Select(x => x + 3);

+ +

One important point that needs explaining is that the type of the resulting sequence doesn’t need to match the type of the source sequence. Do you have a list of ‘Employee’ and need a sequence of ints (containing, for instance, their IDs)? Easy peasy:

+ +
	List<Employee> employees = EmployeeRepository.All();
+	IEnumerable<int> ids = employees.Select(x => x.Id);
+ +

Filter

+ +

I think filter is, hands down, the easiest operation of the bunch. It has a very intuitive name, and the need for filtering stuff is so common in programming that I bet you correctly guessed what it is just by its name (if you didn’t know it already).

+ +

For the sake of completeness, though, let’s define it. The filter operation…wait for it…filters a sequence, returning a new sequence containing just the items approved by some criteria.

+ +

The Imperative Way

+ +

Since we’ve used employees in the previous section, let’s keep within the theme. Let’s say you need to come up with a list of the employees who have used at least three sick days.

+ +

In a more procedural style, you’d maybe write something along the following lines:

+ +
	public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number)
+	{
+	    List<Employee> result = new List<Employee>();
+	
+	    foreach (var e in employees)
+	    {
+	        if (e.Sickdays >= number)
+	        {
+	            result.Add(e);
+	        }   
+	    }
+	
+	    return result;
+	}
+ +

I wouldn’t say there’s something definitely wrong with this code. The method’s name is a bit too long, but it’s very descriptive. The code does what it promises. And it’s readable enough.

+ +

But similarly to the previous section, we can make the argument that the code is too noisy. We can say that, essentially, the only line that does something domain related is the if test. All the other lines are basically boilerplate-y infrastructure code. Can a functional approach help us here?

+ +

The Functional Way

+ +

Let’s rewrite the method above by using LINQ:

+ +
	public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number)
+	{
+	    return employees.Where(x => x.SickDays >= n).ToList();
+	}
+ +

Here we use the “Where” extension method, passing the filtering criterium as a delegate. To be honest, the outer method became not very useful since it just delegates the work. In real life, I’d get rid of it.

+ +

Reduce

+ +

Reduce is often the one many developers have some difficulty understanding. But it isn’t hard at all. Think of it like this: you have a sequence of something, and you also have a function that takes two of these “somethings” and returns one, after doing some processing.

+ +

Then you start applying the function. You apply it to the first two elements in the sequence and store the result. Then you apply it again to the result and the third element. Then you do it again to the result and the fourth item, and so forth.

+ +

The classical example of reduce is adding up a list of numbers, so that’s exactly what we’re going to do in our example.

+ +

The Imperative Way

+ +

So, suppose we’re to sum a bunch of integers. We could do it like this:

+ +
	public int Sum(IEnumerable<int> numbers)
+	{
+	    var result = 0;
+	    foreach (var number in numbers)
+	    {
+	        result += number;
+	    }
+	
+	    return result;
+	}
+ +

At this point, you’re probably familiar with what I have to say about this code: it isn’t necessarily wrong, but it’s inflexible and noisy. Can functional programming save us?

+ +

The Functional Way

+ +

In .NET/C#, the “Reduce” operation assumes the form of the “Aggregate” extension method. This time, I’ll just get rid of the enclosing method and write the LINQ solution right away:

+ +
	var sum = number.Aggregate((x, y) => x + y);
+ +

Things look a little bit more complex here, but don’t get scared. In this case, we’re just passing a function that takes two parameters, instead of one, like in the previous examples. It has to be that way since the function must be applied to two elements of the sequence each time.

+ +

But as it turns out, there’s an even easier way of solving this particular problem (adding a bunch of numbers). Since summing a sequence of numbers is such a common use case, there’s a dedicated method to do just that. It’s called, not surprisingly, “Sum”:

+ +
	var sum = numbers.Sum();
+ +

What’s “Aggregate” good for, then? Well, adding a list of integers is just one of the applications for reduce, but you’re not in any way restricted to only that. You can use it with any binary operation, such as concatenating strings or summing custom types.

+ +

The Verdict: Is the Functional Approach Better?

+ +

After these examples, you might be wondering if the “functional” way is any better? It’d be extremely hard to define what “better” is, so I won’t even bother. Let’s consider another criterion: readability.

+ +

Though we know that code readability can also be highly subjective, I’d say that yes, the functional examples are more readable. Suppose we need to retrieve and sum all the salaries from employees with more than five years of company time. We could easily do that by writing a loop, in which we’d test the condition and accumulate the salary if the test turned out true.

+ +

Or we could just write this:

+ +
	var sum = employees.Where(x => x.CompanyTimeInYears > 5).Select(x => x.Salary).Sum();
+ +

I honestly believe this line to be more readable (and generally better) than the procedural approach. It’s more declarative; it shows the intention of what we’re trying to get done without being too concerned with the how.

+ +

It almost reads like natural language: “The list of employees where their time in the company is greater than five years, select their salary and sum them”.

+ +

Add Some Functional Spice to Make Your Code Tastier

+ +

Many people use LINQ for years without even realizing they’re using functional programming concepts. I take this as proof that functional programming isn’t beyond the capabilities of the enterprise developer who lacks a strong background in math.

+ +

Some of the concepts presented here are neither new nor restricted to functional programming. The benefits of distinguishing between functions that produce side effects from those that don’t is the basis of principles like command-query separation (CQS), for instance.

+ +

The goal of this post was not to teach you functional programming. This is honestly beyond my capabilities, as I’m still studying it myself. And besides, there are awesome resources for that purpose if you want to learn more.

+ +

Instead, what I wanted here is to give you a little taste of what a functional style can do for your code, which is to make it more expressive, concise, and declarative. Now it’s up to you to try to apply the functional mindset to the code you write.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/git-basics-for-tfs-users.html b/en/git-basics-for-tfs-users.html new file mode 100644 index 00000000..d5641558 --- /dev/null +++ b/en/git-basics-for-tfs-users.html @@ -0,0 +1,688 @@ + + + + + + + + Git basics for TFS/TFVC users | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Git basics for TFS/TFVC users

+ +
+ +
+

+ +

Learning Git can be a bit challenging for developers with a background in centralized version control systems. But it doesn’t have to be that way. +

+ +

Introduction

+ +

Git is becoming (or has already become, many would say) the de facto standard version control system of the industry. It was created in 2005 by Linus Torvalds to manage the source code from the Linux kernel, and since then its adoption has been growing phenomenally, specially after Github showed up.

+ +

However, even after all this time, there are some myths about Git that just won’t die. One of them is that Git is super hard to learn. From my experience, I can say that this isn’t true.

+ +

Git was meant to provide a lot of power and flexibility to its users. It certainly allows you to use it in more complex or sophisticate ways. But in practice, the basic commands you will use to get your daily work done are not that hard to learn.

+ +

That being said, Git’s learning curve may present some challenging to people that are used to centralized systems. I think it’s human nature to try to find patterns and to map concepts between what you already know and what you’re trying to learn; but there are significant differences and this “mapping” often results in frustration.

+ +

With that in mind, I’ve decided to write a series of posts to try to help developers who are coming from centralized systems (specifically TFS/TFVC) and trying to learn Git. I don’t intend by any means to exhaust the subject. Quite the opposite: when necessary, I’ll provide links for more in-depth explanations of certain topics.

+ +

A quick note about naming

+ +

TFS stands for Team Foundation Server. It is a Microsoft product that offers capabilities such as project management, requirement management, build automation and release management.

+ +

TFS also offers version control capabilities. Since TFS 2013 there has been native support for Git, but before that it was only possible by using TFS’s own version control system, which is called Team Foundation Version Control (TFVC).

+ +

So, TFS refers to the complete application life-cycle management solution. The version control system itself is called TFVC.

+ +

However, in this article I’ll be calling the version control system “TFS” since many developers colloquially call it that way.

+ +

Commit != Check-in

+ +

Being a centralized system, TFS presents a reasonably simple workflow, which usually consists of three steps:

+ +
    +
  1. Get the most updated version of the source code;
  2. +
  3. Make the necessary changes;
  4. +
  5. Send the code with the changes back to the server.
  6. +
+ +

So, you can see that the “check-in” command in practice has two meaning associated with it: “saving” changes and “sending” those changes to the server.

+ +

What I notice is that this notion of “I’m going to send my changes to the server” is a little bit hard to let go when you’re making the transition.

+ +

Remember: In Git there is no such thing as a central server.

+ +

What you have instead are remote repositories, usually called just remotes. You can have as much remotes as you want to. And they don’t necessarily have to be that remote. Yes, they could be on GitHub or something similar. But they could also be located on your coworker’s machine, on some network drive, or even on another folder in your own machine.

+ +

When your work in a team it’s common to set up a repository that is considered, for organization means, the official repository, which holds the code’s true and current state.

+ +

One more time: in Git doesn’t have a technical concept of a central repository; what’s described above is a convention.

+ +

With that in mind, let’s practice some Git commands so you can get used to them. Today we’re not seeing anything regarding remotes, server, nothing like that: just local commands.

+ +

Downloading and installing

+ +

Some people say that using Git on Windows used to be a pain. Fortunately, that isn’t the case anymore, as you’ll see.

+ +

First, download Git for Windows.

+ +

Double-click, next, next, you know the drill. There shouldn’t be a problem if you just choose all the default options. However, the following option might be useful: +

+ +

When you get to this screen, choosing the second option you allow you to use Git from the Windows command prompt, and not only from Git Bash.

+ +

Basic Configuration

+ +

After you’re done installing Git, it’s time to configure your identity, which consists in telling Git your name and email so it can associate them with each commit you make.

+ +

In order to do that, let’s use Git Bash. Locate “Git Bash” on Start Menu and run it. Git Bash’s window will be shown.

+ +

Type the following commands:

+ +
+

git config –global user.name “Your Name”

+ +

git config –global user.email “email@example.com”

+
+ +

There are a lot of other configurations available, but this is enough for you to be able to explore Git.

+ +

Creating your first repository

+ +

Using Git Bash, let’s create a folder and access it:

+ +
+

mkdir repo

+ +

cd repo

+
+ +

Now it’s time to create the repo:

+ +
+

git init

+
+ +

After running this command, you’ll see the following message:

+ +
+

Initialized empty Git repository in C:/Users/your-name/repo/.git/

+
+ +

Git Bash prompt should be showing you something like this:

+ +
+

User@Machine MINGW64 ~/repo (master)

+
+ +

Nothing mysterious: logged user, current location and current branch. In Git, the standard branch is called master. In the next post we’ll learn some basic operations in branches, but for now we’ll be using just master.

+ +

Some commands

+ +

OK, now you’ve got your repository, time to learn some commands. Let’s starting with one that you’ll probably use a lot: git status. This command allow you to visualize the current status of your repo.

+ +

When you run it you should see the following message:

+ +
+

On branch master

+
+ +
+

Initial commit

+
+ +
+

nothing to commit (create/copy files and use “git add” to track)

+
+ +

That is:

+ +
    +
  • current branch;
  • +
  • which is waiting for your first commit;
  • +
  • it shows what will go in the commit - which in this case is nothing, since we haven’t made any changes.
  • +
+ +

Git even tell us what the next possible step is, i.e. create or copy files and the use git add to track them (don’t worry for now about what this “tracking” thing means).

+ +

Let’s create a file.

+ +
+

echo test > arq1.txt

+
+ +

Run git status again and you’ll see that this time the message is different:

+ +
+

Untracked files: +(use “git add ..." to include in what will be committed)

+ +

arq1.txt

+ +

nothing added to commit but untracked files present (use “git add” to track)

+
+ +

Some new concepts here, starting with “Untracked files”. Git can see our new file but it will not include it in the next commit.

+ +

Again, Git tell us what to do next. Follow its advice and run the following command:

+ +
+

git add arq1.txt

+
+ +

Run git status again and look at the response:

+ +
+

Changes to be committed:

+ +

(use “git rm –cached ..." to unstage)

+ +

new file: arq1.txt

+
+ +

For now ignore this:

+
+

use “git rm –cached ..." to unstage

+
+ +

Now we can see that the added file is ready to be commited. So, let’s do it!

+ +
+

git commit -m “First commit”

+
+ +

The command below creates our first commit. The -m parameter is used to specify a commit message, which is essential for understanding the history of the project.

+ +

git status again:

+ +
+

On branch master

+ +

nothing to commit, working directory clean

+
+ +

Let’s now edit our file. Open it using notepad or another text editor of your preference and add the following line:

+ +
+

adding a new line

+
+ +

git status again:

+ +
+

On branch master +Changes not staged for commit: +(use “git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory)

+ +

modified: arq1.txt

+ +

no changes added to commit (use “git add” and/or “git commit -a”)

+
+ +

The message is familiar, but slightly different from the the previous ones. As you’re probably expecting by now, she ends offering us a suggestion for the next step. Let’s follow the suggestion:

+ +
+

git add arq1.txt

+
+ +

As you can see, this is the same add command we’ve already used, when the file was still in the “untracked” phase. Even tough the command is the same, its meaning is slightly different here. We’ll cover this difference in the future as well.

+ +

Run git status again, message, you should know the drill by now:

+ +
+

Changes to be committed: +(use “git reset HEAD ..." to unstage)

+ +

modified: arq1.txt

+
+ +

The message is very similar with one we’ve already seen, but notice that our file now is in the “modified” stage, instead of “new file”, which makes perfect sense.

+ +

It’s not hard to guess what’s coming next:

+ +
+

git commit -m “Second commit: add second line”

+
+ +

To wrap things up, run git status and you’ll see a familiar message: working directory clean, nothing to commit.

+ +

Conclusion

+ +

I kept this article extremely simple, and that was by design. My intention was to show you some basic Git commands, so you can get the “feel” of what using Git is like.

+ +

Notice that there is an easily perceptible pattern in the commands we ran:

+ +
    +
  • you create an file
  • +
  • “add it”
  • +
  • commit
  • +
  • edit it
  • +
  • “add it”
  • +
  • commit again
  • +
  • and son on
  • +
+ +

Where I’ve wrote “add it”, you know I’m talking about the git add command. You might have noticed that this particular command has two different usages, which is clearly evidenced by the different messages that git status shows us after running it.

+ +

You’ve probably also noticed the different stags that a file can be in: “untracked”, “new file”, “modified”. they progress from one stage to the next one, like in a pipeline.

+ +

In the next article of the series we’ll go a little more deep in this issues. We’ll understand the different “areas” that exist in a Git repository. We’ll understand Git’s basic workflow, and the stages our files can be in.

+ +

We’ll also start to see one of the more important Git’s concepts: branches. We’ll see some common operations involving branches, and you’ll also learn how Git branches are different from those in TFS.

+ +

See you soon!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/git-beautiful-history/index.html b/en/git-beautiful-history/index.html new file mode 100644 index 00000000..a3ee06bd --- /dev/null +++ b/en/git-beautiful-history/index.html @@ -0,0 +1,665 @@ + + + + + + + + Make Your Git History Look Beautiful Using Amend and Rebase | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Make Your Git History Look Beautiful Using Amend and Rebase

+ +
+ +
+

+ +

Photo by Yancy Min on Unsplash

+ +

You’re part of a small to medium-sized software team, and you’re envious of your co-worker’s Git history. They produce clean, well-structured histories with beautifully crafted commit messages. Yours, by comparison, looks like a train-wreck, full of descriptions such as “fix typo”, “add forgotten file”, and so on. You wonder how they do it.

+ +

The answer is simple: they cheat. You see, they probably make just as many mistakes as you do, but they use Git’s features to hide them. They then present a cleaner, nicer history to the world.

+ +

What they do is to rewrite history. Some version control tools treat history like it’s this super sacred thing. Git isn’t like that. It gives you power to rewrite history to your heart’s desire. So much power that you can even shoot yourself in the foot with it if you’re not careful.

+ +

In this post, I’ll show you how to use amend and interactive rebase to make your Git history look beautiful before publishing it. There won’t be much theory; I’ll walk you through some common scenarios, showing how I’d go about solving them.

+ +

Before wrapping up, I’ll teach you how to not shoot yourself in the foot with these commands. As I’ll explain, amending and rebasing are destructive actions, and there are situations in which you should not perform them.

+ +

Requirements

+

To follow along with this post, I assume you:

+ +
    +
  • Are comfortable working with the command line
  • +
  • have Git installed on your machine
  • +
  • know at least the basic Git commands
  • +
+ +

As I write this post, I’m on Windows, using Git version 2.38.1.windows.1 and typing my commands on Git Bash. If you’re on Linux or OSX, I guess everything will work just as fine, but I haven’t tested it myself.

+ +

Defining VS Code as Your Default Text Editor

+

Just a last digression before we really get started. Some of the commands you’ll be seeing throughout this post will require you to edit and save a text file. They do this by opening your default text editor as configured in your Git configuration file and waiting until you edit, save and close the file.

+ +

If you’re on Windows like me, using Git Bash, you’re default editor will be Vim. Vim is a command-line text editor, and some people find it intimidating. Though learning Vim requires some work, it’s not that hard to get the hang of it, and I’d recommend you invest some time to learn at least the most basic commands—specially how to quit!

+ +

However, Git allows you to pick other text editors as your default. If you have Visual Studio Code installed and want to use it, run the following command:

+ +

git config --global core.editor "code --wait"

+ +

Rewriting History: N Common Scenarios

+

I’ll walk you through a few common scenarios you might find yourself in which rewriting history will save you.

+ +

My Git Commit Message Has a Typo

+

You’re in a hjurry to fix this high priority bug. After hours of grueling debugging, you find the offending code, fix it and commit the change.

+ +

Only then you see you made a typo. How to fix that?

+ +

Let’s start by creating a repository for you to practice:

+ +

git init

+ +

Now, let’s add a new file and commit:

+ +

touch file.txt && git add file.txt && git commit -m "fix async request in getUsers() functino"

+ +

Run git log--oneline to see your commit message. You’ll see something like this:

+ +

+ +

Pay attention to the commit identifier, and maybe even write it down; it will be important later on. (Yours will be different than mine.)

+ +

Anyway, your message has a typo. How do you fix it?

+ +

Just run git commit --amend, exactly like that. Git will open your text editor and wait for you to edit the commit’s message:

+ +
fix async request in getUsers() functino
+
+# Please enter the commit message for your changes. Lines starting
+# with '#' will be ignored, and an empty message aborts the commit.
+#
+# Date:      Tue Jan 10 19:14:17 2023 -0300
+#
+# On branch master
+#
+# Initial commit
+#
+# Changes to be committed:
+#   new file:   file.txt
+#
+
+ +

The first line is the actual commit message. The lines starting with the “#” are comments and will be ignored. Just fix the typo, save and close the text file, and you’ll have a brand new commit message. Run git log --oneline again to see it:

+ +

+ +

You’ll notice that the identifier (SHA-1) of the commit is now different than it was before—and also different than the one from the image above. I’ll get back to this later.

+ +

For now, you’ve successfully amended your commit message. Congrats!

+ +

I Forgot to Include a File

+

Sometimes you have several changed files and want to commit some but not all of them. In your hurry, you leave one or more files behind. How to fix this?

+ +

Amend to the rescue again.

+ +

To simulate this situation, let’s create a new file and also add a new line to the existing one:

+ +
touch file2.txt
+echo 'New line' >> file.txt
+
+ +

A common mistake here is to run commit with the -a option, thinking it will include both files:

+ +

git commit -am "update file and add file2"

+ +

Run the command above. Then run git status. This is the result you’ll get:

+ +
On branch master
+
+Untracked files:
+
+  (use "git add <file>..." to include in what will be committed)
+
+        file2.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+ +

Fixing the situation is easy. First, you track or stage the forgotten file:

+ +

git add file2.txt

+ +

Then, use git commit –-amend again. Your editor will open, but in this case, there’s nothing wrong with the message. Just close the editor and you’re done: you now have an amended commit that includes the previously forgotten file.

+ +

But if you’re anything like me, you probably feel like a chump having opened your text editor for no reason at all.

+ +

Fortunately, you don’t always have to do that. When you just want to add one or more missing files without changing the commit message, you can use the --no-edit option, like this:

+ +

git commit –-amend –-no-edit

+ +

This way, Git won’t open your text editor, keeping the original commit message.

+ +

I Want to Merge Several Commits into One

+

Merging several commits into one is an operation called “squashing.” But why would you want to do that?

+ +

Well, it all boils down to your Git style. I like to make small commits, very often. Then, when I’m about to make them public (for instance, by opening a pull request) I squash them into a single commit, with a well-crafted message.

+ +

This is also a common requirement from open-source project maintainers, so it’s a good skill to have. Let’s learn how to do it.

+ +

First, let’s create three commits:

+ +
git commit --allow-empty -m "empty commit"
+git commit --allow-empty -m "empty commit 2"
+git commit --allow-empty -m "empty commit 3"
+
+ +

Creating text files for the sake of having commits gets old pretty quickly. That’s why I’m using the --allow-empty option, that enables me to create empty commits.

+ +

Now, let’s say I need to squash the three commits above into one. To do that, I’ll need to interactively rebase them. By doing an interactive rebase, you can perform tasks like:

+ +
    +
  • Reorder commits
  • +
  • Drop one or more commits
  • +
  • Change their messages
  • +
  • Merge one or more commits together
  • +
+ +

Now comes the part that might be confusing, so please pay attention. Since we’re going to work with the three latest commits, we say we’re rebasing them on top of the fourth (from the top) commit.

+ +

So, use the command git log --oneline -4 to display the last four commits and then copy the SHA1 from the fourth commit from the result:

+ +

+ +

Copy the identifier from that commit and pass it to the rebase command, like this:

+ +

git rebase -i 45f90ca

+ +

Of course, your actual SHA1 value will be different. But there’s an easier way:

+ +

git rebase -i HEAD~3

+ +

To put it simply, HEAD here means the latest commit, and “~3” means “three commits before this one.”

+ +

After executing either of the two commands above, your editor will open, showing a text file that contains the messages from the three commits we want to rearrange, each preceded by the word “pick”. And after that, a set of instructions:

+ +

+ +

Notice that the commits here aren’t in the order you’re used to seeing them on Git. Instead of being in inverse chronological order, they’re in direct chronological order, and there’s a reason for that.

+ +

Each line you see above is a command that Git will execute when you confirm the rebase operation. There are several commands available, and pick is the default one. It simply means the commit will be kept as is. You can use drop to remove a commit, reword to edit a commit’s message, and so on.

+ +

The command we’re going to use is squash. Just replace the word pick with squash in the second and third commits, like this:

+ +
pick dd25df9 empty commit # empty
+squash c68804f empty commit 2 # empty
+squash a76fd60 empty commit 3 # empty
+
+ +

The squash command merges a commit with the one before. So, the third will be merged into the second, which will be merged into the first one. And that’s why the first one needs to be picked.

+ +

After editing the text like I told you, save and close the file. When you do that, your editor will be opened once again. This time, you’ll be prompted to write a commit message for the new commit that will emerge:

+ +

+ +

Replace the file’s content with “this is now a single commit.” Save and close the file.

+ +

Finally, let’s see the result:

+ +

git log --oneline

+ +

This is what you should get:

+ +

+ +

As you can see, the three empty commits were replaced by a single commit. You’ve successfully performed your first squash. Congrats!

+ +

When You Shouldn’t Mess with History

+

Before wrapping up, let’s understand when changing history is problematic.

+ +

First, understand that both amend and rebase produce destructive changes. It’s like they’re destroying history and creating a new one.

+ +

So, imagine that you squash three commits (there were already pushed to the remote) into one and then push that new commit into the remote repository (you’d have to force push for that to work, by the way.) But while you were working, your coworker had branched off from (what was then) the latest commit.

+ +

That commit no longer exists (technically, that’s not quite true, but let’s pretend for a minute that it is), which means they won’t be able to simply push their changes. They’ll have to pull your new commits and then perform a potentially complex merge in order to get things sorted.

+ +

So, the golden rule is never rewrite history that other people depend upon. What this means in specific will depend on whatever branching workflow you and your team use.

+ +

If you use trunk-based development, never rewrite the master/main branch. The same is true if your work with GitHub Flow. If you use git-flow, that means never rewriting the “eternal” branches, i.e., master/main and develop.

+ +

OK, I Lied: Here’s a Bit of Theory

+

Throughout this post, I’ve been using language like “change the commit’s message”, “merge multiple commits into one”, and so forth.

+ +

Technically speaking, those were all lies. When you use commands like git commit --amend or git rebase -i, you’re not changing anything. What Git is doing is creating new commits.

+ +

Remember when you first used amend and I said that it was relevant that the commit now had a new identifier? As it turns out, that was an entire new commit, and the old one is still out there!

+ +

The same goes for rebasing. When you “merge three commits into one”, that’s not what’s happening. Instead, Git creates a new commit and updates the branch reference, so it points to the new commit. The three old commits are still there (at least for a while) but since no branch points to them they’re unreachable—unless you can get ahold of their SHA1 values somehow.

+ +

The following image represents what really happened after you squashed your commits:

+ +

+ +

Now, let’s see the scenario after the squash:

+ +

+ +

As you can see, there’s now a new commit, in orange, which is the result of “merging” the three original ones. However, the three old commits are still there. You can’t easily reach them, though, because now there’s no branch pointing to them.

+ +

The astute reader will notice that even the images above are a simplification. “We should have more commits in the image!”, they say, with their accusatory index finger pointing at the scream. And guess what, they’re right.

+ +

Remember we started this whole thing by amending two commits? Well, since amend doesn’t change commits but create new ones, we have two extra lost commits in our repository. I omitted them from the diagrams above because I was feeling kind of lazy for brevity’s sake. But as an exercise for the reader, you can add them yourself.

+ +

Rewrite the Past to Look (And Be) Smarter

+

Rewriting history is a powerful capability of Git. With commands such as git commit --amend and git rebase -i you can “change” your past commits, hiding your mistakes and making it look like you got everything right from the start. I do this all the time and I reap the benefits: my coworkers think I’m way smarter than what I’m really—please don’t tell them my secret.

+ +

Seriously now: these commands are fantastic tools for getting a more organized history. With them, you can lose the fear of committing frequently once and for all. Make commits small and frequent, and don’t pay too much attention to the message-for example, if you use TDD, you can commit every time the tests pass.

+ +

Then, when it is time to publish your work, squash the commits and put a nice description on them. Adopt a commit messaging convention for you and your team, such as Conventional Commits. Your colleagues (and your future self) will thank you.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/git-create-branch.html b/en/git-create-branch.html new file mode 100644 index 00000000..ebd6f17f --- /dev/null +++ b/en/git-create-branch.html @@ -0,0 +1,564 @@ + + + + + + + + Git Create Branch: 4 Ways To Do It | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Git Create Branch: 4 Ways To Do It

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the Cloudbees blog. You can check out the original here, at their site.

+ +

If you write software for a living, then I can say with confidence you’re familiar with Git. The tool created by Linus Torvalds has become synonymous with version control. And without a doubt, one of Git’s best features is how it takes away the pain of branching and merging. There are several ways you can create a branch in Git. In this post, we’ll review some of them. Then we’ll end with a little reflection on Git’s branching model and branching in general.

+ +

Creating a Branch From main

+ +

You create branches in Git, unsurprisingly, by using the branch command. Like many other Git commands, branch is very powerful and flexible. Besides creating branches, it can also be used to list and delete them, and you can further customize the command by employing a broad list of parameters. We’ll begin with the first way of creating a branch. Let’s say you want to create a new folder called “my-app”, enter it, and start a new Git repository. That’s exactly how you’d do it:

+ +
mkdir my-app
+cd my-app
+git init
+
+ +

Now you have a new, empty Git repository. But empty repositories are boring. So what about creating a new markdown file with “Hello World!” written in it?

+ +
echo Hello World! > file.md
+
+ +

If you run “git status”, you should see a message saying your file is untracked:

+ +
$ git status
+On branch main
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+    file.md
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+ +

Untracked files are also uncool, though, so let’s track it:

+ +
git add file.md
+
+ +

And finally, let’s create our first commit:

+ +
git commit -m "First commit"
+
+ +

We now have a repository with one branch, which has exactly one commit. That might not sound like the most exciting thing in the world (because it really isn’t), but it’s certainly less boring than having a repo with no commits at all, right?

+ +

Now, let’s say that for whatever reason you need to change the file’s content. But you don’t feel like doing that. What if something goes wrong and you somehow spoil the beautiful, pristine content of your file? (Yeah, I know it’s just some stupid file with “Hello World!” in it, but use the wonderful powers of your imagination and think of the file as a proxy for a much more complex project.) The solution to this dilemma is, of course, creating a new branch:

+ +
git branch exp
+
+ +

So now we have a new branch called “exp”, for experimentation. Some people who are used to using different versioning systems, especially centralized ones, could say the branches have the same “content.” This isn’t entirely accurate when talking about Git, though. Think of branches like references that point to a given commit.

+ +

Creating a Branch From a Commit

+ +

Suppose that, for whatever reason, we give up on our experiment, without adding a single commit to the new branch. Let’s go back to main and delete the exp branch:

+ +
git checkout main
+git branch -d exp
+
+ +

Now that we’re back to a single branch, let’s add some commits to it, to simulate work being done:

+ +
echo a new line >> file.md
+git commit -a -m "Add a new line"
+echo yet another line >> file.md
+git commit -a -m "Add yet another line"
+echo one more line >> file.md
+git commit -a -m "Add one more line"
+echo this is the last line i promise >> file.md
+git commit -a -m "Add one last line"
+
+ +

Imagine that after doing all this “work,” you learn that, for whatever reason, you need to go back in time to when there were just two lines in the file and create new changes from then on. But at the same time, you must preserve the progress you already made. In other words,  you want to create a branch from a past commit. How would you do that? In Git, each commit has a unique identifier. So you can easily see this using the git log command. To create a new branch based on a specific commit, just pass its hash as a parameter to the branch command:

+ +
git branch new-branch 7e4decb
+
+ +

As an aside, you don’t even need the whole hash most of the time. Just the first five or six characters will do it.

+ +

Creating a Branch From a Tag

+ +

If you’re a little bit more experienced with Git, then you should be familiar with the concept of tags. You use tags to indicate that a given commit is important or special in some way. For instance, tags are generally used to indicate the actual versions of a product. If you’ve been working in your application for a while and you believe it’s time to release version 1.0, what you’d typically do is bump the version numbers wherever necessary, committing those changes and then adding a tag to that specific point in time. To create a tag, you’d usually run something like this:

+ +
git tag -a v1.0 -m "First major version"
+
+ +

The “-a” parameter indicates this is going to be an annotated tag. In contrast to a lightweight tag, this is a full-blown Git object, containing pieces of information such as the committer’s name and email, the timestamp, and a message. Now you have a tag, an indication that this particular point in history is special and has a name.

+ +

Nice. You can continue doing work, as usual, creating and committing changes that will be part of the 1.1 version. Until a bug report comes in. Some clients that were updated to the 1.0 version of the product say an import feature isn’t working as intended.

+ +

Well, you could theoretically fix the bug in the main branch and deploy it. But then the clients would receive features that are potentially untested and incomplete. That’s a no-no. So what do you do? The answer: You create a new branch from the tag you’ve created to indicate the major version. You fix the issue there, build, and deploy. And you should probably merge this back to main afterward, so the next releases contain the fix. How would you go about that? Easy:

+ +
git branch <NAME-OF-THE-BRANCH> <TAG>
+
+ +

More specifically, using our previous example:

+ +
git branch fix-bug-123 v1.0
+
+ +

After that, you can check out your new branch as usual. Or better yet, you could do it all in one step:

+ +
git checkout -b fix-bug-1234 v1.0
+
+ +

Creating a Branch in Detached Head State

+ +

Have you ever wished to go back in time? With Git this is possible…at least in regard to the files in our repository. You can, at any time, check out a commit if you know its hash:

+ +
git checkout <SHA1>
+
+ +

After running that, Git will show you a curious message:

+ +
You are in 'detached HEAD' state. You can look around, make experimental
+changes and commit them, and you can discard any commits you make in this
+state without impacting any branches by performing another checkout.
+
+ +

When you check out a commit, you enter a special state called, as you can see, “detached HEAD”. While you can commit changes in this state, those commits don’t belong to any branch and will become inaccessible as soon as you check out another branch. But what if you do want to keep those commits? The answer, unsurprisingly, is to use the checkout command again to create a new branch:

+ +
git checkout <sha1> #now you're in detached head state
+# do some work and stage it
+git commit -m "add some work while in detached head state"
+git branch new-branch-to-keep-commits
+git checkout new-branch-to-keep-commits
+
+ +

And of course, by now you know you can write the last two lines as a single command:

+ +
git checkout -b new-branch-to-keep-commits
+
+ +

Pretty easy, right?

+ +

Just Because You Can…Doesn’t Mean You Should

+ +

Git’s branching model is one of its selling points. It turns what in other source control systems is a painful and even slow process into a breeze. One could say that Git has successfully democratized branching for the masses. But there lies a serious danger. Due to the cheapness of branching in Git, some developers might fall into the trap of working with extremely long-lived branches or employing workflows or branching models that delay integration.

+ +

We, as an industry, have been there. We’ve done that. It doesn’t work. Instead, embrace workflows that employ extremely short-lived branches. You’ll have a secure sandbox in which to code without fear of breaking stuff or wasting your coworkers’ time. But does that have you asking, “How do I deploy code with partially completed features?” In that case, it’s feature flags to the rescue.

+ +

Git branches are a powerful tool. Use them wisely, and don’t abuse them. And when they’re not enough, employ continuous delivery/continuous integration along with feature flags—including specialized tools at your disposal—so your applications can get to the next level.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/how-to-choose-good-names/index.html b/en/how-to-choose-good-names/index.html new file mode 100644 index 00000000..f3412677 --- /dev/null +++ b/en/how-to-choose-good-names/index.html @@ -0,0 +1,545 @@ + + + + + + + + Ten tips to help you choose good names | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Ten tips to help you choose good names

+ +
+ +
+

+ +
+

There are only two hard things in Computer Science: cache invalidation and naming things.

+ +

Phil Karlton

+
+ +

Do you want to write great code? Clean, understandable, human-readable code? Well, there are several skills you need to acquire. But I’d say #1 on the list is “Picking Good Names”. +

+ +

Choosing great names for your classes, methods, variables and the like is essential. Wisely chosen names often are the difference between good and awful code.

+ +

But what exactly is a good name? Even though there are some generally accepted guidelines, I’m afraid there isn’t a real consensus. (As it is with a lot of topics in our field, I’d say).

+ +

So, today I’m going to talk about naming conventions and principles that I try to use whenever I’m coding. It’s a mix of what I learned in college, studying by my own and working as a professional developer. It’s been useful to me, so I hope it’s going to be useful to you as well.

+ +

Some of the tips I’m going show you here today come from the book “Clean Code”, by Robert C. Martin (Uncle Bob). It’s one of my favorite programming books, and I’ll write a review on it sometime soon. Stay tuned!

+ +

0. Use self-explanatory names

+ +

What your variable/class/whatever does? How it’s supposed to be used? Choose a name that answers these questions.

+ +

Some people have the misguided notion that shorter names are always better. I can’t understand this. Are they trying to save keystrokes or something?

+ +

Let’s say you’re browsing a code base and you see some code like this:

+ +
    int d; // days until deadline
+ +

You could argue that this code is fine. The variable’s meaning is perfectly expressed in the comment. Great, but remember that the variable will probably be used in other points, away from the declaration and the comment.

+ +

So…why not just drop the comment and use the comment’s text as the variable’s name?

+ +
    int daysUntilDealine;
+ +

1. Use abbreviations only when they’re widely known

+ +

It would be crazy to name a variable “ServiceUniformResourceLocator” instead of “ServiceUrl”. Every developer knows what a Url is. The same thing with Ftp, UI, IO, and so on. So, it’s ok to use abbreviations to name things, but only if they are widely known and used. It would be counterproductive not to do so.

+ +

By the way. When I say “widely known”, I don’t necessarily mean worldwide known. Of course you can use abbreviations that are common in your business domain. It is considered a best practice to program as close as possible to the customer’s language. So, if your fellow developers and the business people are comfortable with the abbreviations, there’s no problem at all in using them.

+ +

2. Choose clarity over brevity

+ +

This is somewhat related to the first point. All else being equal, shorter names are better. But one day you’ll have to choose between clarity and brevity. When that day comes, always pick clarity. Six months down the road, when you have to revisit that code, you’re going to thank yourself.

+ +

3. Use widely accepted conventions (most of the time)

+ +

There are very few points in the book “Clean Code” that I disagree with. One of them is Uncle Bob’s recommendation to not start interface names with a capital “I”. He argues that this practice is reminiscent of Hungarian notation, and thus should die. Even though I understand why he thinks like this, I’m still starting my interface names with an “I”.

+ +

Why? One simple reason: starting interface names with an “I” is a very widespread and accepted convention in the .Net community. When you go against an established convention, you risk alienating developers who are used to that convention, like potential new team members or open-source projects contributors.

+ +

I think you should abandon a widely accepted convention only when the benefit of doing so greatly outweighs the costs. And I don’t think that’s the case here.

+ +

4. Don’t use Hungarian notation

+ +

Maybe you’ve heard about Hungarian Notation, maybe you haven’t. But I bet you’ve seen it, or even used it yourself, even if the name doesn’t ring a bell immediately.

+ +

So, what is this Hungarian thing? Our friend Wikipedia comes to our rescue:

+ +
+

Hungarian notation is an identifier naming convention in computer programming, in which the name of a variable + or function indicates its type or intended use.

+ +

Wikipedia: Hungarian Notation

+
+ +

So, in a nutshell, Hungarian notation is encoding the type of the variable in its name. So, if I have an int variable meant to store the age of a student, I’d call it iStudentAge or intStudentAge. Similarly, a string variable supposed to store a product’s description would be called sProductDescription, or even strProductDescription.

+ +

And why is this bad? Here are a few reasons:

+ +
    +
  • First of all, it’s useless. If your variable has a self-explaining name (see item #0), it will give you a decent clue about its type. If you spot a variable called productName, would you think it’s a floating-point number? Besides, most modern IDEs can tell you not only the variable’s type, but also if it’s a local variable,instance member or a method parameter, and even how many times it’s been referenced.
  • +
  • It can be misleading. People make mistakes, and it’s perfectly possible to change the variable’s type but forget to also change its name to reflect the new type. So now you have a variable prefixed with “int” but it’s actually a long.
  • +
  • It makes the names more difficult to pronounce, and this may complicate discussion about the code and the architecture of your application.
  • +
+ +

5. Stick to the language/framework/project’s coding style

+ +

Most C# developers tend to use CamelCase to name local variables, instance variables and methods parameters, as in productName. In Ruby, for instance, the recommended style is snake_case, as in product_name.

+ +

Development frameworks and open-source projects might have their own guidelines and standards as well.

+ +

It would be pointless to fight against established standards, due to a matter of taste and preference. If you’re writing Ruby code, write the way the Ruby community expects. The same with Java, C#, PHP, what have you.

+ +

It’s like they say: “When in Rome, do as the Romans do”.

+ +

6. Method names should start with a verb

+ +

This one is really short. Methods are usually actions that an object can perform. As such, their names should start with a verb that indicates the action to be performed, e.g. PrintReport(), DrawShape(IShape shape).

+ +

7. Class names should be nouns

+ +

Likewise, class names should be nouns, like Product, Customer, Student. Avoid using the words like Manager, Data, because they add little or no value.

+ +

8. Property names should be nouns or adjective phrases (C# specific)

+ +

Properties should be names with nouns, noun phrases or adjectives. When naming boolean properties, you may add the prefixes Can, Is or Has, when doing so provides value to the caller.

+ +

9. Use pronounceable/searchable names

+ +

Work hard to choose names that are pronounceable. When you pick a name that is hard or impossible to pronounce, you discourage discussion about your code, which is never a good thing.

+ +

Likewise, try to avoid names with a single letter. Among other reasons, they may give you a very hard time when you have to search for them! They make good names only for loop control variables or in lambda expressions. But even then, only when the scope is super short.

+ +

Conclusion

+ +

Choosing names is really hard. A name should express purpose, intention, meaning. It doesn’t necessarily need to be clever – but there are certain tricky situations that will require a little bit of cleverness.

+ +

A name should clearly express the purpose of the entity being named. But there are a lot of things that are very complex by their own nature, and it’s not so easy to come up with a perfect name for a very complex concept.

+ +

Sometimes, the difficulty you experience while choosing a name is a symptom of another problem, like a messy architecture, for instance. If you can’t decide between five options when naming a class, maybe the class is violating the Single Responsibility Principle (it’s trying to do more than one thing).

+ +

On the other hand, if you feel like calling a dozen classes the same thing…maybe they belong together as a single class.

+ +

Choosing names is ultimately about communication. And I think that’s why it’s such a hard task. Because we, developers, are not necessarily famous for our communication skills.

+ +

In “Clean Code”, at the end of the chapter about choosing good names, Uncle Bob writes:

+ +
+

The hardest thing about choosing good names is that it requires good descriptive skills and a shared cultural background. This is a teaching issue rather than a technical, business, or management issue. As a result, many people in this field do not do it very well.

+
+ +

Don’t be like most people in our field. Do the hard work and learn how to name things. You’ll thank yourself in the future.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/linq-join-operator.html b/en/linq-join-operator.html new file mode 100644 index 00000000..e321f779 --- /dev/null +++ b/en/linq-join-operator.html @@ -0,0 +1,758 @@ + + + + + + + + The LINQ Join Operator: A Complete Tutorial | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

The LINQ Join Operator: A Complete Tutorial

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the Stackify blog. You can check out the original here, at their site.

+ +

I think most C# developers would agree that LINQ is an integral part of the experience of writing code with the language. LINQ provides a fluent, intuitive, and consistent way to query data sets. In this post, we’ll help in your LINQ-mastering quest by covering the LINQ join operator.

+ +

We’ll start the post with a definition of LINQ itself, so we’re all on the same page. After that, you’ll see an explanation of join operations in LINQ. Then, it’s time to roll up your sleeves and get practical with our hands-on guide to the join operator.

+ +

Let’s get started.

+ +

What is LINQ?

+ +

LINQ stands for Language Integrated Query. It’s a C# feature that offers a unique and consistent syntax for querying datasets, regardless of their origin. The main benefit of LINQ is that you can use the same syntax to query data in memory, from a database, XML files, and so on.

+ +

LINQ is available in two different flavors, the query syntax and the method syntax.

+ +

The query syntax leverages special keywords to create a syntax that is familiar to anyone who’s worked with SQL. Here’s an example that queries a sequence of numbers, filtering the ones greater than 5:

+ +
int[] numbers = { 2, 8, 4, 9, 3, 6, 1, 7, 5 };
+var largerThanFive =
+    from num in numbers
+    where num > 5
+    select num;
+ +

The method syntax allows you to use extension methods to perform the same query:

+ +
int[] numbers = { 2, 8, 4, 9, 3, 6, 1, 7, 5 };
+var largerThanFive = numbers.Where(x => x > 5);
+ +

What is The LINQ Join Operator?

+ +

When working with data, a common scenario is having two data sources that you want to combine based on some criteria. For instance, you might have a Books table and an Authors table in your database, with a one-to-many relationship between them—i.e., an author can author many books, but each book has only one author. If you need to compile a list of books containing their author’s name, you’d need to perform a join in order to match each line from the Books table to its counterpart in the Authors table.

+ +

A join in LINQ is essentially the same: an operation where you can merge two collections according to some criteria you define.

+ +

The LINQ Join Operator in Practice-

+ +

Examples always make things clearer. So, let’s see how to use the join operator in practice.

+ +

Starting With a Problem

+ +

Let’s say you have an e-commerce application with some data on categories:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdName
1Electronics
4Toys
5Stationery
7Books
10Clothes
+ +

Okay, now let’s have some products:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdNameCategory_Id
1Amazon Kindle1
2Refactoring7
3C# in Depth7
4Legal Pad 50 sheets5
+ +

You can see where this is leading, right? The next thing you’d want to do is to produce a single collection, having the list of products and the names of the categories they belong to. In other words, a view like this:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdNameCategory
1Amazon KindleElectronics
2RefactoringBooks
3C# in DepthBooks
4Legal Pad 50 sheetsStationery
+ +

Solving The Problem: Performing a LINQ Inner Join

+ +

What would that operation look like in code? First of all, we need code to represent our categories and products. Thanks to C#’s record feature, two lines of code suffice for that:

+ +
public record Product(int Id, string Name, int CategoryId);
+public record Category(int Id, string Name);
+ +

Now, let’s have a list of each type:

+ +
var categories = new List<Category>
+{
+    new Category(1, "Electronics"),
+    new Category(4, "Toys"),
+    new Category(5, "Stationery"),
+    new Category(7, "Books"),
+    new Category(10, "Clothes")
+};
+
+var products = new List<Product>
+{
+    new Product(1, "Amazon Kindle", 1),
+    new Product(2, "Refactoring", 7),
+    new Product(3, "C# In Depth", 7),
+    new Product(4, "Legal Pad 50 Sheets", 5),
+    new Product(5, "Surgical Gloves", 12)
+};
+ +

As you can see, the list of products has an additional product (surgical gloves) whose category id doesn’t match any of the available categories. Keep this in mind; it’ll be relevant in a moment.

+ +

Now, let’s write code to perform this join. I’ll show the code in one go and then explain it:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+
+foreach (var line in query)
+{
+    Console.WriteLine(line);
+}
+ +

Now, the explanation:

+ +
    +
  • from p in products -> we’re defining the origin of one of our data sources
  • +
  • join c in categories -> Here, we’re saying that we want to join the previous collection with this one
  • +
  • on p.CategoryId equals c.Id -> This is the condition for the join: the CategoryId on each product should match the Id of a category
  • +
  • select new… -> Here, we’re leveraging C#’s anonymous objects feature to create a new object on the fly, which has the properties we want
  • +
+ +

The result of this query is an IEnumerable of our anonymous object. We then iterate through each item of this collection, displaying it on the console. This is the result: +`

+
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+{ Id = 2, Name = Refactoring, Category = Books }
+{ Id = 3, Name = C# In Depth, Category = Books }
+{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery }
+
+ +

Those of you who remember your databases will notice that the LINQ join we performed is the equivalent of an inner join in SQL. In other words, only items that have a match are returned. In SQL, the equivalent query would look like this:

+ +
SELECT p.Id, p.Name, c.Name AS Category
+FROM products AS p
+JOIN categories AS c ON p.CategoryId = c.Id
+ +

Performing a LINQ Outer Join

+ +

What if you wanted to perform the equivalent of a SQL outer join? That is, you want to retrieve all products, even the ones that don’t match any category. How to go about that?

+ +

Here’s the updated query:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id into joinedCategories
+    from c in joinedCategories.DefaultIfEmpty()
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c?.Name
+    };
+ +

  It looks similar, but there are two differences:

+ +
    +
  • on p.CategoryId equals c.Id into joinedCategories -> here, after joining products with categories, we send the result, as a grouped sequence, to the joinedCategories range variable
  • +
  • from c in joinedCategories.DefaultIfEmpty() -> Then, we retrieve items from the groupedSequence, using the DefaultIfEmpty() method to return the default value when no matches are found
  • +
  • Category = c?.Name -> Finally, when assigning the category name to the Category property on our anonymous object, we have to use the null-conditional operator in order to avoid a null-reference exception (since the default value for Category is null because it’s a reference type.)
  • +
+ +

The result is now different:

+ +
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+{ Id = 2, Name = Refactoring, Category = Books }
+{ Id = 3, Name = C# In Depth, Category = Books }
+{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery }
+{ Id = 5, Name = Surgical Gloves, Category =  }
+ +

As you can see, the “Surgical Gloves” product now appears, even if it doesn’t have a matching category.

+ +

LINQ Inner Join With Where Condition

+ +

Performing a join with a where clause is quite easy. In this example, we’ll perform an inner join, filtering only the products whose id are equal to or greater than 3:

+ +
var query =
+    from p in products
+    where p.Id >= 3
+    join c in categories
+    on p.CategoryId equals c.Id
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

LINQ Inner Join With Multiple Conditions

+ +

If you want to use multiple conditions within your join, you can simply use more than one where clause. Let’s update our query once again:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id
+    where p.Id >= 3
+    where c.Name.EndsWith('s')
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

Here, we’re filtering only categories whose names end with the letter s.

+ +

LINQ Join With Composite Key

+ +

Up until now, all of our examples have used single keys to perform the matching. You can also use composite keys—that is, more than one value—for the matching.

+ +

Suppose both our Product and Category classes gained a new property called Status, which is an enum that can vary between three states: Pending, Active, and Archived. Now, the Status property also needs to be used for the match.

+ +

All of our products are active, but not all of the categories:

+ +
var categories = new List<Category>
+{
+    new Category(1, "Electronics", Status.Active),
+    new Category(4, "Toys", Status.Active),
+    new Category(5, "Stationery", Status.Archived),
+    new Category(7, "Books", Status.Pending),
+    new Category(10, "Clothes", Status.Active)
+};
+
+var products = new List<Product>
+{
+    new Product(1, "Amazon Kindle", 1,  Status.Active),
+    new Product(2, "Refactoring", 7,  Status.Active),
+    new Product(3, "C# In Depth", 7,  Status.Active),
+    new Product(4, "Legal Pad 50 Sheets", 5,  Status.Active),
+    new Product(5, "Surgical Gloves", 12,  Status.Active)
+};
+ +

This is what our updated query looks like now:

+ +
var query =
+    from p in products
+    join c in categories
+    on new { Id = p.CategoryId, Status = p.Status }
+    equals new { Id = c.Id, Status = c.Status }
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

It’s not much more complicated than before. The difference is that now, we use an anonymous object to perform the comparison using both the id and the status properties.

+ +

A single result is displayed from this query:

+ +
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+ +

Conclusion

+ +

As we’ve seen, LINQ is an essential part of working with C#. You can leverage LINQ in many different scenarios, from working with data in memory to XML to SQL. You can use LINQ in ORMs such as NHibernate and Entity Framework.

+ +

Teams that wish to make their LINQ experiences even better can use the tools at their disposal. For instance, Stackify’s Prefix and Retrace offer powerful capabilities of tracing, profiling, and centralizing logging that helps teams inspect their code to find opportunities for performance improvements, which includes LINQ queries.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/mutation-testing/index.html b/en/mutation-testing/index.html new file mode 100644 index 00000000..7316b91d --- /dev/null +++ b/en/mutation-testing/index.html @@ -0,0 +1,499 @@ + + + + + + + + Mutation Testing: What It Is and How It Makes Code Coverage Matter | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Mutation Testing: What It Is and How It Makes Code Coverage Matter

+ +
+ +
+

+ +

Photo by Christina @ wocintechchat.com on Unsplash

+ +

Editorial note: This post was originally written for the NCrunch blog. You can check out the original here, at their site.

+ +

I’ve been fascinated by mutation testing since I found out about it. I thought I’d finally found the answer to so many problems I had when writing tests. With mutation testing, I now had a way to really trust my tests. At last, code coverage had meaning again.

+ +

Then, I was dumbstruck as I realized that very few developers shared my interest in mutation testing. In fact, I dare say that most developers haven’t even heard about it. And that’s a shame because they—and we, as an industry—are missing out on so many benefits.

+ +

So, this post is my humble attempt to remedy the situation. I’ll start by explaining the current dilemmas developers face regarding the reliability of the tests they write. Then, I’ll proceed to show you how mutation testing is the answer to these dilemmas. I’ll explain what it is, how it can make your tests more trustworthy, and how it can turn code coverage into the valuable metric it should be.

+ +

The Problem: Trustworthiness of Tests

+ +

When learning about unit tests—or automated tests in general—most people will ask the same or a similar question: How do I know my tests are right? That’s a legitimate concern. If your tests aren’t trustworthy, then you might be better off with no tests at all.

+ +

So what’s the answer? How do people deal with the problem of test trustworthiness without relying on mutation testing?

+ +

Making Tests Reliable Without Mutation Testing

+ +

There are techniques developers employ to improve the reliability of their tests, and we’ll briefly cover some of them in this section. If you’re experienced with unit testing, you’re probably familiar with them. Let’s dive in.

+ +

Keep Your Tests Simple

+ +

The first technique we’ll cover here to improve the reliability of your tests is just to keep them simple. And by “simple” I mean with less cyclomatic complexity. The lower the cyclomatic complexity of a given piece of code, the likelier it is that it actually does what you think it does. Simple code is easier to reason about, which is a property you definitely want your unit tests to have.

+ +

Keep test code simple to the point of being obvious. That means, for instance, avoiding loops or decision structures. Also, avoid doing anything fancy to compute the expected result (more on that in the next section). Hard-code it instead.

+ +

Don’t Duplicate Implementation Code

+ +

Let’s say you’re doing the Roman numerals kata. Resist the temptation to automatically generate the expected values (“I” for 1, “II” for 2, and so on). Instead, hard-code the values. If the repetition really bothers you and your test framework allows it, use parametrized tests.

+ +

Why would that be a problem? Simple: The fancier your test code gets, the more likely it’s duplicating production code. If that’s the case, you might be unlucky enough to find yourself in the situation where your production code is wrong (it doesn’t solve the problem as it’s supposed to do) but the tests pass. That’s one of the worst possible scenarios. It’s even worse than having no tests at all.

+ +

Ensure You See the Test Failing

+ +

Ensure each test fails at least once before it passes. If you see the test failing when you think it should be failing and vice versa, that’s a sign you’re moving in the right direction. It doesn’t guarantee anything, but it decreases the likelihood the test is passing due to a coincidence.

+ +

Here’s how you’d do it. As soon as you get to the green phase, damage the implementation code in such a way that one or more tests should fail. You could invert conditionals, replace strings or numeric literals with random values, or even delete an if-statement. If you manage to sabotage production code and get away with it, that’s not a good sign. Your test suite is either wrong or incomplete. In a sense, you’re testing the tests.

+ +

Developers who employ TDD (test-driven development) kind of already do that by definition. Since you write a failing test and then proceed to make it pass, you’re seeing the test fail. Of course, the test should fail in the expected manner. Meaning that if you’re performing an assertion, the test should fail due to an assertion failure and not, say, because the method under test throws an exception. Yes, this is better than nothing, but it still might not be enough. Since a unit test represents a single-use case, it’s totally possible to introduce a defect to production code in such a way that this particular test still passes.

+ +

We Must Do Better: Enter Mutation Testing

+ +

So you’ve just applied the technique described in the last section. Good! Not perfect, though. Here comes a problem. You can’t just insert a lot of defects and run the tests, because you wouldn’t be able to identify which defect was responsible for the tests failing. The correct way to do it is to insert a single deliberate defect, run all the tests, verify their result, and then roll back the change. After that, you can introduce another mistake, run all the tests again, verify the result, roll back the change…rinse and repeat. Needless to say, such an approach is extremely slow, tedious, and error-prone.

+ +

That’s where mutation testing comes in.

+ +

What’s Mutation Testing, Anyway?

+ +

Mutation testing is nothing more, nothing less, than automating the whole “sabotaging production code and running tests to see if they fail” process you just saw. To use mutation testing, you need a mutation testing framework. The framework will alter production code, introducing defects that are called “mutations.” For each mutation introduced, the framework will again run the suite of unit tests. If all tests pass, we say the mutation survived. That’s a bad thing. It means that either your suite is lacking tests or the existing ones are wrong.

+ +

If, on the other hand, one or more tests fail, that means the mutation was killed, which is a good thing. The framework will repeat that process until it’s tested the relevant portion of the codebase. When it’s all done you can check the results, which will contain the number of mutations introduced, as well as the ratio of surviving vs. killed mutants.

+ +

Mutation Testing Makes Code Coverage Better

+ +

One of the most controversial topics in the unit testing world is the argument about code coverage. Some developers say that getting to full coverage is essential; others will argue that’s a useless metric. Who’s right?

+ +

First of all, you have to understand that this issue isn’t black and white. As is the case with pretty much everything in software, there’s some nuance. Of course code coverage isn’t useless. Knowing that your codebase has, say, 10% of test coverage is definitely a useful piece of data. Such a coverage is way too low: Seeing the green bar won’t offer them any confidence. That’s not to say that having 100% coverage is necessarily a good thing in itself. You could have tests that don’t have assertions, for instance. Yes, this is a contrived example, but something like that could (and sometimes does) happen.

+ +

A more common occurrence would be to just have tests that don’t exercise enough paths in the software. In short: Low code coverage is definitely a bad thing, but high (or full) code coverage is not necessarily a good thing since it says nothing about the quality of the tests in the suite.

+ +

Since mutation testing does verify the quality of the test suite, it’s the missing piece of the puzzle. If your codebase has a high code coverage and the results of mutation tests show that most or all mutations introduced are being killed, then smile! You probably have a great test suite in place!

+ +

Embrace Mutation Testing Today

+ +

In today’s post, we talked about the problem of test trustworthiness, then proceeded to review some techniques and guidelines you can use to overcome that challenge. Finally, we saw how mutation testing is the superior approach to solving that problem.

+ +

Here’s the thing: The techniques we covered are good guidelines to follow when writing unit tests. Your tests will benefit from abiding by them, whether you employ mutation testing or not. But guidelines can only take you so far. They depend too much on human willpower and discipline, and we all have limited amounts of those. In order to take the quality of your tests to the next level, you need to embrace automation.

+ +

It takes just a few minutes of googling to find a mutation testing tool for your preferred tech stack. Do that today, and stop missing out on the benefits that mutation testing can provide you and your team!

+ + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/null-is-evil.html b/en/null-is-evil.html new file mode 100644 index 00000000..ee660526 --- /dev/null +++ b/en/null-is-evil.html @@ -0,0 +1,577 @@ + + + + + + + + Null Is Evil. What's The Best Alternative? Null. | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Null Is Evil. What's The Best Alternative? Null.

+ +
+ +
+

+Photo by Ben Hershey on Unsplash

+ +

Editorial note: I originally wrote this post for the NDepend blog. You can check out the original here, at their site.

+ +

“Null is evil.” If you’ve been a software developer for any reasonable length of time, I bet you’ve come across that statement several times.

+ +

I’d say it’s also very likely that you agree with the sentiment, i.e., that the null reference is a feature our programming languages would be better off without. Even its creator has expressed regret over the null reference, famously calling it his “billion-dollar mistake.”

+ +

Bashing poor old null tends to get old, so authors don’t do just that. They also offer alternatives. And while I do believe that many of the presented alternatives have their merits, I also think we may have overlooked the best solution for the whole thing.

+ +

In this post, we’re going to examine some of the common alternatives for returning null before making the argument that the best alternative is null itself. Let’s get started!

+ +

Null Is Toxic…

+ +

I won’t dwell too much on the whole “null is evil” thing, since a lot has been written about it already. Some examples:

+ +

Null Is Evil +Null has no type, but Maybe has

+ +

This Stack Overflow answer also has some valuable information.

+ +

…But Useful. What Are the Alternatives?

+ +

Now, I hope we’re on the same page regarding null’s status as a problematic language feature. But toxic or not, null serves some purposes. People use it to represent an absent, invalid, or unknown piece of data, or even to indicate that an error has occurred.

+ +

What should they be doing instead?

+ +

Throw an Exception

+ +

In some situations in which people return null, the reasonable thing to do is to throw an exception. Think of it this way: if a method promises to perform something and fails to do so, it should throw. In other words: when a method fails to fulfill its contract, then it is reasonable to throw.

+ +

Of course, you should reserve exceptions for scenarios that are truly exceptional. If a certain situation happens often, then an exception is not the best solution.

+ +

Null Object Pattern

+ +

Consider the following lines of code:

+ +
var contract = repository.Find(42);
+contract.Extend(12);
+ +

What should happen if there isn’t a contract with ID equals to 42? If the “Find” method returns null, then you’re in for a nasty NullReferenceException. As I’ve said earlier, null makes your code lie. If we were to be really pedantic about it, the method “Find” should be renamed to “FindOrReturnNull”. Too verbose, but more honest.

+ +

Anyway, the null object pattern is an attempt to solve this problem. And how does it do that? By creating its own kind of null.

+ +

To implement the pattern, we create a new class ** ** (let’s call it “NullContract”) that represents the case when a contract is missing. We make this new class fulfill the same contract as the original class, but we do nothing in the methods. So, if we imagine that “Contract” implements “IContract”, our NullContract class could look something like this:

+ +
public class NullContract : IContract
+{
+	// ctor, properties, etc 
+	
+	public void Extend(int months)
+	{
+		// deliberately does nothing
+	}
+}
+ +

By employing the null object pattern you could—theoretically, at least—be sure that you’ll always get an object that fulfills the contract you expect it to honor without blowing up in your face.

+ +

Maybe/Option

+ +

Finally, we have a very interesting alternative that is often found in functional programming languages. This alternative is the use of a dedicated type meant to represent the use case of a potentially absent value. For instance, in F# this is called the option type; Haskell calls it Maybe. Starting in version 8, Java introduced the Optional class.

+ +

At this time, C# doesn’t offer something along those lines natively.

+ +

Alternatives to Null: Are They Any Good?

+ +

Having presented the more commonly used alternatives for null, it’s time for the final verdict. Let’s start with the “throw exception” option.

+ +

Exceptions

+ +

If the caller fails to supply the correct arguments for the function they’re calling, then we could say they’re breaking the function’s contract. Throwing an exception is the correct thing do to in this situation.

+ +

The following code is a good example of what not to do:

+ +
public Foo Bar(int a, string b)
+{
+    if (a > 0 && a <= 100)
+    {
+        if (!string.IsNullOrWhiteSpace(b))
+        {
+            // all is fine with the world; let's do what must be done and return some Foo!
+            return new Foo();
+        }
+    }
+ 
+    // uh-oh! Something wrong with the input parameters. Let's return null. Sounds like a good idea!
+    return null;
+}
+ +

I see code like this all the time in production. Nested ifs are awful. They should have at least used an “and” to fit the whole thing in just one if. But what should really happen is something like this:

+ +
public Foo Bar(int a, string b)
+{
+    if (a <= 0 || a > 100)
+    {
+        throw new ArgumentOutOfRangeException(
+        nameof(a),
+        "The value should be in the range of 1 to 100, inclusive");
+    }
+ 
+    if (string.IsNullOrWhiteSpace(b))
+    {
+        throw new ArgumentException(
+             "The value should be a valid string.",
+             nameof(b)
+             );
+    }
+ 
+    // all is fine with the world; let's do what must be done and return some Foo!
+    return new Foo();
+}
+ +

Also, don’t catch exogenous exceptions that might happen inside your method and return null; instead, just let them bubble up since these type of exceptions represent problems outside of your control. Issues like a failure in the network are problems that you couldn’t have prevented anyway, code-wise.

+ +

Null Object Pattern

+ +

Let’s consider the null object pattern, which I’m certainly not a huge fan of. One problem with this pattern is that you should only use it when the calling code doesn’t care about the outcome of whatever it’s trying to accomplish. Consider again our contract example:

+ +
var contract = repository.Find(42);contract.Extend(12);
+ +

This line of code is not “aware” (nor does it care) if the “Contract” variable refers to a valid contract or an instance of NullContract. If it’s a valid contract, it will be extended by 12 months. If it’s not, then nothing will happen. Sometimes, that’s exactly what you want, but not always. In this example, if a contract with ID equals to 42 really was supposed to exist but did not…maybe throwing an exception would work best.

+ +

All I’ve said so far is that the null object pattern isn’t well suited for every scenario. This isn’t that bad of a problem; you could say the same about pretty much anything.

+ +

My main issue with the null object pattern is that it amounts to little more than creating a new type of null without really solving the problem. You see, using the pattern doesn’t prevent you from returning null. If I consume some method written by a third party that claims to use the pattern, I should be able to assume that whatever it returns is safe for me to deference. But I can’t know for sure. I have three options:

+ +
    +
  • Trust the author of the code;
  • +
  • Inspect the source code, if possible; or
  • +
  • Continue to check for null, which completely defeats the purpose of using the pattern.
  • +
+ +

You could argue that these problems aren’t relevant in the context of a single team working with the same codebase. The developers could agree on using the pattern correctly. But if everything amounts to trust and convention at the end of the day, you might as well just agree to never return null and you’d have the same result.

+ +

Maybe/Option

+ +

Last but not least, what about Maybe/Option types? This is an alternative that’s both elegant and robust, especially in languages such as F# where you’re actually forced, in a sense, to handle both cases by using pattern matching.

+ +

But the sad reality is this: while maybe/option types are amazing approaches, they can’t change the fact that null exists and will continue existing. You can’t really stop people from using it, nor can you remove it from all the lines of code people have been writing since the dawn of C#.

+ +

So, even though they are great approaches, they still suffer from the problem of being yet another type of null for the developers to deal with.

+ +

The Solution for Null: Null Itself

+ +

Do you know the old saying “When in a hole, stop digging?” For better or worse, null exists. Toxic or not, it’s a feature people use. So maybe the solution for this whole thing is just to fix null.

+ +

The kotlin language got it right by having different nullable and non-nullable types and adding all kinds of checks to prevent the developer from doing things that would end badly, like dereferencing a nullable type without checking it for null or assigning a nullable value to a non-nullable variable.

+ +

C# gave us the first step in the right direction many years ago with nullable value types. After a long wait, reference types will finally get the same benefit with C# 8.0.

+ +

The alternative for null is null itself… when done properly.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/reduce-cyclomatic-complexity/index.html b/en/reduce-cyclomatic-complexity/index.html new file mode 100644 index 00000000..e51af68c --- /dev/null +++ b/en/reduce-cyclomatic-complexity/index.html @@ -0,0 +1,558 @@ + + + + + + + + How To Reduce Cyclomatic Complexity: A Complete Guide | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

How To Reduce Cyclomatic Complexity: A Complete Guide

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the LinearB blog. You can check out the original here, at their site. While you’re there, take a look at their product, a software intelligence solution that uses Git and project statistics to help dev teams improve their productivity.

+ +

Software engineers worth their salt are always searching for ways to improve their code. Fortunately for them, there’s a reliable way to evaluate the health of a codebase and project, and that’s through the use of metrics. Today’s post is all about a specific metric. You’ll learn how to reduce cyclomatic complexity and, more importantly, why you would want to do it.

+ +

We’ll start by defining cyclomatic complexity. After that, you’ll learn what the problem with having a high cyclomatic complexity value is and why you would need to reduce it. After the “what” and “why,” we’ll finally get to the “how”: We’ll show you tactics you can adopt to reduce the cyclomatic complexity of your code. Let’s get to it.

+ +

Cyclomatic Complexity: A Brief Definition

+ +

Cyclomatic complexity is an important software metric. It refers to the number of possible execution paths inside a given piece of code—for instance, a function. The more decision structures you use, the more possible branches there are for your code.

+ +

Cyclomatic complexity is especially important when it comes to testing. By calculating the cyclomatic complexity of a function, for instance, you know the minimum number of test cases you’ll need to achieve full branch coverage of that function. So, we can say that cyclomatic complexity can be a predictor of how hard it is to test a given piece of code.

+ +

A Dead Simple Cyclomatic Complexity Example

+ +

Consider the following function written in pseudocode:

+ +
void sayHello(name) {
+    print("Hello, ${name}!");
+}
+ +

Since it has a single statement, it’s easy to see its cyclomatic complexity is 1. Now, let’s change things a little bit:

+ +
void sayHello(name, sayGoodbye = false) {
+    print("Hello, ${name}!");
+    if (sayGoodbye) {
+        print("Goodbye, ${name}!");
+    }
+}
+ +

The second version of the function has a branch in it. The caller to the function might pass true as the value for the sayGoodbye parameter, even though the default value is false. If that does happen, the function will print a goodbye message after saying hello. On the other hand, if the caller doesn’t supply a value for the parameter or chooses false, the goodbye message won’t be displayed.

+ +

So, the function has two possible execution branches, which is the same as saying that its cyclomatic complexity has a value of 2.

+ +

Why Is Cyclomatic Complexity Bad?

+ +

Cyclomatic complexity isn’t intrinsically bad. For instance, you can have a piece of code with a somewhat high cyclomatic complex value that’s super easy to read and understand. However, generally speaking, we can say that having a high cyclomatic complexity is either a symptom of problems with the codebase or a potential cause of future problems. Let’s cover some of the reasons why you’d want to reduce it in more detail.

+ +

Cyclomatic Complexity Might Contribute to Cognitive Complexity

+ +

Cognitive complexity refers to how difficult it is to understand a given piece of code. Though that’s not always the case, cyclomatic complexity can be one of the factors driving up cognitive complexity. The higher the cognitive complexity of a piece of code, the harder it is to navigate and maintain.

+ +

Cyclomatic Complexity Makes Code Harder to Test

+ +

As we’ve already mentioned, higher values of cyclomatic complexity result in the need for a higher number of test cases to comprehensively test a block of code—e.g., a function. So, if you want to make your life easier when writing tests, you probably want to reduce the cyclomatic complexity of your code.

+ +

Cyclomatic Complexity Contributes to Higher Risk of Defects

+ +

You’re likelier to introduce defects to an area of the codebase that you change a lot than to one you rarely touch. In addition, the more complex a given piece of code is, the more likely you are to misunderstand it and introduce a defect to it.

+ +

So, complex code that suffers a lot of churn—frequent changes by the team—represents more risk of defects. By reducing the cyclomatic complexity—and, ideally, the code churn as well—you’ll be mitigating those risks.

+ +

How to Reduce Cyclomatic Complexity: 6 Practical Ways

+ +

We’ll now go over a few practical tips you can use to ensure the cyclomatic complexity of your code is as low as possible.

+ +

1.Prefer Smaller Functions

+ +

What to Do?

+ +

All else being equal, smaller functions are easier to read and understand. They’re also less likely to contain bugs by virtue of their length. If you don’t have a lot of code, you don’t have lots of opportunities for buggy code. The same reasoning applies for cyclomatic complexity: You’re less likely to have complex code if you have less code period. So, the advice here is to prefer smaller functions.

+ +

How to Do It?

+ +

For each function, identify their core responsibility. Extract what’s left to their own functions and modules. Doing that also makes it easier to reuse code, which is a point we’ll revisit soon.

+ +

2.Avoid Flag Arguments in Functions

+ +

What to Do?

+ +

Flag arguments are boolean parameters you add to a function. People usually use them when they need to change how a function works while at the same time preserving the old behavior.

+ +

How to Do It?

+ +

What to use instead of flag parameters? In a nutshell, you can use strategies that accomplish the same result without incurring high complexity. For instance, you could create a new function, maintaining the old one as it is and extracting the common parts into its own private function.

+ +

If the flag parameter is being used to enhance or improve the behavior of the original function somehow, you might want to leverage the decorator pattern to reach the same end.

+ +

3.Reduce the Number of Decision Structures

+ +

What to Do?

+ +

You might consider this one a no-brainer. If the decision structures—especially if-else and switch case—are what cause more branches in the code, it stands to reason that you should reduce them if you want to keep cyclomatic complexity at bay.

+ +

How to Do It?

+ +

Some of the tactics we’ve just seen can contribute to reducing the number of if statements in your code. For instance, instead of using flag arguments and then using an if statement to check, you can use the decorator pattern. Instead of using a switch case to go over many possibilities and decide which one the code will execute, you can leverage the strategy pattern. Sure, at some point in the code, you’ll still need a switch case. After all, someone has to decide which actual implementation to use. However, that point becomes the only point in the code that needs that decision structure.

+ +

4.Get Rid of Duplicated Code

+ +

What to Do?

+ +

Sometimes, you have functions/methods that do almost the same thing. Keeping both increases the total cyclomatic complexity of your class or module. If you can limit your duplicates, you can limit complexity.

+ +

How to Do It?

+ +

Remove duplicated code by:

+ +
    +
  • extracting the common bits of code to their own dedicated methods/functions.
  • +
  • leveraging design patterns—such as template pattern—that encourage code reuse.
  • +
  • extracting generic utility functions into packages—gems, npm modules, NuGet packages, etc.—that can be reused through the whole organization.
  • +
+ +

5.Remove Obsolete Code

+ +

What to Do?

+ +

There are many reasons why it’s a good idea to remove obsolete—i.e., dead—code from your application. For our context, it suffices to say that that’s a “free” way to bring code coverage up and cyclomatic complexity down.

+ +

How to Do It?

+ +

Just use a tool that lets you identify dead code—even your IDE might be able to do it—and then delete it mercilessly.

+ +

6.Don’t Reinvent the Wheel

+ +

What to Do?

+ +

Let the developer who never wrote a function—or even a couple of them—to perform date formatting cast the first stone! It’s almost like a rite of passage.

+ +

Writing code that simply duplicates functionality that your language’s standard library or your framework already provides is a sure way to increase complexity unnecessarily. If code is a liability, you want to write only the strictly necessary amount of it.

+ +

How to Do It?

+ +

Implement a sound code review strategy that’s able to identify and get rid of such wheel reinventions.

+ +

Reduce Cyclomatic Complexity, Increase Code Clarity

+ +

Cyclomatic complexity is one of the most valuable metrics in software engineering. It has important implications for code quality and maintainability, not to mention testing. High cyclomatic complexity might be both a signal of existing problems and a predictor of future ones. So, keeping the value of this metric under control is certainly something you want to do if you want to achieve a healthy codebase. Keeping it under control is exactly what you’ve learned with our post.

+ +

Before parting ways, a final caveat. Keep in mind that no metric is a panacea when used in isolation. Often, what you’d really want to do is to track and improve a group of metrics that, together, can give you the big picture view of the health of your team and project. Thanks for reading.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/share-what-you-learn/index.html b/en/share-what-you-learn/index.html new file mode 100644 index 00000000..426b6566 --- /dev/null +++ b/en/share-what-you-learn/index.html @@ -0,0 +1,465 @@ + + + + + + + + Share what you learn | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Share what you learn

+ +
+ +
+

+Share what you learn. Write a blog post. Answer a question on Stack Overflow. Open-source your code. Create content! In our industry, this advice shows up very often, in all colours and shapes. And rightly so, I’d say. How many hours have you saved thanks to someone else’s post on their blog? Or to a well-crafted answer on Stack Overflow?

+ +

How many times an open-source tool/library/whatever spared you from having to code it’s functionality from scratch? If I had to guess the answer to these questions, I’d say: a lot. +

+ +

Brazilian developer Rafael Rosa Fu talks about some of the benefits of content creation on this post, originally written in Portuguese:

+ +
+
    +
  • Learning - in order to fix new skills you must practice them, when we write about what we learn we are reinforcing and expanding our knowledge by being “forced” to explain it in a way that other people can understand
  • +
  • Memory - I don’t know about you, but my memory is not that great, and I’m sure I’m no exception here. Write about that complex concept or write down the recipe to a sporadic procedure and when you need to remember it just open your blog, or even google it and you’re going to find your own words to remind you.
  • +
  • Portfolio - specially useful to those who are starting their careers, blog posts are useful as part of a knowledge portfolio that can be found by a prospective employer or used as reference during an interview, acting as a complement to career time, besides being an excellent starting point to a conversation. […]
  • +
+
+ +

Jeff Atwood (co-founder of Stack Overflow and Discourse) even said that starting his blog “was the the most important thing I’ve ever done in my entire career.” So, it seems reasonable that we if encourage more and more people to share their knowledge and experiences, the whole community wins, right?

+ +

In this 2012 Smashing Magazine post, Louis Lazaris gives advice on how to start publishing: just publish what you learn, don’t be afraid of making mistakes, welcome your reader’s collaborations.

+ +

It sounds easy, doesn’t it?

+ +

When Doubt Arrives

+ +

I had a lot of self-doubt before starting this blog. I mean, how could it be any different? All those established bloggers, they have years or even decades of experience. They give talks in several countries. They are published authors, they host podcasts, they created successful companies, or maybe a piece of technology used by millions.\r\n\r\nIn short, they have a very impressive “About Me” page. Heck, some of them may even have an wikipedia article about themselves! They’re the rockstars.

+ +

What about me? I’m just a dude, a couple years out of college, trying to learn and make my career. Do I really have something valuable to offer? Will I be able to really help somebody? Or I’ll be just adding to the noise?

+ +

I think these are all important questions. The web is a ridiculously big place. You could share content for years, or maybe even your whole life, without being noticed and without receiving any feedback.

+ +

Every now and then when I google something, I land on some blog with a cool design and very well written posts. I start to browse the posts, and I notice that most of them (sometimes, all of them) have no comments. Sometimes, I also notice that the last post is from 2 or 3 years ago. They gave up.

+ +

While this is sad and quite disencouraging, it’s just a fact of life. Maybe your blog will reach a large audience, maybe it will not.

+ +

Why I created this blog, after all?

+ +

Maybe the previous section has given you the impression that I am skeptical about the benefits of creating content. And maybe I am, just a little bit. But I’m not going to let that stop me. I believe in the importance of giving back to the community.

+ +

Remember that stackoverflow answer that saved your job? Well, guess what: somebody took the time to write that answer, for free, and posted it online, for free, for the whole internet to see, forever. Isn’t that amazing? I think part of the beauty of our profession is that there are so many people willing to share knowledge for free. To sacrifice their own free time in order to build something. Miracles like GitHub, StackOverflow, Wikipedia, are only possible thanks to those people. And I want to be a part of that.

+ +

Sure, you could argue that these people are moved by their own selfish reasons. Yeah, they probably are, but the point is: at the end of the day, it doesn’t really matter. Results matter. If the user JaneDoe123 wrote that answer on StackOverflow just to earn a few points of reputation, that’s fine by me! I just want to have my problem solved.

+ +

So, that’s it. To use a torrent metaphor, I’m tired of being only a leecher. It’s time to seed a little bit.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/sharpen-the-saw/index.html b/en/sharpen-the-saw/index.html new file mode 100644 index 00000000..b716a35b --- /dev/null +++ b/en/sharpen-the-saw/index.html @@ -0,0 +1,534 @@ + + + + + + + + Sharpen the Saw: 4 Quick Tips for Your Dev Team | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Sharpen the Saw: 4 Quick Tips for Your Dev Team

+ +
+ +
+

+Photo by Sven Brandsma on Unsplash

+ +

Editorial note: I originally wrote this post for the SubMain blog. You can check out the original here, at their site. While you’re there, have a look at CodeIt.Right, their automated code review tool.

+ +

Are you familiar with the expression “sharpen the saw” in the context of learning and continuous improvement? If you’ve read Stephen Covey’s The 7 Habits of Highly Effective People, then I’m sure you are. For those unfamiliar with the term, it basically means to engage in practices that will make you better at your craft without necessarily involving the craft itself.

+ +

What can you as a tech lead, lead developer, or software architect do to encourage the developers on your team to sharpen their saws? That’s what we’ll to answer with this post. We’ll show you four quick, easy ways your team can improve their skills and deliver more value.

+ +

1. Sharpening the Saw by Reading: Create a Technical Book Club

+ +

Wouldn’t it be awesome to have a team made up of incredibly well-informed people, who are up to date with the relevant, shiny new things and have solid knowledge on the fundamentals of our industry? Yeah, I thought so. And there’s no better way of achieving that than by reading.

+ +

What I suggest here is something very simple. Every month, you and your team choose an assigned read for the dev team. On which subject, you ask? Design patterns, concurrency, refactoring, unit testing—I’d say virtually anything is fair game, as long as the developers themselves are interested.

+ +

Oh, and before I forget: this probably goes without mentioning, but your company should buy the developers copies of the chosen books. If you feel you can’t afford that, well, I don’t believe you’re going to have a company for very long, I’m afraid.

+ +

A less ideal solution would be to buy a copy of the book for one developer. Have them study the book in their spare time and then present their findings to the rest of the team by giving one or more internal talks. Then, select another book and another team member, and have that developer give the internal talk next month.

+ +

Now, speaking of internal talks…

+ +

2. Sharpening the Saw by Talking: Internal Presentations

+ +

Having the developers deliver internal talks to each other is a great way to spread knowledge throughout the company. For the developers giving the talk, it’s the perfect opportunity to get some hands-on practice with several skills, such as

+ +
    +
  • Coming up with a subject and doing the necessary research.
  • +
  • Creating an appealing slide deck.
  • +
  • Speaking in public, which can be a tough experience for many of us.
  • +
  • Answering questions.
  • +
+ +

I could go on and on, but in short, they’ll be practicing the general skill of communication. That’s simply priceless. Giving internal talks can be great practice for speaking at conferences, for example.

+ +

And what’s on the table for the audience? Obviously, the learning opportunity. But I’ll add that, in the case of internal company talks, the probability of actually putting that knowledge you gained into use is much higher. Since the speakers are actually your coworkers—people who share context with you every day and are aware of the problems and challenges your company is facing—I’d say it’s very likely that they pick a topic that relates to the company.

+ +

3. Sharpening the Saw by Writing: Create and Maintain an Engineering Blog

+ +

When your developers give internal talks, they’re teaching one another, which is fantastic. But what if they could spread this knowledge beyond just your shop, while at the same time improving their writing skills and ability to articulate an argument? What if they could do so while learning about things like content marketing and SEO? And while they’re at it, what if they could demonstrate the technical know-how of your company, positioning it as an expert on its domain area?

+ +

There’s a way to do just that, and it’s called blogging.

+ +

Start an engineering blog. Decide on the specifics, such as:

+ +
    +
  • What topics should be covered?
  • +
  • How frequently will you publish?
  • +
  • Who will the authors be?
  • +
+ +

It would make sense if, at least at the beginning, the developers who are naturally better writers were the blog’s authors. But since the goal here is to learn—to sharpen the saw—the ideal scenario is one in which every developer gets a chance to hone their writing chops.

+ +

4. Sharpening the Saw by Programming: Hold In-Company Coding Dojos

+ +

A coding dojois a kind of training session for programmers in which they rotate in pairs, working in a collaborative manner on the same problem. The inspiration for the name comes from the martial arts. The goal of a coding dojo isn’t necessarily to solve the problem?but to develop both engineering skills, such as unit testing/TDD, and social skills, such as pair programming.

+ +

To hold a coding dojo, you’re going to need the following:

+ +
    +
  • Space. You need a?room large enough to hold from five to 15 people. (Some people say 20 people for a coding dojo is acceptable, but IMHO, this is way too much). Since we’re talking about sharpening your team’s saws, an office or meeting room at your company will probably do.
  • +
  • A computer. It could be a desktop computer or laptop; it doesn’t matter, as long as it’s placed on a desk with two chairs, where two people can sit and collaborate comfortably together.
  • +
  • A projector or a large monitor. All of the participants need to watch what’s going on at any given moment.
  • +
  • Snacks and beverages! A coding dojo should be a bonding experience, and human beings love to connect over food and drink. And programmers are human beings, last time I checked. Just be considerate of those with dietary restrictions, and you should be good.
  • +
+ +

So, let’s say you’re actually doing this thing. You’ve assembled the needed gear, and people have shown up at the agreed-upon location. What now?

+ +

Well, first things first. You need a problem! But not all programming challenges make a good coding dojo problem. As I said earlier, solving the problem isn’t necessarily the goal—rather, it’s more about practicing engineering skills such as TDD and pair programming. So, writing a compiler from scratch isn’t going to cut it. But implementing a converter to roman numerals might work quite well.

+ +

What makes for a good coding dojo problem?

+ +
    +
  • It’s small, so it’s feasible to solve it in a relatively short time.
  • +
  • It lends itself well to TDD.
  • +
  • It’s finite and well-defined. Vague, open-ended challenges won’t do.
  • +
  • It’s based on a real-world problem, not an abstract one.
  • +
  • It’s different from the challenges you solve at your day job.
  • +
+ +

You don’t really need to worry about finding good problems, though. The web’s got your back.?There are plenty of sources for problems out there.

+ +

With choosing the problem out of the way, it’s time to pick a language to work on. You don’t need to use the same language you use every day at your job. In fact, it’s nice to use the coding dojo as an opportunity to try out different languages. This can help make things fresh and more challenging. Just don’t forget to have a person who’s knowledgeable about this language around so they can help when the group hits obstacles.

+ +

Now,?to start, you’ll need two volunteers: one to be the driver and one to be the co-pilot. These terms come from pair programming. The driver is the person who’s typing, and the co-pilot gives advice and feedback. The remaining people are the audience, at least for now. Ideally, everyone in a coding dojo session should write code.

+ +

So, with everyone in their places, the fun begins. The driver starts coding, using TDD’s red-green-refactor cycle:

+ +
    +
  • First, they write a failing test.
  • +
  • Then, they write just the smallest possible amount of code that will make the test pass.
  • +
  • When the test is passing, it’s time to refactor. Only in this phase?are people in the audience are allowed to speak, giving advice and feedback to help the driver better refactor the code.
  • +
+ +

At the end of a?previously-established time period (five to ten?minutes), the driver stops coding and returns to the audience. The copilot becomes the driver, and a new member of the audience becomes the copilot.

+ +

This cycle continues until everyone in the room had written code or the allotted time for the session expires—whatever comes first.

+ +

Retrospective

+ +

As soon as the coding session itself is done, take some time to do a retrospective. Ask the participants about the things they liked and didn’t like about the session, and write it all down. These two lists will serve as a guideline for what to do and not to do in your future coding dojos.

+ +

Start Sharpening Your Saw—and Your Team’s Saw—Right Away!

+ +

Software development is a profession of practice. It requires continuous learning—or should I say, continuous saw-sharpening. Beyond the tips I’ve just given you, there are plenty of other ways to sharpen your saw. In fact, you’re doing one of them right now. You’re reading a tech blog!

+ +

From in-depth tutorials on tools like CodeIt.Right that can help your team write better code?to insights about best practices?to even tips about things you might have taken for granted, there’s no shortage of interesting and useful topics you can learn about by reading a good tech blog.

+ +

Thanks for reading, and happy sharpening!

+ + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/types-of-comments-to-avoid/index.html b/en/types-of-comments-to-avoid/index.html new file mode 100644 index 00000000..2729600d --- /dev/null +++ b/en/types-of-comments-to-avoid/index.html @@ -0,0 +1,539 @@ + + + + + + + + Learn which types of comments should be avoided | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Learn which types of comments should be avoided

+ +
+ +
+

+ +

Spoiler Alert: You should avoid most of them. +

+ +

“To comment or not to comment”. This is a question that tends to spark heated debate. Some people say that comments are an indispensable tool. Others argue that the comments show the developer’s inability to express himself clearly in the code. Who’s right?

+ +

When I was in college, I considered the comments indispensable when writing code. Otherwise, how could you understand what the code should do?

+ +

After getting my degree and finding a job, things started to change. I was being exposed to real code; I was reading books, articles and blog posts written by influential people in our industry.

+ +

These experiences shaped my current vision.

+ +

The dangers of bad documentation

+ +

Comments are just another form of documentation. And make no mistake: documentation is a good thing - when done correctly and in the right amount.

+ +

Unfortunately, it is so often done wrong!

+ +

Many types of documentation can be problematic. It is very common for the documentation to lose synchronization with what it is documenting, which is worse than not having any documentation in the first place.

+ +

This is one of the problems that comments suffer from, but it is far from being the only one.

+ +

Commented-out Code

+ +

Let’s start with the most obvious one, which is commented-out code. Some developers, when fixing a bug, for example, choose to comment the offending code out, rather than delete it.

+ +

Don’t do this!

+ +

Commented-out code does no good to anyone. It’s just waste. Rely on your version control system. It will remember the changes you made if you needed to revert them in the future.

+ +

‘Changelog’ Comments

+ +

This category of bad comments is similar to the previous category, which is caused by a lack of trust in your version control system.

+ +

What do I mean by “Changelog” comments? Comments that just list the changes made to a file:

+ + + +

Comments like this are just doing the same work as your VCS already does, but in a clumsy and error-prone way.

+ +

Do not write these types of comments. Use git and be happy.

+ +

Redundant Comments

+ +

This type of bad comment is very easy to detect and very easy to fix. Consider the following code:

+ + + +

I think we can all agree that these comments are useless. The code is perfectly clear without them, therefore, they should be removed.

+ +

Comments at the end of blocks

+ +

You’ve probably seen code like this before:

+ + + +

Some people write them so they do not lose control of the brackets.

+ +

If you need a comment for this reason, that indicates that your method is too long and you have too many levels of indentation.

+ +

Remember the Principle of Single Responsibility: each method should do only one thing. Divide your method into small ones and the need for such comments disappears.

+ +

Comments that delimit sections inside methods

+ +

This one is similar to the previous one. If you have several sections inside a method, each one of them with an explaining comment on top, then you’re probably violating the Single Responsibility Principle.

+ +

Remove each section to its own method, use the comment text as the name for the new method, and then delete the comments.

+ +

Out of date comments

+ +

Here’s a common scenario:

+ +
    +
  • Bob writes some lines of code. He thinks the code isn’t clear enough and adds some comments to express its intent.
  • +
  • Fast forward some weeks. It turns out that the code Bob wrote had a bug. He is on vacation, though, so Alice is made responsible for fixing the bug.
  • +
  • Alice fixes the code in a few minutes and checks in her changes. But she forgets to update the comments to reflect the changes she’s made in the code.
  • +
+ +

Now what you get? Comments that lie!

+ +

Documentation that spread lies is worse than no documentation at all. It’s a source of confusion for developers, and a fertile ground for bugs. When you spot an out-of-date comment, don’t think twice: delete it right away, or rewrite it to be accurate. But most of the time you shouldn’t keep the comment. See next topic for why.

+ +

Comments created due to lack of expressiveness in the code

+ +

Consider the following code:

+ + + +

Maybe you don’t consider the comment in the sample above to be bad. It is not that terrible, sure. But think of the missed opportunity to extract a useful method or property:

+ + + +

In the new code, we’ve extracted the concept of being eligible for blood donation in a new property. The rules for blood donation eligibility are now consolidated in a single place; should they ever change, the amount of work required to update them will be minimal.

+ +

And we get the nice collateral benefit of readability: the new if statement reads almost like natural language.

+ +

Conclusion

+ +

As we’ve seen, there are several types of bad comments you should be weary of. They are often signs that there may be something wrong with your code. Maybe your methods are too long. Maybe you didn’t pick good names for your variables.

+ +

Every time you feel the need to write a comment, stop and try to think about ways in which you could improve your code to render the comment unnecessary.

+ +

Not all comments are bad, though. In a future post, I’ll write about situations in which comments can be valuable.

+ +

See you later!

+ +

Read More

+ + + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/unit-testing-for-beginners-part1/index.html b/en/unit-testing-for-beginners-part1/index.html new file mode 100644 index 00000000..40d1dc97 --- /dev/null +++ b/en/unit-testing-for-beginners-part1/index.html @@ -0,0 +1,556 @@ + + + + + + + + Unit testing for beginners - Part 1 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Unit testing for beginners - Part 1

+ +
+ +
+

+ +

Maybe, some time in your career, you might have worked on an incredibly complex application, with an enormous, poorly-documented code base, full of hacks, unnecessary couplings, with a confused architecture and no specifications at all. That kind of app you’d call a miracle if it even works. Maybe I’ve just described your current project! +

+ +

This post is part of a series. See all the articles in the series.

+ +

In this type of project, it’s very common for the developers to get afraid of touching the code, cause they know that if they do, something is going to break for sure. And worse: it’s going to break in production, most likely.

+ +

Now, imagine that your application is completely covered by an alarm system. Every time a feature stops working, the alarm goes off. The developers are immediately notified, and someone can take action and solve the problem as soon as possible.

+ +

Imagine yet that this alarm system consists of hundreds of smaller systems. Each subsystem must watch a very specific part of your application. In order for the main system to function properly, each subsystem must be totally independent from the others.

+ +

The adoption of such a system would bring several benefits. First of all, developers would lose the fear of touching the code. Code refactoring would become easier to do, and it would be done more often. As a consequence, the quality of the code would improve.

+ +

The development process itself would be simplified. The alarm system would dramatically reduce the need for slow manual tests, thus speeding the release to the users.

+ +

Finally, the need for independence between the subsystems would promote the reduction of coupling between modules of the application.

+ +

It sounds too good to be true? Well, it isn’t. This “alarm system” is exactly the benefit you get after adding a suite of unit tests to your application.

+ +

What are unit tests?

+ +

Let’s see what Wikipedia tells us:

+ +
+

In computer programming, unit testing is a software testing method by which individual units of source code, […] are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. […] + Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.

+
+ +

The first thing worth mentioning is that unit tests don’t have the goal of testing the system as a whole. On the contrary, they test small pieces of the application - the units. And what is a unit? There are several conflicting points of view on this, several “schools of thought”. But it’s safe to say that, in a context of Object Oriented Programming, most people would consider the class as being a unit.

+ +

Right after this, we see that unit tests are usually written and run by programmers. This is interesting for two reasons: first, it apparently goes against the idea that programmers don’t make good testers (I’m going back to this point later). And more importantly than that, it shows the principal feature of unit tests: they are automated.

+ +

Bear in mind that there are a lot of types of automated tests, but here we’re only talking about unit tests (which, according to several authors, such as Martin Fowler, are the ones who benefits the application the most).

+ +

In practice, unit tests are classes that contains methods who test small and isolated pieces of functionality. These classes are created with the aid of a test framework (such as JUnit in Java, NUnit or Microsoft Test in .Net). Then, the tests can be run via command line, by your IDE or even by an automated build service.

+ +

Example of test case in C#

+ +

After the tests are run, you get an immediate feedback about which tests failed and which ones succeeded, along with the run time of each one of them.

+ +

Windows displaying the result of a test run

+ +

With this feedback, you can decide on your best course of action. Ideally, a failing test should signal something wrong in the production code. The production code should then be fixed so the test can pass.

+ +

Benefits of unit tests

+ +

In the beginning of the post, while using the alarm system metaphor, I’ve talked about some of the benefits that unit tests can provide, for instance:

+ +
    +
  • they promote and facilitate code refactoring;
  • +
  • they promote architectural improvement of the system;
  • +
  • they can simplify and accelerate the release of the product to the final users;
  • +
+ +

Another benefit worth mention is that unit tests document the code. Think of it: for each production class in your system, there are several test cases, that exercise every possible use of this class. A good test suite could help a recent hire to quickly gain familiarity with the code base.

+ +

That is, the best type of documentation: the one that is alive, executable, always up-to-date, and never lies.

+ +

We must also mention that a good and comprehensive test suite helps to prevent bug regression. It’s a best practice to create a new test every time a new bug is found. That way, if the bug ever comes back due to a change, the test is going to show you.

+ +

Finally, one of the more important benefits that test automation can provide is cost reduction. Oddly enough, I don’t see this benefit being talked about too much - maybe because it’s more related to the business side of things. Let’s say that your team tests the whole application, every time your about to release. You use four testers, working full-time, during two weeks. Just do the math and you’ll see that manual tests are freaking expensive!

+ +

Worse yet: they are expensive twice. First, there’s the cost itself, that you can calculate with the formula hourly rate of tester x number of testers x hours spent in testing. Pretty straightforward, no surprises here.

+ +

But, besides that, there is also an opportunity cost: if professionals are spending time doing manual tests that could be automated, then they are NOT doing other tasks that could have a greater ROI to the company.

+ +

Common misconceptions

+ +

In this section, I’m going to try to clarify some of the myths and misconceptions that some people have about unit testing.

+ +

Programmers shouldn’t write tests, because they are bad testers

+ +

There is a widespread notion that programmers shouldn’t test their own code. The rationale for this is that the developers would unconsciously avoid to use the app in a way that would break it. And from experience I can say that this indeed happens. I’ve lost count of how many times a coworker found bugs in an app I made after literally seconds of using it, in spite of the fact that I had already tested it a lot without making it fail.

+ +

The important point here is: there are tests and tests. Often, when people say that developers shouldn’t test, they’re talking about system tests, also called end-to-end tests. Such tests mean to test the system as a whole, which is not the goal of unit tests, as I said before.

+ +

Maybe, it’s just lack of information: the person probably doesn’t know the nature and purpose of unit tests, and mistake them for end-to-end tests.

+ +

Writing unit tests is a waste of time; it’s like coding the same thing twice

+ +

When you try to convince management that unit tests are worth it, it would be wise to focus on cost reduction. But, what about the developers? How to convince them to spend time writing test code, when they’re already in tight deadlines and under a lot of pressure?

+ +

So, don’t be so surprised if you try to sell unit testing to your fellow developers, and they just say to you: “Wast of time. We’re not going to do that”.

+ +

What these people don’t grasp is that they’re already testing their own code all the time, even if they don’t call it that way. Not convinced? Well, I bet your development work-flow looks something like this:

+ +
    +
  • Write a bit of code
  • +
  • Compile
  • +
  • Run the app, test the new feature +
      +
    • If it works, start to code next functionality;
    • +
    • If if doesn’t, debug until you find what’s wrong, then fix it.
    • +
    +
  • +
  • Repeat
  • +
+ +

What we propose is just to swap the “write production code -> compile -> test manually -> debug -> repeat” cycle for the “write production code -> write test code -> run tests -> fix production code if necessary”.

+ +

You could argue that the cycles are the same - they kind of are. But the big advantage of unit tests is that, once written, they are easily repeatable until the end of the project’s life. You “waste time” only once. Or better, you invest time and effort in the beginning, in order to create the tests, and seize the benefits for indefinite time.

+ +

Unit tests replace all manual tests

+ +

Unit tests are not the only types of tests that can be beneficial to a project. We can also use several other types of automated tests such as integration tests and acceptance tests.

+ +

Testing pyramid, showing the ideal ratio of different types of software testing

+ +

That doesn’t mean that manual testing should be extinct. On the contrary, manual tests still have an important role in quality assurance processes. Ideally, manual tests should focus on the areas that can’t be automated, like usability testing.

+ +

In regards to agile methodologies, it is key that the Product Owner/Client/Business Person approves and accepts the user stories before they are included in a release.

+ +

Exploratory manual tests, that doesn’t follow a script, can be useful to detect certain kinds of bugs. Most automated test cases tend to focus on the “Happy Path”, that is, the scenario in which everything went right. +In real life, is very common for the users to use the application in…hm…“creative” ways. So, when you put the system under stress, using it in ways that the developers never intended, nasty bugs that would otherwise keep hidden, can show up.

+ +

Of course, once the bug is found, you should immediately write a test that exposes it. That way, if the bug ever comes back, it’ll be easily detected.

+ +

Conclusion

+ +

Unit testing - and automated software testing, in general - is a huge subject. There are a lot of books about it, there are master’s theses about it. So, of course I can’t do justice to this subject with a mere blog post.

+ +

But I sincerely hope that I had made a proper introduction to unit tests and clarified some of the questions that beginners usually have. If you have a question, suggestion or criticism, the comment are is all yours.

+ +

This post is the first one in a series dedicated to unit testing. +Next post: time to get your hands dirty! I’m going to show how to create your first unit test!

+ +

See you there!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/unit-testing-for-beginners-part2/index.html b/en/unit-testing-for-beginners-part2/index.html new file mode 100644 index 00000000..1d03a05d --- /dev/null +++ b/en/unit-testing-for-beginners-part2/index.html @@ -0,0 +1,696 @@ + + + + + + + + Unit testing for beginners - Part 2 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Unit testing for beginners - Part 2

+ +
+ +
+

+ +

Better late than later! Time to continue our series on unit testing for beginners. Today you’re going to write your first unit test. +

+ +

Introduction

+ +

This post is part of a series. See all the articles in the series.

+ +

In the previous article you learned what unit tests are and what are the motivations for writing them.

+ +

Today you’re going to learn how to create unit tests. I’ll show you how to install and use the a unit test framework called NUnit. Together, we’re going to write some tests in order for you to know some of its features.

+ +

NUnit Installation

+ +

If you recall my previous article, you’ll remember that, in order to write and run unit tests, you need a unit testing framework.

+ +

The framework we’re going to use is NUnit, based on JUnit, which is a test framework for the Java language. There are other testing frameworks available in the .Net world, such as MS Test, developed by Microsoft itself. +Feel free to try other frameworks later on.

+ +

Ok, let’s begin. For this project I’m going to use Visual Studio 2017. Download the Community version here.

+ +

Create a new solution of the Class Library type, with the name LearningUnitTesting.

+ +

Whenever I create a new solution on Visual Studio I delete the Class1 class that is created by default. You could rename it, of course, it makes no difference.

+ +

Now, let’s rename the default project to Application. This project will store the production code in our solution.

+ +
+

In the context of unit testing, we use the term Production Code when we’re talking about the “real code” in our application, in contrast to the Test Code we also write.

+
+ +

Next step! Now we create the test project. There are several different opinions regarding where should the test class be kept: along with production code, or in a different location. I usually create another project, which I name using the scheme [ProductionProject]Test.

+ +

So, the new project will be called ApplicationTest, and it’ll be of type Class Library as well. +After creating the project, I delete the default class, same as before.

+ +

Your solution should look like this:

+ +

+ +

Let’s install NUnit. Fortunately, NUnit is available as a Nuget package, which makes its installation a breeze.

+ +

First, open the Package Manager Console. Go to: Tools > Nuget Package Manager > Package Manager Console.

+ +

Then type or copy-paste the following command:

+ +
+

Install-Package NUnit

+
+ +

Double-check that you’ve got the right project selected, like in the image:

+ +

+ +

And then press ENTER. The installation will be done in a few seconds.

+ +

We are not done yet, though. We need to install another package, the NUnit Test Adapter, which we’ll let us run NUnit tests in Visual Studio. The process is the same, the only difference is the package’s name:

+ +
+

Install-Package NUnit3TestAdapter

+
+ +

Don’t forget to check if the right project is selected before pressing ENTER. The installation will be done in a few seconds.

+ +

This is it.

+ +

Creating and running the first test

+ +

Let’s create some tests. First, let’s add a new class to our production project. The class’s name will be Employee and its code will look like this:

+ + + +

I think the class is simple enough to not require additional explanation. Now, it’s time to create our test class. Add a new class called EmployeeTest to the ApplicationTest project.

+ +
+

This is another naming convention I like to use: to name the test class after the production class, adding the word Test at the end.

+
+ +

After the class is created, add the NUnit.Framework namespace to its using declarations. Then, create a new void returning public method called MyFirstTestMethod and add the [Test] attribute to it.

+ +

By now, your code should look like this:

+ + + +

The skeleton for the test is ready. It’s time for you to write your first assertion. In the context of unit testing, an assertion is an affirmation about how a unit of your system should behave. If the affirmation turns out to be true, we say the test has passed. In case it proves to be false, we say the test has failed.

+ +

In NUnit we use the Assert class to write our assertions. This class has a large number of methods that allow us to express our expectations about the behavior of our units.

+ +

Add the following line of code to the test method:

+ +
+

Assert.Pass();

+
+ +

The Pass method, not surprisingly, just forces the test to pass. Now you’re going to run this test in order to see it passing. First of all, open the Test Explorer. Use the menu bar: Test > Windows > Test Explorer.

+ +

When the window is show, click on Run All. If everything goes right, you’ll see this:

+ +

+ +

When you click on the test’s name, some additional information is shown, such as the test file and elapsed time:

+ +

+ +

Notice the use of green to indicate the test’s success.

+ +

Now let’s do the opposite: force the test to fail. Replace the previous line for the following one:

+ +
+

Assert.Fail();

+
+ +

Run the test again and you’ll see the failure message, this time with the red bar:

+ +

+ +

Now that you’re getting the hang of it, we’re start testing our Employee class. Don’t forget to switch the test method back to Assert.Pass(), otherwise it will continue to fail.

+ +

Now add a new method called IntroduceMethodShouldWorkCorrectly. In this method we’ll create a new instance of Employee and verify that the Introduce method is working properly.

+ +

Before we do that, though, we must add a reference from the production project to our test project. Otherwise, our test class won’t be able to see the classes it is supposed to test!

+ +

To do that, right-click the ApplicationTest project, then go to Add, then Reference. In the opened window, choose the project, according to the following image:

+ +

+ +

Then, click on OK.

+ +

Back to the test class. Edit the code so it looks like this:

+ + + +

You will notice that Employee is marked as an error. If you hover over it, you’ll see a message saying that the name Employee couldn’t be found and asking if there is some reference or using directive missing.

+ +

Of course there is a using directive missing, related to the reference we’ve just added. To fix this problem, just add the line using Application; to the namespace declarations, right at the start of the file.

+ +

Now that our code compiles, let’s go through this method, line by line.

+ +

In the first line, we create a new instance of Employee, specifying name, profession and salary. In the following line, we assign to a variable the value we expect the method to return. Then we assign to another variable the obtained result from the method.

+ +

Finally, we use the AreEqual method from the Assert class to verify the equality of the two values. This method is, probably, the one you’ll use the most during your tests.

+ +

Now it’s time to run the test. Use the shortcut CTRL + R, A or click on Run All in the Test Explorer window. If everything goes smoothly, you should see the green bar and the message indicating that both tests have passed.

+ +

Time to test our test! We’re going to deliberately ruin the Introduce method to see if the test fails as expected. Back to the production class, edit the method like this:

+ + + +

As you’ve seen, we’ve just removed the square brackets before and after “JobTitle”. This way, the string interpolation won’t work, hard-coding the string instead of replacing it by the value of the variable.

+ +

When we run the tests again, we got the following result:

+ +
+

Mensagem: Expected string length 48 but was 46. Strings differ at index 37. +Expected: “Hi! My name is Alice and I work as a Programmer.” +But was: “Hi! My name is Alice and I work as a JobTitle.” +————————————————^

+
+ +

As you can see, the message is very detailed. It not only lets us know that the strings differed, but it also tells us exactly where they differ. It also shows the expected string and what we really got. It is important to notice that the parameter’s orders in the AreEqual matters a lot, since it is used in the failure message.

+ +
+

The parameters’ order in the AreEqual is very important. First specify the expected value, and then the actual result.

+
+ +

Great. Now you can switch the method back to the correct implementation and run the tests again, so the test can be green again.

+ +

As you can see, a unit test consists in a well defined sequence of steps: we prepare the scenario, then execute the action and verify the results. This sequence of steps, or phases, is sometimes called AAA: Arrange-Act-Assert.

+ +
+

A typical unit test has the three phases: Arrange-Act-Assert.

+
+ +

Even though there are another naming conventions for the phases of a unit test, we’ll adopt Arrange-Act-Assert , at least for now.

+ +

You may be wondering why I gave the name “sut” to the variable at the start of the method. This is a naming convention that I learned while reading Mark Seeman’s blog. SUT stands for System Under Test, i.e. the thing you’re testing.

+ +

There is nothing preventing you from naming the variable whatever you want. I really like to follow this convention, though, since it makes really clear what is being tested.

+ +
+

Tip: Try to use naming conventions that improve the readability of your code and make the author’s intention clear for anyone who reads the code.

+
+ +

Take a look at the same test method, but this time with comments delimiting each test phase:

+ + + +

Even though it isn’t really need, I suggest you use comments like the ones above to indicate the test phases, at least in the beginning of your learning.

+ +

Testing the GiveRaise method

+ +

A salary raise is always welcome, wouldn’t you agree? Let’s test the GiveRaise method to see if it’s working properly. Add the following method to your test class:

+ + + +

Run the test and you should see the familiar green bar. Did it work? Great. Time to test the test: we’re going to sabotage the implementation of GiveRaise and hope our test catches the error.

+ +

In the production class, edit the method this way:

+ + + +

Now the method is obviously wrong; the test should fail. Let’s run it?

+ +
+

Mensagem: Expected: 110 + But was: 5m

+
+ +

Ok, as we can see, the test did fail. Switch the method back to the correct implementation.

+ +

One last test

+ +

Let’s say the Product Owner just showed up with a new requirement: the GiveRaise method should ignore negative raise rates. First, let’s edit the GiveRaise method to deal with this scenario:

+ + + +

We’ve just made a change in production code. Our top priority right now is to guarantee that we haven’t broken anything. +Run the test to be sure that all of them are passing.

+ +

Everything still green? Great, let’s go ahead. Now we need to create a new test to document the “negative raise attempt” scenario.

+ +
+

Unit tests are also a type of documentation.

+
+ +

In the test class, add the following method:

+ + + +

Nothing really surprising here, right? At this point I’m sure you’ve already got this. So, now it is up to you to test the test: ruin the production code in one or more ways to see if the test fails as expected.

+ +

A quick recap

+ +

Today’s article was more dense than the previous one. We’ve managed to cover several topics::

+ +
    +
  • Installation of NUnit and NUnit Test Adapter;
  • +
  • Creation of a test;
  • +
  • Introduction to the Assert class;
  • +
  • Test execution, via Test Explorer and keyboard shortcuts;
  • +
  • Reading and interpretation of test results;
  • +
  • Phases of a unit test (Arrange-Act-Assert).
  • +
+ +

Besides these topics, we’ve also enlarged our test related vocabulary with terms like SUT, assertion and test code vs production code.

+ +

Some naming conventions were covered as well, for both classes and methods.

+ +

Last but not least, you’ve learned about the importance of seeing the test fail, and how we can gain confidence in our tests by deliberately sabotaging the production code.

+ +

Some notes

+ +
    +
  • You’ve probably noticed that my Visual Studio is not in English in the screen-captures. That is because I’m Brazilian and my Visual Studio is configured in Portuguese (and I first wrote this post in pt-br). I apologize for that.
  • +
  • All of the code for today’s post can be found on Github.
  • +
  • Once again, I thank my friend Gunter Italiano Ribeiro for proof-reading this post.
  • +
+ +

Conclusion

+ +

This was my second article in the series about unit testing. As I already mentioned, it is deliberately longer and more practical than the previous one. Still, all we’ve covered today is just the tip of the iceberg. Whole books were written about unit testing; by the way I’m indicating some in the following articles, along with more references.

+ +

For the tests we wrote today, we used the more intuitive - and probably more common - approach of creating the tests after the production code. However, many people and teams work differently: they write the tests before the production code.

+ +

I know it may sound strange, at first, but working this way can bring many benefits to your project. This and other topics will be covered in the next article.

+ +

Thanks for reading! See you soon.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/value-objects-tool/index.html b/en/value-objects-tool/index.html new file mode 100644 index 00000000..66ebfc6e --- /dev/null +++ b/en/value-objects-tool/index.html @@ -0,0 +1,541 @@ + + + + + + + + Value Objects: A Tool for Self-Documented Code and Fewer Errors | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Value Objects: A Tool for Self-Documented Code and Fewer Errors

+ +
+ +
+

+ +

Editorial note: I originally wrote this post for the NDepend blog. You can check out the original here, at their site. While you’re there, take a look at NDepend.

+ +

Have you ever heard of value objects? I bet you have. Even though they’re talked about a lot less than I’d like, they’re still talked about enough that many developers have at least some passing familiarity with the term.

+ +

“Passing familiarity” isn’t good enough, though. So that’s what we’re fixing with this post. Today you’re going to learn what value objects are and how you, as a C# developer, can harness their power to make your code clearer, self-documenting, and less error-prone.

+ +

What Are Value Objects?

+ +

Value objects are one of the building blocks of domain-driven design, as proposed by Eric Evans on his seminal book Domain-Driven Design: Tackling Complexity in the Heart of Software.

+ +

Simply put, a value object is an object that represents a value. And I’m aware that sounds excruciatingly obvious and even boring when said this way. So, what’s all the fuss about it?

+ +

Some Properties

+ +

I think it’s easier to understand value objects when we quit trying to explain what they are and talk about their characteristics instead.

+ +

Value Objects Don’t Have Identity

+ +

I think it’s fair to say that the main characteristic of a value object is that it lacks identity.  But what does that really mean in practice?

+ +

Let’s say you go to the nearest ATM and deposit a $50 bill into your checking account. Then you drive a couple of hours to another town, go to a bank there, and withdraw $50.

+ +

Now comes the question: does it matter to you that the bill you’ve got in your hands now isn’t the same one you deposited earlier? Of course not!  And why is that? Well, the thing we generally care about, as it concerns money, is its value, not the vessel that holds that value.

+ +

In other words, we couldn’t care less about the identity of that particular bill. The only thing that matters is its value.

+ +

It’s no coincidence that money is a classic example of a value object.

+ +

Value Objects Are Immutable

+ +

Can you change the number five? No, you can’t. There’s nothing you (or anyone else) can do to mutate the value of the number five. If you add one to it, it doesn’t change; instead, you get six, which is another number.

+ +

Could you alter a date? Nope, you also can’t do that. If you start with “2018-01-9” and add one day to it, you get “2018-01-10.” You don’t change the original date at all. In fact, the immutability aspect of a value object is a direct consequence of the previous point; since a value object doesn’t have identity, we can say the value object is its value. Therefore, it doesn’t even make sense to talk about changing it.

+ +

The implication of this for you as a developer is that value objects are inherently safer and easier to reason about. There’s no risk of changing them by accident since they can’t be changed at all.

+ +

Value Objects Have Structural Equality

+ +

Imagine you could magically teleport people to anywhere you wish, and you’ve decided to swap two men called “John Smith” during the night. How do you think their respective partners would react to see a total stranger in their beds instead of their husbands?

+ +

People are obviously not interchangeable, despite sharing one or more characteristics. Even if our two Johns had not only the same name but also the same height, weight, skin color, and hair color, they would still be two completely different people. Even identical twins (or, on a slightly Black Mirror note, clones) continue to be different people, despite being as equal to one another as you can get.

+ +

On the other hand, people change continuously during their lives, but they are still the same people (as long as we don’t get philosophical here, as in “a man can’t step into the same river twice” type of thing).

+ +

You may be wondering if I’ve gotten off track here, but I haven’t. This only serves to illustrate the crucial differences between entities and value objects. With entities, we care about identity, not about the value of its attributes.  With value objects, we care only about the value itself.

+ +

The implication of this, in programming terms, is that value objects typically present structural equality. It makes sense to compare them by their values, not their references or identities. So, when implementing a value object, you’ll want to override “Equals” and “GetHashCode.”

+ +

What’s in It for Me?

+ +

By now you should have a pretty good idea of what value objects are. What’s not clear yet is why you should use them.  To answer this, let’s consider the following line of code:

+ +
    double  distance  =  4.5;
+ +

Is there something wrong with this? Well, I could Ben Kenobi you and say that it might be wrong “from a certain point of view.” But I won’t. Instead, I’ll say it’s definitely wrong. It doesn’t matter that it compiles. It also doesn’t matter that it actually works some or even most of the time.

+ +

The problem here is the code smell known as “primitive obsession,” i.e., modeling domain concepts using primitive types. The next few sections will dive in into why is this such a problem and how the use of value objects can help.

+ +

Value Objects Provide Context

+ +

OK, so why is primitive obsession a bad thing? There are in fact several reasons, but one of the main problems with the code snippet presented in the previous section is that it lacks a critical piece of information. As you can see, the code assigns the value 4.5 to the variable. But 4.5 what? Meters? Kilometers? Miles? Parsecs? In other words, we don’t have the unit of measurement.

+ +

This can be a recipe for disaster. It just takes a developer fetching a value from a database or a file, thinking it’s supposed to represent meters but it’s in fact kilometers. When they then proceed to use the value in a calculation, say, adding kilometers to miles…silence. Instead of failing fast, you’d get a program that silently misbehaves while corrupting data and providing inconsistent results.

+ +

Well, at least you’re using unit tests…right?

+ +

Sure, nothing prevents you from encoding that information in the variable name itself:

+ +
	double  distanceInKilometers  =  4.5;
+ +

Yeah, this is slightly better than the previous version, but it’s still a very brittle solution. At any moment, the value can be assigned to another variable or even passed as an argument to some function, and then the information is lost.

+ +

By using value objects, you can eliminate this problem easily. You’d just have to choose a unit to be the internal representation of the type—for distance, it probably makes sense to use meter, since it’s an SI unit. And then you can provide several static factory methods for each necessary unit:

+ +
	var  distance  =  Distance.FromMeters(4000);
+	var  distance2  =  Distance.FromKilometers(4);
+	Assert.AreEqual(distance,  distance2);
+ +

If you go on to overload the “+” operator (or create a “Plus” method), you can safely add two distances that originate from different units of measurement since the internal representation is the same.

+ +

Value Objects Are Type Safe

+ +

Let’s say you have a method with this signature:

+ +
	double  PerformSomeImportantCalculation(double  distance,  double  temperature);
+ +

What would happen if you made a mistake and inverted the values when calling the method? The program would silently misbehave, and you wouldn’t even be aware. Hopefully, you’d have a good QA process in place that would catch this bug before it hits production, but hope isn’t exactly a strategy, right?

+ +

Well, as it turns out, that’s the exact kind of problem value types are great at preventing. You’d just have to use custom types for each concept instead of relying on primitives:

+ +
	double  PerformSomeImportantCalculation(Distance distance,  Temperature temperature);
+ +

That way, you can’t just pass the parameters in the wrong order: the compiler won’t let you!

+ +

Value Objects Prevent Duplication of Domain Logic

+ +

When you model domain concepts using primitive types, you tend to have a lot of code related to that concept spread throughout the whole application. Let’s say you’re building an application that has the concept of a license plate, and you’re using strings to represent those. Of course, not all strings are valid license plates. So your code ends up with format validations for license plates everywhere.

+ +

This could be prevented by creating a “LicensePlate” class and performing the necessary validations on its constructor. That way you’d consolidate the validation code in one place; should it ever change in the future, you’d only have to change it in this one place.

+ +

Value Objects and Value Types Aren’t Synonymous

+ +

This section is necessary in order to clarify a common misconception, which is to mix up value objects with the concept of value types in C#. See, in C#, we have two categories of types: reference types and value types.

+ +

While you certainly can use structs (value types) to implement value objects—examples in the BCL would be DateTime or the primitive numeric types— there’s nothing preventing you from using classes.

+ +

On the other hand, structs are not automatically value objects. For instance, while it’s considered good practice to keep structs immutable, they’re not immutable by default.

+ +

In short, value type is an implementation detail in C#/.NET while value object is a design pattern. Keep that in mind and consult the Microsoft design guidelines and you should be fine.

+ +

Value Objects Are Worth It!

+ +

Value objects are a relatively low-cost technique that can greatly enhance the manageability and clarity of your code. By employing value objects, you can make your code easier to reason about, crafting APIs that are self-documenting, easy to understand, hard to use incorrectly, and inherently type-safe.

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/value-reference-types-in-csharp-part-2/index.html b/en/value-reference-types-in-csharp-part-2/index.html new file mode 100644 index 00000000..a4cb48ca --- /dev/null +++ b/en/value-reference-types-in-csharp-part-2/index.html @@ -0,0 +1,495 @@ + + + + + + + + Value and reference types in C#, Part 2 - Why can't a DateTime be null? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Value and reference types in C#, Part 2 - Why can't a DateTime be null?

+ +
+ +
+

+ +

“Why is not allowed to assign null to a DateTime?” Again and again, this question keeps showing up on StackOverflow and similar sites. Different phrasing, maybe a different type (“Why type “int” is never equal to ‘null’?”), but the same question, in essence. Which is only natural, considering that probably thousands of developers join the field every year. +

+ +

The short answer is: because DateTime/int/float/whatever is a value type, and value types can never be null. Only reference types can be null.

+ +

That’s great but…why???

+ +

I mean, at some point, the C# designers had to make that call. They deliberately decided that null can’t be assigned to a value type. Is there something intrinsic to value types that prevent them from being null? Maybe it has something to do with the stack and the heap?

+ +

Well, I think before we try to answer those questions, it’d be helpful to get a step back and think about other question.

+ +

What exactly is ‘null’?

+ +

You probably think of null as a way to represent a missing piece of information. Something that is unknown, absent or irrelevant. Maybe a piece of information that isn’t where it’s supposed to be yet, but it might be in the future.

+ +

In the previous post about reference and value types, we learned that a variable of a reference type contains a reference that points to an instance of that type. But when null is assigned to the variable, what does the variable contain? Nothing?

+ +

Not exactly. Even though null basically means nothing, this “nothing” has to be represented in some way in the machine’s memory.

+ +

In C#, the null keyword represents a null reference, which is a reference that doesn’t point to any object. +In practice, the null value is represented as all zero bits.

+ +

Of course, this is just an implementation detail. It could be implemented in different ways, so this isn’t really relevant for us. What you need to understand is, you need something to represent nothing. You need some kind of special value that means “this value is missing” or “this value is unknown”.

+ +

Once you understand this, it becomes easier to see what the problem is with value types.

+ +

How would you represent null for a value type?

+ +

To understand why would be complicated to represent null using a value type, you must bear in mind that value types usually have a range of possible values that they’re able to represent.

+ +

It’s easier to get this with an example. So, consider the byte value type.

+ +

This type can represent one byte of possible values. Since 2^8 = 256, it can represent 256 values. It is also unsigned, meaning it can only represent values greater than or equals to zero. Thus, the range of possible values that the byte type can represent is 0 to 255.

+ +
00000000 => 0
+00000001 => 1
+00000010 => 2
+    .        .
+    .        .
+    .        .
+11111111 => 255
+
+ +

Now comes the tricky part. If the C# language designers wanted the byte type to be nullable, they’d have to pick a value from the range and elect it as the null value. Let’s imagine they picked zero as the null value for byte. If that was the case, we wouldn’t be able to use zero as a valid value never again!

+ +

That’s the whole point: for value types to be nullable, it is necessary to sacrifice one of the possible values of the range to represent the null value.

+ +

Jon Skeet, author of C# In Depth, puts it better than me:

+ +
+

You’ve got to be able to store the values 0-255 in that variable; otherwise it’s useless for reading arbitrary binary data. With the 256 normal values +and one null value, you’d have to cope with a total of 257 values, and there’s no way of squeezing that many values into a single byte.

+ +

The designers could’ve decided that every value type would have an extra flag bit somewhere determining whether a value was null or contained real data, but the memory usage implications +are horrible, not to mention the fact that you’d have to check the flag every time you wanted the use the value.

+
+ +

So, there is nothing in principle that prevents value types from being null. It’d just be so complicated that the C# designers considered that the benefits of doing so don’t outweigh the costs.

+ +

But I really want/need a nullable value type. What can I do?

+ +

You now hopefully understand the complications involved in representing null for a value type, and why the C# developers decided against it. But, what if you really need to do this? One common scenario is when you’re fetching data from a relational database. What should you do?

+ +

Well, thankfully, there’s an easy solution. Even though “normal” value types can’t be null, C# 2 introduced the Nullable structure, which allows you to assign `null` to pretty much anything.

+ +

I’ll talk about nullable types in the next article. As a bonus, you’ll learn a bit about another nice feature called generics.

+ +

Stay tuned!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/en/value-reference-types-in-csharp/index.html b/en/value-reference-types-in-csharp/index.html new file mode 100644 index 00000000..4df62ee2 --- /dev/null +++ b/en/value-reference-types-in-csharp/index.html @@ -0,0 +1,542 @@ + + + + + + + + Value and reference types in C# | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Value and reference types in C#

+ +
+ +
+

+ +

This is my first “real” post here on my blog, and I decided to talk about value types and reference types. This is somewhat of a basic subject, in the sense that it is something that you should already know if you write C# code for a living.But at the same time, it can be a little non-intuitive if you’re not an experienced developer. + +I’ll try to make this as simple and short as possible, so I won’t talk about string immutability, boxing, unboxing, and some other things with fancy names. +I’ll write about those in the future, but for today let’s focus on the basics.

+ +

So, take a look at the following piece of code.

+ +
    int x = 10;
+    int y = x;
+    y++;
+    Console.WriteLine($"The value of x is {x}"); // Outputs "The value of x is 10"
+    Console.WriteLine($"The value of y is {y}"); // Outputs "The value of y is 11"
+ +

No surprises here, cause this is the exact behaviour you’d expect.
+Now, suppose we have a class like this:

+ +
    public class Person
+    {
+        public string Name { get; set; }
+        public string Profession {get; set; }
+
+        public Person(string name, string profession)
+        {
+            Name = name;
+            Profession = profession;
+        }
+
+        public void SayHello()
+        {
+            Console.WriteLine($"Hello! My name is {Name} and I'm a {Profession}");
+        }
+    }
+ +

Now, you do this:

+ +
   
+    var person = new Person("Mary", "programmer");    
+    person.SayHello(); // outputs "Hello! My name is Mary and I'm a programmer"
+    var person2 = person;
+    person2.Name = "John";
+    person2.Profession = "musician";    
+    person2.SayHello(); // outputs "Hello! My name is John and I'm a musician "  
+    person.SayHello();   // outputs "Hello! My name is John and I'm a musician " 
+ +

Now is the time when beginners sometimes get confused. “This doesn’t make sense”, they say. “I’ve changed the value of one of the variables, and the other also changed.”

+ +

Well, that is the wrong way to look at it. As it turns out,you didn’t really change the value of the variable, in this case. And that’s the point.

+ +

Remember the first example? Let’s take a look at it again, this time step by step:

+ +

The figure show a sample of C# soure code, in which a variable is being declared and assigned the value 10

+ +

We declare the first variable and assign the value 10 to it. Now, somewhere inside the computer’s memory, there is a “box” labeled “x” which holds the value 10.

+ +

The image show a sample of C# code, in which a variable y is being declared, and the value of x is assigned to it.

+ +

We declare the second variable and assign the value of the first variable to it. Notice that the value is copied from x to y. Now we have two boxes, one labeled x, the other labeled y, and both of them hold the value 10.

+ +

The image show a sample of C# code, in which a variable y gets incremented by 1.

+ +

Finally, we increment the value of the variable y by 1. Notice that the value of x remained unchanged. Of course, because they have nothing to do with each other!

+ +

On the other hand, something very different happens when you’re dealing with reference types. To understand that, let’s review the second example, step by step:

+ +

The image show a sample of C# code, in which a variable is assigned a new instance of the Person class

+ +

First, we create a variable called person and assign to it a new instance of the Person class. Now, somewhere inside the computer’s memory, we have a box called “person”. Notice, however, that our variable person stores a reference that points to the instance of Person, instead of storing the instance itself!

+ +

The image show a sample of C# code, in which a variable person2 is created and receives the value of the variable person.

+ +

In the second step, we create a variable called person2 and assign the value of the variable person to it. As in the previous example, the value from one variable is copied to the other. In this case, the value that is copied is the reference that points to the instance. So now we have two variables whose values are references that point to the same instance of Person.

+ +

Now, of course when you change the object’s data (e.g. alter the person’s name and/or profession), it seems that the two variables were altered. In fact, the variables’s values remain exactly the same: what was really changed was the object to which they point to.

+ +

So, we could summarize that way: value types store data. When you assign the value of a value type variable to another, what gets copied is the data itself (like an integer, for example).
+This is similar to when you copy a file from one folder and paste it somewhere else. You made a copy, but from now on, they are independent files and have nothing to do with each other.

+ +

Reference types store a reference, that points to the data, which lives somewhere else in the machine’s memory. When you assign the value of a reference type variable to another, what gets copied is the reference.It can be useful to think of them as shortcuts to files. If you have one or more shortcuts that point to a particular file, when you make changes in the original file, those changes will be visible through the shortcuts. Because they’re just that, shortcuts.

+ +

Which types are value types?

+ +

According to MSDN, the value types are:

+ +
    +
  • All numeric data types
  • +
  • Boolean, Char, and Date
  • +
  • All structures
  • +
  • Enumerations
  • +
+ +

Which types are reference types?

+ +

Again, acording to MSDN:

+ +
    +
  • String
  • +
  • All arrays
  • +
  • Classes
  • +
  • Delegates
  • +
+ +

Wait a minute! String is a reference type?!

+ +

Maybe you’re surprised to see String listed as a reference type. After all, it seems to behave as a value type. +Well, the reason for this is because String is an immutable type. As I said, I won’t talk about this today, but soon we’ll have a post all about System.String.

+ +

OK, that’s it for today. I hope you guys enjoyed this post, and I’d love to hear your feedback.Have I expressed myself clearly enough? Have I said something innacurate - or even flat-out wrong? +Let me know in the comments, or reach me on twitter.

+ +

References:

+ + + + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..56f589bc2aa690ee2d3aa8022ac225899d404342 GIT binary patch literal 1150 zcmd6lZAep57{~uc6cp4L6hR-9UdRtYeo6F8LL?R{89{FZBKbj>fh9^5L?J;Tgt3w` zDVgSLE>SU!N*iJ}UFD+LaJz0-x4W0SUGLSsubs|q_0jvGPjUD^&pFR?e(*f!IY0(o zDix^BLe)lKCxC1!8lsVOoH~H!)LYZ~eWr#G^54iaUDGG}Eq*D$L{{9>$rbnKkiZNu zw8oZCW>IcSvDVda+%57p&TG15_8Y79o+-_!ceX~1a0A5sz0-I5W}RB8Up_^^Ox9tc z8O5G1(~8Y(H_Dd#afs6+pV4B6HuOxfL(_Swi88M7qS_h`iSF8b8n1-+}!;hCI0Fe;Cw*_f;zzYD)TsJth*Sr z^;pBakx0I;WU+tubtV2_X8KpeEfuGPr4e4@e~>lNPB=@OZ*^?fxx^syl=$JMeHiP% z+mKu{kxuZ+h062uzR#;9(K+IoAGW)vF4vj|Ph;W^V9-LP z-Xi~FWqx_G>RlopAhx~(8e1cdEj&k#;SnxrE3vot;aNO+_Hy0X$$haC7n-7UV|!ax zZf-`dza52q8%oEu8@3S=Lr3=;MgB_Zrc4sl&-z2e!&>zdyzz!Xn7L+f%)M}i31M9> zmqzLR%8P+-y?b&Zmik4>-Yx_kLq7$VDHZpQBqZjkc(0-MgcAR6Ir&Wi2c5lRI}oK> WIhpp!zh|0rj?;X>AIW#9WbPMez0uwP literal 0 HcmV?d00001 diff --git a/feed.xml b/feed.xml new file mode 100644 index 00000000..5c2f9b96 --- /dev/null +++ b/feed.xml @@ -0,0 +1,2462 @@ + + + + carlos schults / blog + Articles on software development and technology. + https://carlosschults.net/ + + Fri, 02 Aug 2024 13:11:07 +0000 + Fri, 02 Aug 2024 13:11:07 +0000 + Jekyll v4.3.1 + + + + C# Regex: How Regular Expressions Work in C#, With Examples + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg" alt="" /> +<em>Editorial note: I originally wrote this post for the Stackify blog. You can <a href="https://stackify.com/c-regex-how-regular-expressions-work-in-c-with-examples/">check out the original here, at their site</a>.</em></p> + +<p>Text manipulation is one of the most common tasks in programming with virtually all major programming languages usually supporting regex (regular expression) via their standard libraries. C# is no exception, so today we bring you a C# regex guide.</p> + +<p>You’ll learn what regexes are, why you’d want to use them and how to get started in a comprehensive, approachable manner. That way, you can start using regular expressions to solve real problems ASAP.</p> + +<p>Buckle up for your regex learning journey, starting now!</p> + +<h2 id="what-is-regex">What Is Regex?</h2> +<p>A regular expression (regex) is an expression containing one or many characters that expresses a given pattern in text. If that sounds a little vague, an example will help. Consider a date in the following format:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>28-JUL-2023 +</code></pre></div></div> + +<p>Using a regex, we can express that format like this:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0-9]{2}-[A-Z]{3}-[0-9]{4} +</code></pre></div></div> + +<p>Note that the regular expression above expresses a pattern with:</p> + +<ul> + <li>two numeric digits followed by a hyphen</li> + <li>three upper-case letters followed by a hyphen</li> + <li>four more numbers</li> +</ul> + +<p>You’ll learn more about what each part of a regex means in a minute. For now, just bear in mind that the regex above doesn’t <em>know</em> anything about dates. It just happens that we were able to devise a regular expression that matches the pattern or shape of the date. All of the following match with that regex, even though they’re not valid dates:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>32-ABC-7894 +30-FEV-1978 +00-AAA-9999 +</code></pre></div></div> + +<h2 id="is-there-regex-in-c">Is There Regex in C#?</h2> + +<p>Yes, of course. But that doesn’t come from the language itself. Instead, regex support comes from <a href="https://learn.microsoft.com/en-us/dotnet/standard/class-library-overview">.NET’s BCL (Base Class Library),</a> which is essentially C#’s standard library.</p> + +<h2 id="why-use-regex-in-c">Why Use Regex In C#?</h2> + +<p>As you’ve seen, regex is something to use to express a pattern that can match a given text. </p> + +<p>In practice, all uses of regex in C# or other languages boil down to three reasons: validation, manipulation and extraction.</p> + +<h3 id="validation">Validation</h3> + +<p>An incredibly common use case for regex is data validation. For instance, let’s say you have a web form and want to ensure a certain field only accepts inputs in a specific format. How to solve that? Regex comes to the rescue.</p> + +<h3 id="manipulation">Manipulation</h3> + +<p>Sometimes you need to change information within text. Let’s go back to the previous example. Imagine for compliance reasons you need to remove all phone numbers from this body of text and replace them with the word “REDACTED.” Again, regexes would be a perfect fit for this situation.</p> + +<p>Interestingly, programming languages are not alone in using regular expressions to solve problems. Even text editors such as Notepad++ offer find-and-replace features powered by regexes.</p> + +<h3 id="extraction">Extraction</h3> + +<p>Let’s say you have considerable amounts of text. This text contains telephone numbers that you need to extract. You know the format of those numbers and the fact that they’re inside the text, but that’s the extent of your knowledge.</p> + +<p>How would you go about extracting that information? A neat C# regex would certainly come in handy in that situation.</p> + +<h2 id="how-to-use-regex-in-c-getting-started-in-practice">How to Use Regex In C#: Getting Started in Practice</h2> + +<p>C# is an <a href="https://stackify.com/oop-concepts-c-sharp/">OOP language</a>, so it shouldn’t be a surprise that you’ll use a class for your C# regex work. More specifically, the class I’m talking about is appropriately called Regex and resides in the System.Text.RegularExpressions namespace<strong>.</strong></p> + +<h3 id="c-regex-a-validation-example">C# Regex: A Validation Example</h3> + +<p>Let’s start with a simple validation example on how to use regex to validate whether several strings match a given pattern. The first step is to add the following <strong>using</strong> statement to your code:</p> + +<p>using System.Text.RegularExpressions;</p> + +<p>Now, let’s create an array of strings and populate it with some values:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">candidates</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> +<span class="p">{</span> + <span class="s">"28-JUL-2023"</span><span class="p">,</span> + <span class="s">"whatever"</span><span class="p">,</span> + <span class="s">"89-ABC-1234"</span><span class="p">,</span> + <span class="s">"11-JUN-2022"</span><span class="p">,</span> + <span class="s">"11-JUN-2022, a date plus other stuff"</span><span class="p">,</span> + <span class="s">"This is certainly not a date"</span> +<span class="p">};</span></code></pre></figure> + +<p>Finally, we’ll loop through the values and use the <code class="language-plaintext highlighter-rouge">IsMatch</code> static method from the <code class="language-plaintext highlighter-rouge">Regex</code> class to verify which of the strings matches our desired pattern:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">"[0-9]{2}-[A-Z]{3}-[0-9]{4}"</span><span class="p">;</span> +<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">c</span> <span class="k">in</span> <span class="n">candidates</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">Regex</span><span class="p">.</span><span class="nf">IsMatch</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">pattern</span><span class="p">))</span> + <span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"The string '</span><span class="p">{</span><span class="n">c</span><span class="p">}</span><span class="s">' matches the pattern '</span><span class="p">{</span><span class="n">pattern</span><span class="p">}</span><span class="s">'"</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Before going further, let’s break down the pattern piece by piece:</p> + +<ul> + <li><strong>[0-9]{2}:</strong> The first part means “Match exactly two characters, that must be digits from 0 to 9.”</li> + <li><strong>-:</strong> This character matches exactly a hyphen.</li> + <li><strong>[A-Z]{3}:</strong> Here, the expression says, “Let’s match exactly three characters, which can be any of the letters from A to Z.”</li> + <li><strong>-:</strong> This matches another hyphen</li> + <li><strong>[0-9]{4}:</strong> This should be easy to understand by now, right? Exactly four numbers.</li> +</ul> + +<p>Now, let’s run the code and see what we get:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The string '28-JUL-2023' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +The string '89-ABC-1234' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +The string '11-JUN-2022' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +The string '11-JUN-2022, a date plus other stuff' matches the pattern '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +</code></pre></div></div> + +<p>The first three results probably didn’t surprise you. I even include something that’s not a date but matches the pattern we’re using in order to really drive home the point that regular expressions are about patterns and shapes and not about any semantics of the data we’re looking for.</p> + +<p>However, the fourth result might’ve surprised you. The text indeed starts with data that matches the pattern we’re looking for, but then it has some additional text. And even then, this string matched!</p> + +<p>The explanation for this behavior is simple, and it’s spelled out for us in the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.ismatch?view=net-7.0#system-text-regularexpressions-regex-ismatch(system-string-system-string)">summary</a> for the <code class="language-plaintext highlighter-rouge">IsMatch</code> method:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Indicates whether the specified regular expression finds a match in the specified input string. +</code></pre></div></div> + +<p>The regular expression indeed found a match in the specified input string (“11-JUN-2022, a date plus other stuff”), and that’s why it was considered a match.</p> + +<p>But what if we wanted an exact match? In that case, you’d have to change the pattern, adding a circumflex accent (“^”) to the star of the pattern and a dollar sign (“$”) to its end. In other words, here’s how the pattern should look now:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">"^[0-9]{2}-[A-Z]{3}-[0-9]{4}$"</span><span class="p">;</span></code></pre></figure> + +<p>If we run the code now, it displays only the strings that are an exact match with the pattern:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The string '28-JUL-2023' matches the pattern '^[0-9]{2}-[A-Z]{3}-[0-9]{4} +</code></pre></div></div> + +<h3 id="c-regex-a-manipulation-example">C# Regex: A Manipulation Example</h3> + +<p>Consider you have a body of text containing sensible user data. Due to privacy/compliance concerns, you want to redact those data points. Luckily for you, it’s quite easy to use a regex for that. </p> + +<p>Let’s start by creating an array containing names and phone numbers for fictitious people:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">contacts</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> + <span class="s">"Emily Johnson,(555) 123-4567"</span><span class="p">,</span> + <span class="s">"Benjamin Williams,(555) 987-6543"</span><span class="p">,</span> + <span class="s">"Olivia Davis,(555) 222-3333"</span><span class="p">,</span> + <span class="s">"Alexander Smith,(555) 444-5555"</span><span class="p">,</span> + <span class="s">"Sophia Brown,(555) 777-8888"</span><span class="p">,</span> + <span class="s">"William Anderson,(555) 111-2222"</span><span class="p">,</span> + <span class="s">"Ava Martinez,(555) 666-7777"</span><span class="p">,</span> + <span class="s">"James Thompson,(555) 888-9999"</span><span class="p">,</span> + <span class="s">"Isabella Wilson,(555) 333-4444"</span><span class="p">,</span> + <span class="s">"Michael Taylor,(555) 777-1111"</span> +<span class="p">};</span></code></pre></figure> + +<p>Then, let’s create the pattern to match the phone numbers:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">@"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}"</span><span class="p">;</span></code></pre></figure> + +<p>The pattern above is a bit more involved than the ones we used earlier, but it’s still simple. There are a couple of new elements, though:</p> + +<ul> + <li><strong>The backward slash (\):</strong> We need it here in order to escape the opening and closing parenthesis, which is a character with meaning in a regular expression. In this instance, we actually do want to match a “(” character, so we need to escape it.</li> + <li><strong>The \s character:</strong> matches a single space.</li> +</ul> + +<p>Finally, let’s loop through this array and, for each item, use the <code class="language-plaintext highlighter-rouge">Regex.Replace</code> method to generate a new string in which the phone number is replaced by all zeroes:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">contact</span> <span class="k">in</span> <span class="n">contacts</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span> + <span class="n">Regex</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="n">contact</span><span class="p">,</span> <span class="n">pattern</span><span class="p">,</span> <span class="s">"(000) 000-0000"</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Using the Replace static method is easy. Though it has several overloads, the one we use just takes three arguments:</p> + +<ul> + <li>the input string</li> + <li>the pattern you want to match</li> + <li>the replacement string</li> +</ul> + +<p>After running the code, here’s the output we get:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Emily Johnson,(000) 000-0000 +Benjamin Williams,(000) 000-0000 +Olivia Davis,(000) 000-0000 +Alexander Smith,(000) 000-0000 +Sophia Brown,(000) 000-0000 +William Anderson,(000) 000-0000 +Ava Martinez,(000) 000-0000 +James Thompson,(000) 000-0000 +Isabella Wilson,(000) 000-0000 +Michael Taylor,(000) 000-0000 +</code></pre></div></div> + +<h3 id="c-regex-an-extraction-example">C# Regex: An Extraction Example</h3> + +<p>For our last example, let’s extract data from a string using a regular expression. Let’s start by converting the array from the previous example into a single string:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">contacts</span> <span class="p">=</span> + <span class="s">"Emily Johnson+(555) 123-4567"</span> <span class="p">+</span> + <span class="s">"\nBenjamin Williams+(555) 987-6543"</span> <span class="p">+</span> + <span class="s">"\nOlivia Davis+(555) 222-3333"</span> <span class="p">+</span> + <span class="s">"\nAlexander Smith+(555) 444-5555"</span> <span class="p">+</span> + <span class="s">"\nSophia Brown+(555) 777-8888"</span> <span class="p">+</span> + <span class="s">"\nWilliam Anderson+(555) 111-2222"</span> <span class="p">+</span> + <span class="s">"\nAva Martinez+(555) 666-7777"</span> <span class="p">+</span> + <span class="s">"\nJames Thompson+(555) 888-9999"</span> <span class="p">+</span> + <span class="s">"\nIsabella Wilson+(555) 333-4444"</span> <span class="p">+</span> + <span class="s">"\nMichael Taylor+(555) 777-1111"</span><span class="p">;</span></code></pre></figure> + +<p>Then, we define the pattern again (same one) and use the Matches static method to get all of the matches from the string:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">@"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}"</span><span class="p">;</span> +<span class="n">MatchCollection</span> <span class="n">matches</span> <span class="p">=</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">contacts</span><span class="p">,</span> <span class="n">pattern</span><span class="p">);</span></code></pre></figure> + +<p>The <code class="language-plaintext highlighter-rouge">MatchCollection</code> class holds all of the strings that matched the pattern we gave to the method. This object is enumerable, so we can loop over it with a foreach:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"Here are the extracted phone numbers:"</span><span class="p">);</span> +<span class="k">foreach</span> <span class="p">(</span><span class="n">Match</span> <span class="n">match</span> <span class="k">in</span> <span class="n">matches</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>And, finally, our results: </p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">Here</span> <span class="n">are</span> <span class="n">the</span> <span class="n">extracted</span> <span class="n">phone</span> <span class="n">numbers</span><span class="p">:</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">123</span><span class="p">-</span><span class="m">4567</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">987</span><span class="p">-</span><span class="m">6543</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">222</span><span class="p">-</span><span class="m">3333</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">444</span><span class="p">-</span><span class="m">5555</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">777</span><span class="p">-</span><span class="m">8888</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">111</span><span class="p">-</span><span class="m">2222</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">666</span><span class="p">-</span><span class="m">7777</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">888</span><span class="p">-</span><span class="m">9999</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">333</span><span class="p">-</span><span class="m">4444</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">777</span><span class="p">-</span><span class="m">1111</span></code></pre></figure> + +<h2 id="c-regex-an-indispensable-tool">C# Regex: An Indispensable Tool</h2> + +<p>As we said in the intro, text manipulation is a staple of programming, and regular expressions make this task easier. In this C# regex guide, you’ve learned what regular expressions are, their most common usage scenarios and how to get started with regular expressions in C#.</p> + +<p>Before departing, a few tips:</p> + +<ul> + <li>Experiment more with the <code class="language-plaintext highlighter-rouge">Regex</code> class. It offers plenty of features, and the methods we’ve used today have many overloads with useful capabilities.</li> + <li>Learn more and practice writing regular expressions. <a href="https://regexr.com/">Here’s a great site</a> you can use.</li> + <li>Educate yourself on the performance considerations of C# regex. For instance, read this <a href="https://learn.microsoft.com/en-us/dotnet/standard/base-types/compilation-and-reuse-in-regular-expressions?redirectedfrom=MSDN">Microsoft article on the compilation and reuse of regular expressions</a>.</li> +</ul> + +<p>Finally, if you want to learn more about C# in general, you’re in the right place. The Stackify blog is full of useful resources. As a suggestion, take a look at <a href="https://stackify.com/unit-test-frameworks-csharp/">the pros and cons of the top 3 unit test frameworks for C#</a>, <a href="https://stackify.com/csharp-catch-all-exceptions/">how to catch exceptions and find application errors in C#</a>, and <a href="https://stackify.com/what-is-c-reflection/">how C# reflection works</a> next.</p> + +<p>Thanks for reading!</p> + + Tue, 07 May 2024 00:00:00 +0000 + https://carlosschults.net/en/csharp-regex + https://carlosschults.net/en/csharp-regex + + csharp + + regex + + regular_expressions + + tutorial + + + + + + Git Create Branch: 4 Ways To Do It + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><em>Editorial note: I originally wrote this post for the Cloudbees blog. You can <a href="https://www.cloudbees.com/blog/git-create-branch">check out the original here, at their site</a>.</em></p> + +<p>If you write software for a living, then I can say with confidence you’re familiar with Git. The tool created by Linus Torvalds has become synonymous with version control. And without a doubt, one of Git’s best features is how it takes away the pain of branching and merging. There are several ways you can create a branch in Git. In this post, we’ll review some of them. Then we’ll end with a little reflection on Git’s branching model and branching in general.</p> + +<h2 id="creating-a-branch-from-main">Creating a Branch From main</h2> + +<p>You create branches in Git, unsurprisingly, by using the <code class="language-plaintext highlighter-rouge">branch</code> command. Like many other Git commands, <code class="language-plaintext highlighter-rouge">branch</code> is very powerful and flexible. Besides creating branches, it can also be used to list and delete them, and you can further customize the command by employing a broad list of parameters. We’ll begin with the first way of creating a branch. Let’s say you want to create a new folder called “my-app”, enter it, and start a new Git repository. That’s exactly how you’d do it:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir my-app +cd my-app +git init +</code></pre></div></div> + +<p>Now you have a new, empty Git repository. But empty repositories are boring. So what about creating a new markdown file with “Hello World!” written in it?</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo Hello World! &gt; file.md +</code></pre></div></div> + +<p>If you run “git status”, you should see a message saying your file is untracked:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git status +On branch main +Untracked files: + (use "git add &lt;file&gt;..." to include in what will be committed) + + file.md + +nothing added to commit but untracked files present (use "git add" to track) +</code></pre></div></div> + +<p><a href="https://www.cloudbees.com/blog/git-remove-untracked-files">Untracked files are also uncool, though, so let’s track it:</a></p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add file.md +</code></pre></div></div> + +<p>And finally, let’s create our first commit:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit -m "First commit" +</code></pre></div></div> + +<p>We now have a repository with one branch, which has exactly one commit. That might not sound like the most exciting thing in the world (because it really isn’t), but it’s certainly less boring than having a repo with no commits at all, right?</p> + +<p>Now, let’s say that for whatever reason you need to change the file’s content. But you don’t feel like doing that. What if something goes wrong and you somehow spoil the beautiful, pristine content of your file? (Yeah, I know it’s just some stupid file with “Hello World!” in it, but use the wonderful powers of your imagination and think of the file as a proxy for a much more complex project.) The solution to this dilemma is, of course, creating a new branch:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch exp +</code></pre></div></div> + +<p>So now we have a new branch called “exp”, for experimentation. Some people who are used to using different versioning systems, especially centralized ones, could say the branches have the same “content.” This isn’t entirely accurate when talking about Git, though. Think of branches like references that point to a given commit.</p> + +<h2 id="creating-a-branch-from-a-commit">Creating a Branch From a Commit</h2> + +<p>Suppose that, for whatever reason, we give up on our experiment, without adding a single commit to the new branch. Let’s go back to <code class="language-plaintext highlighter-rouge">main</code> and delete the <code class="language-plaintext highlighter-rouge">exp</code> branch:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout main +git branch -d exp +</code></pre></div></div> + +<p>Now that we’re back to a single branch, let’s add some commits to it, to simulate work being done:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo a new line &gt;&gt; file.md +git commit -a -m "Add a new line" +echo yet another line &gt;&gt; file.md +git commit -a -m "Add yet another line" +echo one more line &gt;&gt; file.md +git commit -a -m "Add one more line" +echo this is the last line i promise &gt;&gt; file.md +git commit -a -m "Add one last line" +</code></pre></div></div> + +<p>Imagine that after doing all this “work,” you learn that, for whatever reason, you need to go back in time to when there were just two lines in the file and create new changes from then on. But at the same time, you must preserve the progress you already made. In other words,  you want to create a branch from a past commit. How would you do that? In Git, each commit has a unique identifier. So you can easily see this using the <code class="language-plaintext highlighter-rouge">git log</code> command. To create a new branch based on a specific commit, just pass its hash as a parameter to the <code class="language-plaintext highlighter-rouge">branch</code> command:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch new-branch 7e4decb +</code></pre></div></div> + +<p>As an aside, you don’t even need the whole hash most of the time. Just the first five or six characters will do it.</p> + +<h2 id="creating-a-branch-from-a-tag">Creating a Branch From a Tag</h2> + +<p>If you’re a little bit more experienced with Git, then you should be familiar with the concept of <a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging">tags</a>. You use tags to indicate that a given commit is important or special in some way. For instance, tags are generally used to indicate the actual versions of a product. If you’ve been working in your application for a while and you believe it’s time to release version 1.0, what you’d typically do is bump the version numbers wherever necessary, committing those changes and then adding a tag to that specific point in time. To create a tag, you’d usually run something like this:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git tag -a v1.0 -m "First major version" +</code></pre></div></div> + +<p>The “-a” parameter indicates this is going to be an annotated tag. In contrast to a lightweight tag, this is a full-blown Git object, containing pieces of information such as the committer’s name and email, the timestamp, and a message. Now you have a tag, an indication that this particular point in history is special and has a name.</p> + +<p>Nice. You can continue doing work, as usual, creating and committing changes that will be part of the 1.1 version. Until a bug report comes in. Some clients that were updated to the 1.0 version of the product say an import feature isn’t working as intended.</p> + +<p>Well, you could theoretically fix the bug in the <code class="language-plaintext highlighter-rouge">main</code> branch and deploy it. But then the clients would receive features that are potentially untested and incomplete. That’s a no-no. So what do you do? The answer: You create a new branch from the tag you’ve created to indicate the major version. You fix the issue there, build, and deploy. And you should probably merge this back to <code class="language-plaintext highlighter-rouge">main</code> afterward, so the next releases contain the fix. How would you go about that? Easy:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch &lt;NAME-OF-THE-BRANCH&gt; &lt;TAG&gt; +</code></pre></div></div> + +<p>More specifically, using our previous example:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch fix-bug-123 v1.0 +</code></pre></div></div> + +<p>After that, you can check out your new branch as usual. Or better yet, you could do it all in one step:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout -b fix-bug-1234 v1.0 +</code></pre></div></div> + +<h2 id="creating-a-branch-in-detached-head-state">Creating a Branch in Detached Head State</h2> + +<p>Have you ever wished to go back in time? With Git this is possible…at least in regard to the files in our repository. You can, at any time, check out a commit if you know its hash:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout &lt;SHA1&gt; +</code></pre></div></div> + +<p>After running that, Git will show you a curious message:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You are in 'detached HEAD' state. You can look around, make experimental +changes and commit them, and you can discard any commits you make in this +state without impacting any branches by performing another checkout. +</code></pre></div></div> + +<p>When you check out a commit, you enter a special state called, as you can see, “<a href="https://www.cloudbees.com/blog/git-detached-head">detached HEAD</a>”. While you can commit changes in this state, those commits don’t belong to any branch and will become inaccessible as soon as you check out another branch. But what if you do want to keep those commits? The answer, unsurprisingly, is to use the <code class="language-plaintext highlighter-rouge">checkout</code> command again to create a new branch:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout &lt;sha1&gt; #now you're in detached head state +# do some work and stage it +git commit -m "add some work while in detached head state" +git branch new-branch-to-keep-commits +git checkout new-branch-to-keep-commits +</code></pre></div></div> + +<p>And of course, by now you know you can write the last two lines as a single command:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout -b new-branch-to-keep-commits +</code></pre></div></div> + +<p>Pretty easy, right?</p> + +<h2 id="just-because-you-candoesnt-mean-you-should">Just Because You Can…Doesn’t Mean You Should</h2> + +<p>Git’s branching model is one of its selling points. It turns what in other source control systems is a painful and even slow process into a breeze. One could say that Git has successfully democratized branching for the masses. But there lies a serious danger. Due to the cheapness of branching in Git, some developers might fall into the trap of working with <a href="https://rollout.io/blog/pitfalls-feature-branching/">extremely long-lived branches</a> or employing workflows or branching models that delay integration.</p> + +<p>We, as an industry, have been there. We’ve done that. It doesn’t work. Instead, embrace workflows that employ extremely short-lived branches. You’ll have a secure sandbox in which to code without fear of breaking stuff or wasting your coworkers’ time. But does that have you asking, “How do I deploy code with partially completed features?” <a href="https://rollout.io/blog/ultimate-feature-flag-guide/">In that case, it’s feature flags to the rescue</a>.</p> + +<p>Git branches are a powerful tool. Use them wisely, and don’t abuse them. And when they’re not enough, employ <a href="https://rollout.io/blog/continuous-integration-continuous-delivery-continuous-deployment/">continuous delivery/continuous integration</a> along with feature flags—including <a href="https://rollout.io/product/">specialized tools</a> at <a href="https://rollout.io/blog/5-tools-continuous-deployment/">your disposal</a>—so your applications can get to the next level.</p> + + Wed, 21 Feb 2024 00:00:00 +0000 + https://carlosschults.net/en/git-create-branch + https://carlosschults.net/en/git-create-branch + + git + + tutorial + + + + + + The LINQ Join Operator: A Complete Tutorial + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1617641333/reduce-cyclomatic-complexity/reduce-cyclomatic-complexity-1038x437.jpg" alt="" /></p> + +<p><em>Editorial note: I originally wrote this post for the Stackify blog. You can <a href="https://stackify.com/the-linq-join-operator-a-complete-tutorial/">check out the original here, at their site</a>.</em></p> + +<p>I think most C# developers would agree that LINQ is an integral part of the experience of writing code with the language. LINQ provides a fluent, intuitive, and consistent way to query data sets. In this post, we’ll help in your LINQ-mastering quest by covering the LINQ join operator.</p> + +<p>We’ll start the post with a definition of LINQ itself, so we’re all on the same page. After that, you’ll see an explanation of join operations in LINQ. Then, it’s time to roll up your sleeves and get practical with our hands-on guide to the join operator.</p> + +<p>Let’s get started.</p> + +<h2 id="what-is-linq">What is LINQ?</h2> + +<p><a href="https://learn.microsoft.com/en-us/dotnet/csharp/linq/">LINQ</a> stands for Language Integrated Query. It’s a C# feature that offers a unique and consistent syntax for querying datasets, regardless of their origin. The main benefit of LINQ is that you can use the same syntax to query data in memory, from a database, XML files, and so on.</p> + +<p>LINQ is available in two different flavors, the query syntax and the method syntax.</p> + +<p>The query syntax leverages special keywords to create a syntax that is familiar to anyone who’s worked with SQL. Here’s an example that queries a sequence of numbers, filtering the ones greater than 5:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">int</span><span class="p">[]</span> <span class="n">numbers</span> <span class="p">=</span> <span class="p">{</span> <span class="m">2</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">9</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">5</span> <span class="p">};</span> +<span class="kt">var</span> <span class="n">largerThanFive</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">num</span> <span class="k">in</span> <span class="n">numbers</span> + <span class="k">where</span> <span class="n">num</span> <span class="p">&gt;</span> <span class="m">5</span> + <span class="k">select</span> <span class="n">num</span><span class="p">;</span></code></pre></figure> + +<p>The method syntax allows you to use extension methods to perform the same query:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">int</span><span class="p">[]</span> <span class="n">numbers</span> <span class="p">=</span> <span class="p">{</span> <span class="m">2</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">9</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">5</span> <span class="p">};</span> +<span class="kt">var</span> <span class="n">largerThanFive</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span> <span class="p">&gt;</span> <span class="m">5</span><span class="p">);</span></code></pre></figure> + +<h2 id="what-is-the-linq-join-operator">What is The LINQ Join Operator?</h2> + +<p>When working with data, a common scenario is having two data sources that you want to combine based on some criteria. For instance, you might have a Books table and an Authors table in your database, with a one-to-many relationship between them—i.e., an author can author many books, but each book has only one author. If you need to compile a list of books containing their author’s name, you’d need to perform a join in order to match each line from the Books table to its counterpart in the Authors table.</p> + +<p>A join in LINQ is essentially the same: an operation where you can merge two collections according to some criteria you define.</p> + +<h2 id="the-linq-join-operator-in-practice-">The LINQ Join Operator in Practice-</h2> + +<p>Examples always make things clearer. So, let’s see how to use the join operator in practice.</p> + +<h3 id="starting-with-a-problem"><strong>Starting With a Problem</strong></h3> + +<p>Let’s say you have an e-commerce application with some data on categories:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Electronics</td> + </tr> + <tr> + <td>4</td> + <td>Toys</td> + </tr> + <tr> + <td>5</td> + <td>Stationery</td> + </tr> + <tr> + <td>7</td> + <td>Books</td> + </tr> + <tr> + <td>10</td> + <td>Clothes</td> + </tr> + </tbody> +</table> + +<p>Okay, now let’s have some products:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Category_Id</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Amazon Kindle</td> + <td>1</td> + </tr> + <tr> + <td>2</td> + <td>Refactoring</td> + <td>7</td> + </tr> + <tr> + <td>3</td> + <td>C# in Depth</td> + <td>7</td> + </tr> + <tr> + <td>4</td> + <td>Legal Pad 50 sheets</td> + <td>5</td> + </tr> + </tbody> +</table> + +<p>You can see where this is leading, right? The next thing you’d want to do is to produce a single collection, having the list of products and the names of the categories they belong to. In other words, a view like this:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Category</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Amazon Kindle</td> + <td>Electronics</td> + </tr> + <tr> + <td>2</td> + <td>Refactoring</td> + <td>Books</td> + </tr> + <tr> + <td>3</td> + <td>C# in Depth</td> + <td>Books</td> + </tr> + <tr> + <td>4</td> + <td>Legal Pad 50 sheets</td> + <td>Stationery</td> + </tr> + </tbody> +</table> + +<h3 id="solving-the-problem-performing-a-linq-inner-join">Solving The Problem: Performing a LINQ Inner Join</h3> + +<p>What would that operation look like in code? First of all, we need code to represent our categories and products. Thanks to C#’s record feature, two lines of code suffice for that:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="n">record</span> <span class="nf">Product</span><span class="p">(</span><span class="kt">int</span> <span class="n">Id</span><span class="p">,</span> <span class="kt">string</span> <span class="n">Name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">CategoryId</span><span class="p">);</span> +<span class="k">public</span> <span class="n">record</span> <span class="nf">Category</span><span class="p">(</span><span class="kt">int</span> <span class="n">Id</span><span class="p">,</span> <span class="kt">string</span> <span class="n">Name</span><span class="p">);</span></code></pre></figure> + +<p>Now, let’s have a list of each type:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">categories</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Category</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Electronics"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Toys"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Stationery"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">7</span><span class="p">,</span> <span class="s">"Books"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="s">"Clothes"</span><span class="p">)</span> +<span class="p">};</span> + +<span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Amazon Kindle"</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="s">"Refactoring"</span><span class="p">,</span> <span class="m">7</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="s">"C# In Depth"</span><span class="p">,</span> <span class="m">7</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Legal Pad 50 Sheets"</span><span class="p">,</span> <span class="m">5</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Surgical Gloves"</span><span class="p">,</span> <span class="m">12</span><span class="p">)</span> +<span class="p">};</span></code></pre></figure> + +<p>As you can see, the list of products has an additional product (surgical gloves) whose category id doesn’t match any of the available categories. Keep this in mind; it’ll be relevant in a moment.</p> + +<p>Now, let’s write code to perform this join. I’ll show the code in one go and then explain it:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span> + +<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">line</span> <span class="k">in</span> <span class="n">query</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">line</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>Now, the explanation:</p> + +<ul> + <li><strong>from p in products</strong> -&gt; we’re defining the origin of one of our data sources</li> + <li><strong>join c in categories</strong> -&gt; Here, we’re saying that we want to join the previous collection with this one</li> + <li><strong>on p.CategoryId equals c.Id</strong> -&gt; This is the condition for the join: the CategoryId on each product should match the Id of a category</li> + <li><strong>select new…</strong> -&gt; Here, we’re leveraging C#’s anonymous objects feature to create a new object on the fly, which has the properties we want</li> +</ul> + +<p>The result of this query is an <code class="language-plaintext highlighter-rouge">IEnumerable</code> of our anonymous object. We then iterate through each item of this collection, displaying it on the console. This is the result: +`</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ Id = 1, Name = Amazon Kindle, Category = Electronics } +{ Id = 2, Name = Refactoring, Category = Books } +{ Id = 3, Name = C# In Depth, Category = Books } +{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery } +</code></pre></div></div> + +<p>Those of you who remember your databases will notice that the LINQ join we performed is the equivalent of an inner join in SQL. In other words, only items that have a match are returned. In SQL, the equivalent query would look like this:</p> + +<figure class="highlight"><pre><code class="language-sql" data-lang="sql"><span class="k">SELECT</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> <span class="k">c</span><span class="p">.</span><span class="n">Name</span> <span class="k">AS</span> <span class="n">Category</span> +<span class="k">FROM</span> <span class="n">products</span> <span class="k">AS</span> <span class="n">p</span> +<span class="k">JOIN</span> <span class="n">categories</span> <span class="k">AS</span> <span class="k">c</span> <span class="k">ON</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="o">=</span> <span class="k">c</span><span class="p">.</span><span class="n">Id</span></code></pre></figure> + +<h3 id="performing-a-linq-outer-join">Performing a LINQ Outer Join</h3> + +<p>What if you wanted to perform the equivalent of a SQL outer join? That is, you want to retrieve all products, even the ones that don’t match any category. How to go about that?</p> + +<p>Here’s the updated query:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> <span class="k">into</span> <span class="n">joinedCategories</span> + <span class="k">from</span> <span class="n">c</span> <span class="k">in</span> <span class="n">joinedCategories</span><span class="p">.</span><span class="nf">DefaultIfEmpty</span><span class="p">()</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">?.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>  It looks similar, but there are two differences:</p> + +<ul> + <li><strong>on p.CategoryId equals c.Id into joinedCategories</strong> -&gt; here, after joining products with categories, we send the result, as a grouped sequence, to the <strong>joinedCategories</strong> range variable</li> + <li><strong>from c in joinedCategories.DefaultIfEmpty()</strong> -&gt; Then, we retrieve items from the groupedSequence, using the DefaultIfEmpty() method to return the default value when no matches are found</li> + <li><strong>Category = c?.Name</strong> -&gt; Finally, when assigning the category name to the Category property on our anonymous object, we have to use the null-conditional operator in order to avoid a null-reference exception (since the default value for Category is null because it’s a <a href="https://carlosschults.net/en/value-reference-types-in-csharp/">reference type</a>.)</li> +</ul> + +<p>The result is now different:</p> + +<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Amazon</span><span class="w"> </span><span class="err">Kindle</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Electronics</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Refactoring</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Books</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">C#</span><span class="w"> </span><span class="err">In</span><span class="w"> </span><span class="err">Depth</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Books</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Legal</span><span class="w"> </span><span class="err">Pad</span><span class="w"> </span><span class="mi">50</span><span class="w"> </span><span class="err">Sheets</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Stationery</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Surgical</span><span class="w"> </span><span class="err">Gloves</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="p">}</span></code></pre></figure> + +<p>As you can see, the “Surgical Gloves” product now appears, even if it doesn’t have a matching category.</p> + +<h3 id="linq-inner-join-with-where-condition">LINQ Inner Join With Where Condition</h3> + +<p>Performing a join with a where clause is quite easy. In this example, we’ll perform an inner join, filtering only the products whose id are equal to or greater than 3:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">where</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span> <span class="p">&gt;=</span> <span class="m">3</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<h3 id="linq-inner-join-with-multiple-conditions">LINQ Inner Join With Multiple Conditions</h3> + +<p>If you want to use multiple conditions within your join, you can simply use more than one where clause. Let’s update our query once again:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">where</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span> <span class="p">&gt;=</span> <span class="m">3</span> + <span class="k">where</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">EndsWith</span><span class="p">(</span><span class="sc">'s'</span><span class="p">)</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>Here, we’re filtering only categories whose names end with the letter s.</p> + +<h3 id="linq-join-with-composite-key">LINQ Join With Composite Key</h3> + +<p>Up until now, all of our examples have used single keys to perform the matching. You can also use composite keys—that is, more than one value—for the matching.</p> + +<p>Suppose both our Product and Category classes gained a new property called Status, which is an enum that can vary between three states: Pending, Active, and Archived. Now, the Status property also needs to be used for the match.</p> + +<p>All of our products are active, but not all of the categories:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">categories</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Category</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Electronics"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Toys"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Stationery"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Archived</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">7</span><span class="p">,</span> <span class="s">"Books"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Pending</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="s">"Clothes"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">)</span> +<span class="p">};</span> + +<span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Amazon Kindle"</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="s">"Refactoring"</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="s">"C# In Depth"</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Legal Pad 50 Sheets"</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Surgical Gloves"</span><span class="p">,</span> <span class="m">12</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">)</span> +<span class="p">};</span></code></pre></figure> + +<p>This is what our updated query looks like now:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span><span class="p">,</span> <span class="n">Status</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Status</span> <span class="p">}</span> + <span class="k">equals</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> <span class="n">Status</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Status</span> <span class="p">}</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>It’s not much more complicated than before. The difference is that now, we use an anonymous object to perform the comparison using both the id and the status properties.</p> + +<p>A single result is displayed from this query:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">Name</span> <span class="p">=</span> <span class="n">Amazon</span> <span class="n">Kindle</span><span class="p">,</span> <span class="n">Category</span> <span class="p">=</span> <span class="n">Electronics</span> <span class="p">}</span></code></pre></figure> + +<h2 id="conclusion">Conclusion</h2> + +<p>As we’ve seen, LINQ is an essential part of working with C#. You can leverage LINQ in many different scenarios, from working with data in memory to XML to SQL. You can use LINQ in ORMs such as <a href="https://stackify.com/entity-framework-core-nhibernate/">NHibernate and Entity Framework.</a></p> + +<p>Teams that wish to make their LINQ experiences even better can use the tools at their disposal. For instance, <a href="https://stackify.com/prefix/">Stackify’s Prefix</a> and <a href="https://stackify.com/retrace-code-profiling/">Retrace</a> offer powerful capabilities of tracing, profiling, and centralizing logging that helps teams inspect their code to find opportunities for performance improvements, which includes LINQ queries.</p> + + Tue, 06 Feb 2024 00:00:00 +0000 + https://carlosschults.net/en/linq-join-operator + https://carlosschults.net/en/linq-join-operator + + csharp + + linq + + dotnet + + + + + + Git Bisect: An Introduction To Beginners + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><span>Photo by <a href="https://unsplash.com/@yancymin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yancy Min</a> on <a href="https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p>If you’re trying to level up your <em>git-fu</em>, you could do worse than learn the <code class="language-plaintext highlighter-rouge">git bisect</code> command. Git has its (un)fair share of complicated commands, that’s true. The good news is that, unlike those, <code class="language-plaintext highlighter-rouge">git bisect</code> is quite easy to understand and use. The even better news is that it’s super useful to help you fix bugs.</p> + +<h2 id="prerequisites">Prerequisites</h2> + +<p>Before getting started, let’s review some prerequisites you’ll need to follow along with the post:</p> +<ul> + <li>Having git installed on your machine</li> + <li>Knowing at least the basic git commands</li> + <li>Having Node.js installed on your machine (later on you’ll use a sample application provided by me, and it’s written in JavaScript.)</li> +</ul> + +<p>Have all that? Great, let’s move on.</p> + +<h2 id="whats-git-bisect-why-do-you-need-it">What’s Git Bisect? Why Do You Need It?</h2> + +<p><code class="language-plaintext highlighter-rouge">Git bisect</code> is a command that enables you to perform a binary search on your commit history. Why do that?</p> + +<p>Here’s a common scenario during development. Someone reports a bug. You go see it and find out that, two weeks ago, the feature was working just fine.</p> + +<p>To fix the bug, it’d be useful to find out when exactly it was introduced to the codebase. Since you know one commit that you’re sure to be “good”—that is, it doesn’t contain the bug—you could <code class="language-plaintext highlighter-rouge">git checkout</code> your way there, going back one commit at a time and testing to see if the application works.</p> + +<p>That’s bound to work, but it could potentially take a long time, depending on the number of commits you’d have to check and where the problem is. For those who remember your Computer Science classes, the approach described above is a <a href="https://en.wikipedia.org/wiki/Linear_search">linear search</a>, which isn’t the most optimal way to search for a value within a list.</p> + +<p>Do you know what’s more efficient? A binary search. If you have, say, 50 commits you need to check, and you test the 25th one and don’t find the bug, what does that mean? You can disregard the first 25 commits and continue your search within the 25 later ones. Continue the process, always partioning by half, and you’ll find the faulty one in way fewer checks than would be necessary with a linear search.</p> + +<p>Doing this by hand would be super boring, though. And that’s where <code class="language-plaintext highlighter-rouge">git bisect</code> comes in handy. It has an easy syntax that allows you to specify both a good and a bad commit, and then git will perform the binary partitions on your behalf. At each step, you’ll have to test your application and inform git whether that commit is a bad or a good one. Then, git calculates the next step, takes you there, and the process ends when you find the culprit.</p> + +<h2 id="how-to-use-git-bisect-in-practice">How To Use <code class="language-plaintext highlighter-rouge">Git Bisect</code> In Practice?</h2> + +<p>Time to learn how to use <code class="language-plaintext highlighter-rouge">git bisect</code> in a hands-on approach. To practice this command, you need a repo with at least some commits, and that has a bug. It’d take a while for you to set up a repository like this, so I already made one for you—yes, I’m nice like that.</p> + +<h3 id="getting-the-sample-application">Getting The Sample Application</h3> +<p>Just <a href="https://github.com/carlosschults/git-bisect-intro">clone this GitHub repo</a> and you’re good to go.</p> + +<p>The repo contains a silly toy JavaScript application that implements some rules from the <a href="https://osherove.com/tdd-kata-1">String Calculator Kata by Roy Osherov</a>. Here’s what the application is supposed to do:</p> +<ul> + <li>after running it, the application will prompt you for a list of numbers, separated by comma;</li> + <li>you provide the numbers;</li> + <li>the sum of the numbers is displayed.</li> + <li>numbers larger than 1000 are ignored. So, the string “1,2,1000” should yield the result 1003, but “1,2,1001” should result in 3.</li> + <li>negative numbers shouldn’t be allowed. If you enter one or more negative numbers, the application should throw an error with the message “Negatives not allowed”, followed by the negative numbers that were inputted.</li> +</ul> + +<p>After cloning the repository, let’s test the app. Access its folder via the command line, run <code class="language-plaintext highlighter-rouge">node index.js</code> and, when prompted for the numbers, enter “1,2,3” and press enter.</p> + +<p>Oops.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: . + at C:\repos\git-bisect-intro\index.js:11:11 + at [_onLine] [as _onLine] (node:internal/readline/interface:423:7) + at [_line] [as _line] (node:internal/readline/interface:886:18) + at [_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1264:22) + at ReadStream.onkeypress (node:internal/readline/interface:273:20) + at ReadStream.emit (node:events:513:28) + at emitKeys (node:internal/readline/utils:357:14) + at emitKeys.next (&lt;anonymous&gt;) + at ReadStream.onData (node:internal/readline/emitKeypressEvents:64:36) + at ReadStream.emit (node:events:513:28) + +Node.js v18.12.1 +</code></pre></div></div> +<p>The app doesn’t work. It throws the “negatives not allowed” error even if no negatives were entered. If you want to see the app working, I made things easier for you: I created a tag called <code class="language-plaintext highlighter-rouge">good-commit</code> that references a point in the history guaranteed to be good. Just go there and check it:</p> + +<p><code class="language-plaintext highlighter-rouge">git checkout good-commit</code></p> + +<p>After running the command above, it’s possible you’ll see some messages about <a href="https://www.cloudbees.com/blog/git-detached-head">detached HEAD</a> and stuff. Just ignore those. Run the application again, and <em>voilá</em>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> + +<p>Ok, let’s now test the numbers-larger-than-1000-should-be-ignored rule:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,1000, 1001 +The sum of the entered numbers is 1003. +</code></pre></div></div> + +<p>Nice! As expected, the number 1000 is considered but 1001 is ignored. For a final test, let’s verify the negative numbers prohibition:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3,-5,-4,-7 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -4, -7. +</code></pre></div></div> + +<p>Sweet. Now, for the next step. But first, run <code class="language-plaintext highlighter-rouge">git checkout main</code> to return to the latest commit.</p> + +<h3 id="time-to-roll-up-your-sleeves">Time To Roll-Up Your Sleeves</h3> +<p>To start using the <code class="language-plaintext highlighter-rouge">git bisect</code> command, you need to begin a <em>bisect session</em>. You do this by simply running <code class="language-plaintext highlighter-rouge">git bisect start</code>. You’ll then see the following message:</p> + +<p><code class="language-plaintext highlighter-rouge">status: waiting for both good and bad commits</code></p> + +<p>Now, you have to tell git about a commit that’s known to be “good”—i.e. not contain the bug—and one commit that does contain the bug. Let’s start with the good one:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect good good-commit</code></p> + +<p>As I said before, I created a tag to point to a known good commit to make things easier for you. But you’re not restricted to tags when it comes to pointing to a commit for a bisecting session. Branch names will also work, as commit SHAs and pretty much any references that resolve to a commit.</p> + +<p>Anyway, after running the command, you’ll see this: +<code class="language-plaintext highlighter-rouge">status: waiting for bad commit, 1 good commit known</code></p> + +<p>Now it’s time to point to a bad commit. I’m sure you’re able to guess the syntax now: <code class="language-plaintext highlighter-rouge">git bisect bad &lt;REFERENCE-TO-COMMIT&gt;</code>. But since the commit we’re at—in other words, the tip of <code class="language-plaintext highlighter-rouge">main</code>—is known to be bad, you can simply run:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect bad</code></p> + +<p>Now the fun begins! Git will display a message, showing you the status of the bisecting operation. It’ll tell you how many revisions are left to test , and how many steps that would take, and to which commit it has “transported” you:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 11 revisions left to test after this (roughly 4 steps) +[e159647d4d142c410894aaf10c1e11e2208848d7] Edit to negative rule +</code></pre></div></div> + +<p>Your job now is to test the application and tell git whether that’s a good or bad commit. So, let’s run <code class="language-plaintext highlighter-rouge">node index.js</code> and provide some numbers:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: . +</code></pre></div></div> + +<p>I’ve cut some of the output for brevity, but anyway: the app’s not working. So, tell git that:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect bad</code></p> + +<p>It takes you to a different commit:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 5 revisions left to test after this (roughly 3 steps) +[0b8f71999bed054d8a95d9da3be6f0c831074cd7] Update README.md - Commit 6 +</code></pre></div></div> + +<p>Let’s repeat the test with <code class="language-plaintext highlighter-rouge">node index.js</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> + +<p>Awesome! At this commit, the app seems to work fine. Let’s do a different test, using negative numbers:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3,-5,-4,-10 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -4, -10. +</code></pre></div></div> + +<p>Perfect: it’s throwing an error, as it’s supposed to do in this scenario. So, run <code class="language-plaintext highlighter-rouge">git bisect good</code> to mark this commit as good.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 2 revisions left to test after this (roughly 2 steps) +[e6413a915c7ca92871394b01a8497c8df3fc46ae] Update README.md - Commit 9 +</code></pre></div></div> + +<p>Yet another commit, yet another test:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> +<p>Let’s test the negatives:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +10,20,-5 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5. +</code></pre></div></div> + +<p>Everything looks fine, let’s mark it as good: +<code class="language-plaintext highlighter-rouge">git bisect good</code></p> + +<p>And the result:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 0 revisions left to test after this (roughly 1 step) +[053207649aefdb09cd255567df673cadbe2e38e3] Restore README +</code></pre></div></div> + +<p>We’re getting close! Let’s test:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. + +node index.js +Enter a list of numbers separated by comma: +1,2,3,-5,-6 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -6. +</code></pre></div></div> + +<p>Marking it as good: <code class="language-plaintext highlighter-rouge">git bisect good</code>. And, <em>voilà</em>, here’s our answer:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e159647d4d142c410894aaf10c1e11e2208848d7 is the first bad commit +commit e159647d4d142c410894aaf10c1e11e2208848d7 +Author: Carlos Schults &lt;carlos.schults@gmail.com&gt; +Date: Tue Jan 9 08:53:47 2024 -0300 + + Edit to negative rule + + index.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +</code></pre></div></div> + +<h3 id="what-now">What Now?</h3> +<p>Ok, now you know that the commit <code class="language-plaintext highlighter-rouge">e159647d4d142c410894aaf10c1e11e2208848d7</code> is the one that introduced the bug. What should you do now?</p> + +<p>In short, you need to see details of this commit, to learn what changes it makes so you can understand what caused the problem. Let’s use the <code class="language-plaintext highlighter-rouge">git show</code> command for that:</p> + +<p><code class="language-plaintext highlighter-rouge">git show e159647d4d142c410894aaf10c1e11e2208848d7</code></p> + +<p>This command will output several things about the commit, including author, date, and message. I’ll reproduce only the part I’m interested in, which is the diff:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diff --git a/index.js b/index.js +index 5f351e0..4e65e0c 100644 +--- a/index.js ++++ b/index.js +@@ -6,7 +6,7 @@ const readline = require('readline').createInterface({ + readline.question('Enter a list of numbers separated by comma:\n', numbers =&gt; { + let integers = numbers.split(',').map(x =&gt; parseInt(x) || 0); + let negatives = integers.filter(x =&gt; x &lt; 0); +- if (negatives.length &gt; 0) { ++ if (negatives.length &gt;= 0) { + throw new Error(`Negatives not allowed: ${negatives.join(', ')}.`); + } +</code></pre></div></div> + +<p>And now as an image, so you can see the colors:</p> + +<p><img src="/img/diff.png" alt="" /></p> + +<p>As you can see, this commit made a change to the <code class="language-plaintext highlighter-rouge">if</code> statement that tests for negative numbers, adding an equals sign to the comparison. That way, the error will be thrown regardless of whether the <code class="language-plaintext highlighter-rouge">negatives</code> array has elements.</p> + +<p>Now that you know how the bug was introduced, it’s super easy to fix it. To end the bisect session, just run <code class="language-plaintext highlighter-rouge">git bisect reset</code>. That way, you’ll be back to the point in which you originally started.</p> + +<h2 id="a-note-about-good-and-bad">A Note About “Good” and “Bad”</h2> + +<p>Astute readers will have noticed that, although this command uses terms like “goo”,’ “bad,” and “bug,” there’s nothing stopping you from using <code class="language-plaintext highlighter-rouge">git bisect</code> to find out the point in time at which any property of the codebase has changed. After all, Git can’t know how your application is supposed to work; it was you, the whole time, who was testing it.</p> + +<p>Even the <a href="https://git-scm.com/docs/git-bisect#_alternate_terms">documentation for the command</a> acknowledges this fact:</p> + +<blockquote> + <p>Sometimes you are not looking for the commit that introduced a breakage, but rather for a commit that caused a change between some other “old” state and “new” state. +For example, you might be looking for the commit that introduced a particular fix. Or you might be looking for the first commit in which the source-code filenames were finally all converted to your company’s naming standard. Or whatever.</p> +</blockquote> + +<p>In such a scenario, it’d be weird to use the terms “good” and “bad”. The good news is that you can use “new” and “old” instead: the <em>new</em> commit is one that contains the property you’re looking after, and the <em>old</em> doesn’t contain such property.</p> + +<p>To use this terminology, just start a bisecting session as usual, and then run <code class="language-plaintext highlighter-rouge">git bisect old &lt;COMMIT&gt;</code> to indicate the old commit, and <code class="language-plaintext highlighter-rouge">git bisect new &lt;COMMIT</code> to indicate the new one.</p> + +<p>Keep in mind that you can either use good/bad or old/new, but not mix the two. At any point during a session, you can run <code class="language-plaintext highlighter-rouge">git bisect terms</code> to be reminded of the terms you’re using.</p> + +<p>The command is even more flexible than that: you can pick your own terms! Just start a session by running the following:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect start --term-old &lt;term-old&gt; --term-new &lt;term-new&gt;</code></p> + +<h2 id="git-bisect-where-do-you-go-now">Git Bisect: Where Do You Go Now?</h2> + +<p>I know this is only anecdotal data but, from my observations, I’d say that <code class="language-plaintext highlighter-rouge">git bisect</code> is an underused command. Which is pretty sad, considering that <code class="language-plaintext highlighter-rouge">git bisect</code> is a)incredibly useful and b)easy to understand and use, at least in its most basic use case.</p> + +<p>If you’re already comfortable with the most common git commands — i.e. <code class="language-plaintext highlighter-rouge">status</code>, <code class="language-plaintext highlighter-rouge">log</code>, <code class="language-plaintext highlighter-rouge">commit</code>, <code class="language-plaintext highlighter-rouge">add</code>, <code class="language-plaintext highlighter-rouge">pull</code>, <code class="language-plaintext highlighter-rouge">push</code>, <code class="language-plaintext highlighter-rouge">checkout</code> — and want to go one step higher, learning <code class="language-plaintext highlighter-rouge">git bisect</code> is a great place for you to start.</p> + +<p>So, you’ve learned the basics of this command with the introduction I wrote. Awesome, but where should you go from here? I’ve got a few suggestions:</p> + +<ul> + <li>Put it into practice ASAP. Even if you’re not bug-hunting right now, come up with <em>some</em> characteristic of your application and find the commit in which it was introduced using <code class="language-plaintext highlighter-rouge">git bisect</code>.</li> + <li>Dive depeer into the command and look for more advanced use cases. For instance, it’s possible to <a href="https://dev.to/emilysamp/how-to-run-an-automated-git-bisect-with-rspec-3dm3">automate <code class="language-plaintext highlighter-rouge">git bisect</code></a> so you don’t even have to manually test in order to triage the good commits from the bad ones!</li> + <li>Read the <a href="https://git-scm.com/docs/git-bisect">documentation</a> for <code class="language-plaintext highlighter-rouge">git bisect</code>. Keep going back to it from time to time, and you’re bound to learn something new and useful.</li> +</ul> + +<p>That’s it for this post. I hope you like it, and I really appreciate any feedback. Thanks for reading!</p> + + Mon, 22 Jan 2024 00:00:00 +0000 + https://carlosschults.net/git-bisect-intro/ + https://carlosschults.net/git-bisect-intro/ + + git + + + + + + The 5 Levels of Readable Code + <p><img src="/img/levels.jpg" alt="" /></p> + +<p><span>Photo by <a href="https://unsplash.com/@greysonjoralemon?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Greyson Joralemon</a> on <a href="https://unsplash.com/photos/w000nNe9Xq8?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></span></p> + +<p>Recently I’ve been thinking a lot about code readability. What does it mean for a piece of code to be readable? Is it possible to define readability objectively? Should we attempt to do it?</p> + +<p>These are some of the questions I’ve been thinking about, and in this post, I present my answers in an attempt to start a conversation around readability.</p> + +<p>Here’s the TL;DR version: yes, I believe objectively defining code readability is both possible and desirable, and in this article, I suggest a model for evaluating readability.</p> + +<h2 id="the-importance-of-a-code-readability-definition">The Importance of a Code Readability Definition</h2> + +<p>Readability will always be somewhat subjective and, to some degree, that subjectivity is harmless. However, it <em>can</em> cause problems in some scenarios.</p> + +<p>If we’re working within a team, it’s important to come up with at least some objective guidelines regarding code readability, and that’s because of code reviews. If the team can’t agree on what constitutes readable code, then code review feedback will feel like arbitrary whims.</p> + +<p>In short: teams need conventions. A team should have a vision when it comes to what constitutes good, readable code.</p> + +<h2 id="a-framework-for-thinking-about-code-readability-levels">A Framework For Thinking About Code Readability: Levels</h2> + +<p>Not long ago I started thinking about code readability in terms of levels. The levels represent specific concerns regarding readability, and they’re ordered in terms of priority.</p> + +<p>So, level 1 represents the most basic stuff you’ve got to take care of first, before progressing towards higher levels. Tidy up the basics, then go for the advanced stuff. Something like <a href="https://en.wikipedia.org/wiki/Maslow%27s_hierarchy_of_needs">Maslow’s hierarchy of needs</a>, but for code.</p> + +<p>There will be some code examples, and I’ll be using C# for those. However, what I’ll show here applies to any language, unless I explicitly say otherwise.</p> + +<p>Without further ado, here are the five levels of readable code.</p> + +<h2 id="level-1-your-code-does-the-bare-minimum">Level 1: Your Code Does The Bare Minimum</h2> + +<p>(Yes, level one. Please spare me that “programmers start counting at zero” nonsense.)</p> + +<p>Level 1 of readable code refers to code that does the bare minimum. Think of simple readability guidelines such as:</p> + +<ul> + <li>Picking <a href="https://carlosschults.net/en/how-to-choose-good-names/">descriptive names </a>for variables, functions, classes, and so on.</li> + <li>Avoiding too many indentation levels.</li> + <li>Keeping <a href="https://carlosschults.net/en/reduce-cyclomatic-complexity/">cyclomatic complexity low.</a></li> + <li>Avoiding <a href="https://carlosschults.net/en/types-of-comments-to-avoid/">comments that don’t bring any value</a>.</li> + <li>Keeping <a href="https://blog.ploeh.dk/2019/11/04/the-80-24-rule/">functions and other blocks of code small.</a></li> + <li>Avoiding <a href="https://en.wikipedia.org/wiki/Magic_number_(programming)">magic numbers</a>.</li> +</ul> + +<p>It’s not hard to learn these kinds of best practices. You can pick up most of these through sheer experience, by listening to the feedback of more experienced engineers during code reviews, or by reading books and even blog posts like the ones listed above.</p> + +<h2 id="level-2-your-code-is-idiomatic">Level 2: Your Code Is Idiomatic</h2> + +<p>Consider the following C# class:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span> +<span class="p">{</span> + <span class="k">private</span> <span class="kt">string</span> <span class="n">_name</span><span class="p">;</span> + <span class="k">private</span> <span class="kt">int</span> <span class="n">_age</span><span class="p">;</span> + + <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span> + <span class="n">_age</span> <span class="p">=</span> <span class="n">age</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">SetName</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetName</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_name</span><span class="p">;</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">SetAge</span><span class="p">(</span><span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_age</span> <span class="p">=</span> <span class="n">age</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">int</span> <span class="n">GetAge</span> <span class="p">=&gt;</span> <span class="n">_age</span><span class="p">;</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>There’s nothing wrong with the above class, at least not technically. The compiler happily compiles it, and the class works as it should.</p> + +<p>However, if you’re at least somewhat experienced with C#, you noticed something weird when you saw the code: the getter and setter methods. The C# development team made the concepts of getters and setters a first-class citizen of the language early on, via the concept of properties. If there’s no additional logic involved in the setting and getting of values, the programmer can make usage of <a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties">auto-implemented properties</a> with a concise result (even the backing private fields no longer need to be explicitly declared):</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span> +<span class="p">{</span> + <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span> + <span class="n">Age</span> <span class="p">=</span> <span class="n">age</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">int</span> <span class="n">Age</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>All of this is to say: that to be readable, a given piece of code needs to be idiomatic to the language it’s written into. If you’re writing C#, follow the coding standards and conventions of the language. The same applies to Java, JavaScript, and any other language.</p> + +<p>The Python community has a wonderful concept to describe Python code that adheres to the standards and philosophies of the language: “pythonic”. A piece of Python code might work, but if it’s not Pythonic, experienced Python engineers will find the code awkward to work with.</p> + +<p>Why does writing idiomatic code matter for readability? When you look at code—in whatever language—that doesn’t look like what it should look, according to the mental model you have of that language, it becomes harder to follow the code.</p> + +<p>Non-idiomatic code increases the <a href="https://linearb.io/blog/cognitive-complexity-in-software">cognitive complexity </a>of a code base. It makes it harder to onboard developers who are familiar with the language standards and idioms. If you have an open-source project, too many idiosyncrasies in the code might push away potential contributors.</p> + +<p>Of course, the opposite of all of this is true.</p> + +<h2 id="level-3-your-code-reveals-intent-via-tactical-use-of-typing">Level 3: Your Code Reveals Intent Via Tactical Use of Typing</h2> + +<p>As the title suggests, this item, unlike the previous two, only applies to statically typed languages—or, perhaps, dynamically typed ones that feature some kind of optional type annotation.</p> + +<p>Let’s start with a simple example. Look at the following lines:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Canvas</span><span class="p">.</span><span class="nf">DrawLine</span><span class="p">(</span><span class="m">5</span><span class="p">);</span> +</code></pre></div></div> + +<p>Disregard the magic number, which is itself already a problem. Consider that you know that the <code class="language-plaintext highlighter-rouge">DrawLine</code> method has a single parameter, <code class="language-plaintext highlighter-rouge">length</code>. The line could’ve been made slightly more readable through the usage of a <a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments">named argument,</a> but even that wouldn’t solve the biggest issue: what the heck is the unit of measurement?</p> + +<p>Besides harming readability, this problem opens up the possibility of bugs, due to a mismatch of units—a portion of the code “thinks” the unit is centimeters, while others might believe it’s inches.</p> + +<p>What am I advocating instead? Well, use typing to your favor. Here, a good solution would be to create a <a href="https://carlosschults.net/en/value-objects-tool/">value object </a>called, let’s say, <code class="language-plaintext highlighter-rouge">Length</code>. This type would have several static factory methods named after specific units of measurement, and its constructor would be private. Then, you’d be able to rewrite the previous example to something like this:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Canvas</span><span class="p">.</span><span class="nf">DrawLine</span><span class="p">(</span><span class="n">Length</span><span class="p">.</span><span class="nf">FromCentimeters</span><span class="p">(</span><span class="m">5</span><span class="p">));</span> +</code></pre></div></div> + +<p>Another example would be the usage of the <code class="language-plaintext highlighter-rouge">TimeSpan</code> type to express durations, instead of using primitive values or employing the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.uri?view=net-7.0">Uri class </a>instead of just strings.</p> + +<p>Maybe you’re thinking all of this is simply a convoluted way of saying “avoid primitive obsession.” There’s more to it than that, though.</p> + +<p>To illustrate my point, I’ll share another—maybe a bit contrived, I admit—example. Let’s say you’re solving a problem that calls for the usage of a <a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)">stack</a>. In this case, nothing is stopping you from using the <code class="language-plaintext highlighter-rouge">List&lt;T&gt;</code> class as a stack, right?</p> + +<ul> + <li>The <code class="language-plaintext highlighter-rouge">Add</code> method would be your replacement for the <code class="language-plaintext highlighter-rouge">push</code> functionality</li> + <li>For the <code class="language-plaintext highlighter-rouge">pop</code> functionality, you’d use a combination of getting the last element from the list via its indexer and then using the <code class="language-plaintext highlighter-rouge">RemoveAt</code> method to delete the item.</li> +</ul> + +<p>The above solution, despite being somewhat convoluted, would work. But I’d vehemently encourage you to just go and use the regular <code class="language-plaintext highlighter-rouge">Stack&lt;T&gt;</code> class. Using the more specific type would make the code immediately more readable to anyone who knows what a stack is. It would make the code reveal its intent.</p> + +<p>In short: unless you have a justifiable reason to not do so, always prefer the type that more closely represents the concept or functionality you need. It’ll not only make your code more robust but also more intention-revealing.</p> + +<h2 id="level-4-your-code-doesnt-mix-levels-of-abstraction">Level 4: Your Code Doesn’t Mix Levels of Abstraction</h2> + +<p>Your code shouldn’t mix more than one level of abstraction. Code that lives in the “Business Rules” portion of your codebase shouldn’t mess with code that lives in the “IO concerns” neighborhood, to give you an example.</p> + +<p>Why is this a problem? See the following function:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="kt">double</span> <span class="nf">CalculateAverageTemperature</span><span class="p">(</span><span class="kt">string</span> <span class="n">filePath</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">List</span><span class="p">&lt;</span><span class="n">ClimaticReading</span><span class="p">&gt;</span> <span class="n">readings</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> + + <span class="k">try</span> + <span class="p">{</span> + <span class="k">using</span> <span class="nn">var</span> <span class="n">reader</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StreamReader</span><span class="p">(</span><span class="n">filePath</span><span class="p">);</span> + <span class="k">while</span> <span class="p">(!</span><span class="n">reader</span><span class="p">.</span><span class="n">EndOfStream</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">line</span> <span class="p">=</span> <span class="n">reader</span><span class="p">.</span><span class="nf">ReadLine</span><span class="p">();</span> + <span class="kt">var</span> <span class="n">values</span> <span class="p">=</span> <span class="n">line</span><span class="p">?.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">)</span> <span class="p">??</span> <span class="n">Array</span><span class="p">.</span><span class="n">Empty</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;();</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">Length</span> <span class="p">&lt;</span> <span class="m">2</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">values</span><span class="p">[</span><span class="m">0</span><span class="p">],</span> <span class="k">out</span> <span class="n">DateTime</span> <span class="n">date</span><span class="p">)</span> <span class="p">&amp;&amp;</span> + <span class="kt">double</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span> + <span class="n">values</span><span class="p">[</span><span class="m">1</span><span class="p">],</span> + <span class="n">NumberStyles</span><span class="p">.</span><span class="n">Float</span><span class="p">,</span> + <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">,</span> + <span class="k">out</span> <span class="kt">double</span> <span class="n">temperature</span><span class="p">))</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">reading</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ClimaticReading</span> + <span class="p">{</span> + <span class="n">Date</span> <span class="p">=</span> <span class="n">date</span><span class="p">,</span> + <span class="n">Temperature</span> <span class="p">=</span> <span class="n">temperature</span> + <span class="p">};</span> + <span class="n">readings</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">reading</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="s">$"Error reading the CSV file: </span><span class="p">{</span><span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">readings</span><span class="p">.</span><span class="n">Count</span> <span class="p">&lt;</span> <span class="m">3</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="s">"There must be at least 3 readings to calculate the average."</span><span class="p">);</span> + <span class="p">}</span> + + <span class="n">readings</span> <span class="p">=</span> <span class="n">readings</span><span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">reading</span> <span class="p">=&gt;</span> <span class="n">reading</span><span class="p">.</span><span class="n">Temperature</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span> + + <span class="n">readings</span><span class="p">.</span><span class="nf">RemoveAt</span><span class="p">(</span><span class="m">0</span><span class="p">);</span> + <span class="n">readings</span><span class="p">.</span><span class="nf">RemoveAt</span><span class="p">(</span><span class="n">readings</span><span class="p">.</span><span class="n">Count</span> <span class="p">-</span> <span class="m">1</span><span class="p">);</span> + + <span class="kt">double</span> <span class="n">sum</span> <span class="p">=</span> <span class="n">readings</span><span class="p">.</span><span class="nf">Sum</span><span class="p">(</span><span class="n">reading</span> <span class="p">=&gt;</span> <span class="n">reading</span><span class="p">.</span><span class="n">Temperature</span><span class="p">);</span> + <span class="kt">double</span> <span class="n">average</span> <span class="p">=</span> <span class="n">sum</span> <span class="p">/</span> <span class="n">readings</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">average</span><span class="p">;</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>The function reads and parses a .CSV file containing climatic readings. Lines that don’t have the expected two values (date and temperature) are dismissed. Then it sorts the readings, removes the highest and lowest values, and, finally, calculates and returns the average of the remaining values.</p> + +<p>This function mixes at least two abstraction levels:</p> + +<ul> + <li>The “domain logic” level—i.e. the part that makes the calculation</li> + <li>The low level: reading and parsing the .CSV file.</li> +</ul> + +<p>You could even make the argument that there are three levels, since the low level could be split into two: file system manipulation and parsing.</p> + +<p>This example function isn’t the hardest thing in the world to read, but it’s certainly harder than it has to be. It mixes domain logic with IO error handling and even parsing. A better solution would be to have a method that gets a collection of <code class="language-plaintext highlighter-rouge">ClimaticReading</code> and calculates and returns the average.</p> + +<p>In other words, a better and more elegant solution would be to have a <strong>pure function</strong>. This new method, besides being more readable, would be more robust, less error-prone, and also deterministic—i.e. always returns the same results for the same input—making it intrinsically <a href="https://carlosschults.net/en/csharp-unit-testing-intro-tdd/">unit testable.</a></p> + +<h2 id="level-5-your-code-speaks-the-language-of-the-business">Level 5: Your Code Speaks The Language of The Business</h2> + +<p>You’ve reached level 5 when you write code that speaks the language of the business. When you use terms that are the same ones that domain experts use.</p> + +<p>In other words: yeah, I’m pretty much advocating for the same thing that the pragmatic programmers call “program closer to the domain”, or that Eric Evans famously dubbed ubiquitous language in his classical—but definitely not a page-turner—tome, “Domain-Driven Design: Tackling Complexity in the Heart of Software.”</p> + +<p>If your code uses unorthodox terms instead of industry terms, it makes onboarding harder when you bring in new people that are familiar with the business but new to the codebase. If the code uses different jargon than that of stakeholders, communication becomes more taxing, since it requires you to perform a constant mapping between concepts just to stay afloat.</p> + +<p>Level 5 is somewhat of a logical consequence of level 4. If you carefully segregate the concerns of your app, making sure that high level code doesn’t mix with low level code, the tendency is for the high level code to become closer and closer to the domain in terms of naming.</p> + +<h2 id="level-up-the-readability-of-your-code">Level Up The Readability of Your Code</h2> + +<p>Most programmers would agree that code readability is vital. But what about agreeing on what “readable code” looks like? That’s a horse of a different color.</p> + +<p>As I said earlier, I think a level of subjectivity when it comes to readability is both inevitable and harmless. However, in the context of a team, there has to be at least some consensus of what readable code is. Otherwise, code reviews become exercises of futility, and team morale sinks.</p> + +<p>I believe that our industry would benefit from a more objective way to reason about readability. In this post, I gave my small contribution, in the form of a readability “checklist”, in prioritized order.</p> + +<p>But again: the idea of this post isn’t to give a definitive answer, <strong>but to start a conversation</strong>. Do you think the “levels” models make no sense? Or maybe you’d like to share your own levels? I invite you to share your opinion via a comment, or shoot me an e-mail (you can find my address on the about page).</p> + +<p><em>Special thanks to <a href="https://blog.ploeh.dk/">Mark Seemann</a>, <a href="https://www.linkedin.com/in/pgpbarbosa/">Pedro Barbosa</a> and <a href="https://www.linkedin.com/in/petermorlion/">Peter Morlion</a> for giving feedback on earlier drafts of this post.</em></p> + + Wed, 18 Oct 2023 00:00:00 +0000 + https://carlosschults.net/en/fivel-levels-readable-code/ + https://carlosschults.net/en/fivel-levels-readable-code/ + + best-practices + + readability + + + + + + Make Your Git History Look Beautiful Using Amend and Rebase + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><span>Photo by <a href="https://unsplash.com/@yancymin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yancy Min</a> on <a href="https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p>You’re part of a small to medium-sized software team, and you’re envious of your co-worker’s Git history. They produce clean, well-structured histories with beautifully crafted commit messages. Yours, by comparison, looks like a train-wreck, full of descriptions such as “fix typo”, “add forgotten file”, and so on. You wonder how they do it.</p> + +<p>The answer is simple: <em>they cheat.</em> You see, they probably make just as many mistakes as you do, but they use Git’s features to hide them. They then present a cleaner, nicer history to the world.</p> + +<p>What they do is to <strong>rewrite history.</strong> Some version control tools treat history like it’s this super sacred thing. Git isn’t like that. It gives you power to rewrite history to your heart’s desire. So much power that you can even shoot yourself in the foot with it if you’re not careful.</p> + +<p>In this post, I’ll show you how to use amend and interactive rebase to make your Git history look beautiful before publishing it. There won’t be much theory; I’ll walk you through some common scenarios, showing how I’d go about solving them.</p> + +<p>Before wrapping up, I’ll teach you how to not shoot yourself in the foot with these commands. As I’ll explain, amending and rebasing are destructive actions, and there are situations in which you should not perform them.</p> + +<h2 id="requirements">Requirements</h2> +<p>To follow along with this post, I assume you:</p> + +<ul> + <li>Are comfortable working with the command line</li> + <li>have Git installed on your machine</li> + <li>know at least the basic Git commands</li> +</ul> + +<p>As I write this post, I’m on Windows, using Git version <strong>2.38.1.windows.1</strong> and typing my commands on Git Bash. If you’re on Linux or OSX, I guess everything will work just as fine, but I haven’t tested it myself.</p> + +<h2 id="defining-vs-code-as-your-default-text-editor">Defining VS Code as Your Default Text Editor</h2> +<p>Just a last digression before we really get started. Some of the commands you’ll be seeing throughout this post will require you to edit and save a text file. They do this by opening your default text editor as configured in your Git configuration file and waiting until you edit, save and close the file.</p> + +<p>If you’re on Windows like me, using Git Bash, you’re default editor will be Vim. Vim is a command-line text editor, and some people find it intimidating. Though learning Vim requires some work, it’s not that hard to get the hang of it, and I’d recommend you invest some time to learn at least the most basic commands—specially how to quit!</p> + +<p>However, Git allows you to pick other text editors as your default. If you have Visual Studio Code installed and want to use it, run the following command:</p> + +<p><code class="language-plaintext highlighter-rouge">git config --global core.editor "code --wait"</code></p> + +<h2 id="rewriting-history-n-common-scenarios">Rewriting History: N Common Scenarios</h2> +<p>I’ll walk you through a few common scenarios you might find yourself in which rewriting history will save you.</p> + +<h3 id="my-git-commit-message-has-a-typo">My Git Commit Message Has a Typo</h3> +<p>You’re in a hjurry to fix this high priority bug. After hours of grueling debugging, you find the offending code, fix it and commit the change.</p> + +<p>Only then you see you made a typo. How to fix that?</p> + +<p>Let’s start by creating a repository for you to practice:</p> + +<p><code class="language-plaintext highlighter-rouge">git init</code></p> + +<p>Now, let’s add a new file and commit:</p> + +<p><code class="language-plaintext highlighter-rouge">touch file.txt &amp;&amp; git add file.txt &amp;&amp; git commit -m "fix async request in getUsers() functino"</code></p> + +<p>Run <code class="language-plaintext highlighter-rouge">git log--oneline</code> to see your commit message. You’ll see something like this:</p> + +<p><img src="/img/git-beautiful-history/img1.png" alt="" /></p> + +<p>Pay attention to the commit identifier, and maybe even write it down; it will be important later on. (Yours will be different than mine.)</p> + +<p>Anyway, your message has a typo. How do you fix it?</p> + +<p>Just run <code class="language-plaintext highlighter-rouge">git commit --amend</code>, exactly like that. Git will open your text editor and wait for you to edit the commit’s message:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fix async request in getUsers() functino + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# Date:      Tue Jan 10 19:14:17 2023 -0300 +# +# On branch master +# +# Initial commit +# +# Changes to be committed: +#   new file:   file.txt +# +</code></pre></div></div> + +<p>The first line is the actual commit message. The lines starting with the “#” are comments and will be ignored. Just fix the typo, save and close the text file, and you’ll have a brand new commit message. Run <code class="language-plaintext highlighter-rouge">git log --oneline</code> again to see it:</p> + +<p><img src="/img/git-beautiful-history/img2.png" alt="" /></p> + +<p>You’ll notice that the identifier (SHA-1) of the commit is now different than it was before—and also different than the one from the image above. I’ll get back to this later.</p> + +<p>For now, you’ve successfully amended your commit message. Congrats!</p> + +<h3 id="i-forgot-to-include-a-file">I Forgot to Include a File</h3> +<p>Sometimes you have several changed files and want to commit some but not all of them. In your hurry, you leave one or more files behind. How to fix this?</p> + +<p>Amend to the rescue again.</p> + +<p>To simulate this situation, let’s create a new file and also add a new line to the existing one:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>file2.txt +<span class="nb">echo</span> <span class="s1">'New line'</span> <span class="o">&gt;&gt;</span> file.txt +</code></pre></div></div> + +<p>A common mistake here is to run commit with the <code class="language-plaintext highlighter-rouge">-a</code> option, thinking it will include both files:</p> + +<p><code class="language-plaintext highlighter-rouge">git commit -am "update file and add file2"</code></p> + +<p>Run the command above. Then run <code class="language-plaintext highlighter-rouge">git status</code>. This is the result you’ll get:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>On branch master + +Untracked files: + + (use "git add &lt;file&gt;..." to include in what will be committed) + + file2.txt + +nothing added to commit but untracked files present (use "git add" to track) +</code></pre></div></div> + +<p>Fixing the situation is easy. First, you track or stage the forgotten file:</p> + +<p><code class="language-plaintext highlighter-rouge">git add file2.txt</code></p> + +<p>Then, use <code class="language-plaintext highlighter-rouge">git commit –-amend</code> again. Your editor will open, but in this case, there’s nothing wrong with the message. Just close the editor and you’re done: you now have an amended commit that includes the previously forgotten file.</p> + +<p>But if you’re anything like me, you probably feel like a chump having opened your text editor for no reason at all.</p> + +<p>Fortunately, you don’t always have to do that. When you just want to add one or more missing files without changing the commit message, you can use the <code class="language-plaintext highlighter-rouge">--no-edit</code> option, like this:</p> + +<p><code class="language-plaintext highlighter-rouge">git commit –-amend –-no-edit</code></p> + +<p>This way, Git won’t open your text editor, keeping the original commit message.</p> + +<h3 id="i-want-to-merge-several-commits-into-one">I Want to Merge Several Commits into One</h3> +<p>Merging several commits into one is an operation called “squashing.” But why would you want to do that?</p> + +<p>Well, it all boils down to your Git style. I like to make small commits, very often. Then, when I’m about to make them public (for instance, by opening a pull request) I squash them into a single commit, with a well-crafted message.</p> + +<p>This is also a common requirement from open-source project maintainers, so it’s a good skill to have. Let’s learn how to do it.</p> + +<p>First, let’s create three commits:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit"</span> +git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit 2"</span> +git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit 3"</span> +</code></pre></div></div> + +<p>Creating text files for the sake of having commits gets old pretty quickly. That’s why I’m using the <code class="language-plaintext highlighter-rouge">--allow-empty</code> option, that enables me to create empty commits.</p> + +<p>Now, let’s say I need to squash the three commits above into one. To do that, I’ll need to interactively rebase them. By doing an interactive rebase, you can perform tasks like:</p> + +<ul> + <li>Reorder commits</li> + <li>Drop one or more commits</li> + <li>Change their messages</li> + <li>Merge one or more commits together</li> +</ul> + +<p>Now comes the part that might be confusing, so please pay attention. Since we’re going to work with the three latest commits, we say <strong>we’re rebasing them on top of the fourth (from the top) commit.</strong></p> + +<p>So, use the command <code class="language-plaintext highlighter-rouge">git log --oneline -4</code> to display the last four commits and then copy the SHA1 from the fourth commit from the result:</p> + +<p><img src="/img/git-beautiful-history/img3.png" alt="" /></p> + +<p>Copy the identifier from that commit and pass it to the rebase command, like this:</p> + +<p><code class="language-plaintext highlighter-rouge">git rebase -i 45f90ca</code></p> + +<p>Of course, your actual SHA1 value will be different. But there’s an easier way:</p> + +<p><code class="language-plaintext highlighter-rouge">git rebase -i HEAD~3</code></p> + +<p>To put it simply, <code class="language-plaintext highlighter-rouge">HEAD</code> here means the latest commit, and “~3” means “three commits before this one.”</p> + +<p>After executing either of the two commands above, your editor will open, showing a text file that contains the messages from the three commits we want to rearrange, each preceded by the word “pick”. And after that, a set of instructions:</p> + +<p><img src="/img/git-beautiful-history/img4.png" alt="" /></p> + +<p>Notice that the commits here aren’t in the order you’re used to seeing them on Git. Instead of being in inverse chronological order, they’re in direct chronological order, and there’s a reason for that.</p> + +<p>Each line you see above is a command that Git will execute when you confirm the rebase operation. There are several commands available, and <code class="language-plaintext highlighter-rouge">pick</code> is the default one. It simply means the commit will be kept as is. You can use <code class="language-plaintext highlighter-rouge">drop</code> to remove a commit, <code class="language-plaintext highlighter-rouge">reword</code> to edit a commit’s message, and so on.</p> + +<p>The command we’re going to use is <code class="language-plaintext highlighter-rouge">squash</code>. Just replace the word <code class="language-plaintext highlighter-rouge">pick</code> with <code class="language-plaintext highlighter-rouge">squash</code> in the second and third commits, like this:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pick dd25df9 empty commit <span class="c"># empty</span> +squash c68804f empty commit 2 <span class="c"># empty</span> +squash a76fd60 empty commit 3 <span class="c"># empty</span> +</code></pre></div></div> + +<p>The squash command merges a commit with the one before. So, the third will be merged into the second, which will be merged into the first one. And that’s why the first one needs to be <em>picked</em>.</p> + +<p>After editing the text like I told you, save and close the file. When you do that, your editor will be opened once again. This time, you’ll be prompted to write a commit message for the new commit that will emerge:</p> + +<p><img src="/img/git-beautiful-history/img5.png" alt="" /></p> + +<p>Replace the file’s content with “this is now a single commit.” Save and close the file.</p> + +<p>Finally, let’s see the result:</p> + +<p><code class="language-plaintext highlighter-rouge">git log --oneline</code></p> + +<p>This is what you should get:</p> + +<p><img src="/img/git-beautiful-history/img6.png" alt="" /></p> + +<p>As you can see, the three empty commits were replaced by a single commit. You’ve successfully performed your first squash. Congrats!</p> + +<h2 id="when-you-shouldnt-mess-with-history">When You Shouldn’t Mess with History</h2> +<p>Before wrapping up, let’s understand when changing history is problematic.</p> + +<p>First, understand that both <code class="language-plaintext highlighter-rouge">amend</code> and <code class="language-plaintext highlighter-rouge">rebase</code> produce <strong>destructive changes</strong>. It’s like they’re destroying history and creating a new one.</p> + +<p>So, imagine that you squash three commits (there were already pushed to the remote) into one and then push that new commit into the remote repository (you’d have to force push for that to work, by the way.) But while you were working, your coworker had branched off from (what was then) the latest commit.</p> + +<p>That commit no longer exists (technically, that’s not quite true, but let’s pretend for a minute that it is), which means they won’t be able to simply push their changes. They’ll have to pull your new commits and then perform a potentially complex merge in order to get things sorted.</p> + +<p>So, the golden rule is <strong>never rewrite history that other people depend upon.</strong> What this means in specific will depend on whatever branching workflow you and your team use.</p> + +<p>If you use <a href="https://trunkbaseddevelopment.com/">trunk-based development,</a> never rewrite the master/main branch. The same is true if your work with <a href="https://docs.github.com/en/get-started/quickstart/github-flow">GitHub Flow</a>. If you use git-flow, that means never rewriting the “eternal” branches, i.e., master/main and develop.</p> + +<h2 id="ok-i-lied-heres-a-bit-of-theory">OK, I Lied: Here’s a Bit of Theory</h2> +<p>Throughout this post, I’ve been using language like “change the commit’s message”, “merge multiple commits into one”, and so forth.</p> + +<p>Technically speaking, those were all lies. When you use commands like <code class="language-plaintext highlighter-rouge">git commit --amend</code> or <code class="language-plaintext highlighter-rouge">git rebase -i</code>, you’re not changing anything. What Git is doing <strong>is creating new commits</strong>.</p> + +<p>Remember when you first used <code class="language-plaintext highlighter-rouge">amend</code> and I said that it was relevant that the commit now had a new identifier? As it turns out, that was an entire new commit, and the old one is still out there!</p> + +<p>The same goes for rebasing. When you “merge three commits into one”, that’s not what’s happening. Instead, Git creates a new commit and updates the branch reference, so it points to the new commit. The three old commits are still there (at least for a while) but since no branch points to them they’re unreachable—unless you can get ahold of their SHA1 values somehow.</p> + +<p>The following image represents what really happened after you squashed your commits:</p> + +<p><img src="/img/git-beautiful-history/img7.png" alt="" /></p> + +<p>Now, let’s see the scenario after the squash:</p> + +<p><img src="/img/git-beautiful-history/img8.png" alt="" /></p> + +<p>As you can see, there’s now a new commit, in orange, which is the result of “merging” the three original ones. However, the three old commits are still there. You can’t easily reach them, though, because now there’s no branch pointing to them.</p> + +<p>The astute reader will notice that even the images above are a simplification. “We should have more commits in the image!”, they say, with their accusatory index finger pointing at the scream. And guess what, they’re right.</p> + +<p>Remember we started this whole thing by amending two commits? Well, since amend doesn’t change commits but create new ones, we have two extra lost commits in our repository. I omitted them from the diagrams above <del>because I was feeling kind of lazy</del> for brevity’s sake. But as an exercise for the reader, you can add them yourself.</p> + +<h2 id="rewrite-the-past-to-look-and-be-smarter">Rewrite the Past to Look (And Be) Smarter</h2> +<p>Rewriting history is a powerful capability of Git. With commands such as <code class="language-plaintext highlighter-rouge">git commit --amend</code> and <code class="language-plaintext highlighter-rouge">git rebase -i</code> you can “change” your past commits, hiding your mistakes and making it look like you got everything right from the start. I do this all the time and I reap the benefits: my coworkers think I’m way smarter than what I’m really—please don’t tell them my secret.</p> + +<p>Seriously now: these commands are fantastic tools for getting a more organized history. With them, you can lose the fear of committing frequently once and for all. Make commits small and frequent, and don’t pay too much attention to the message-for example, if you use <a href="/en/csharp-unit-testing-intro-tdd/">TDD</a>, you can commit every time the tests pass.</p> + +<p>Then, when it is time to publish your work, squash the commits and put a nice description on them. Adopt a commit messaging convention for you and your team, such as <a href="https://www.conventionalcommits.org/en/v1.0.0/">Conventional Commits</a>. Your colleagues (and your future self) will thank you.</p> + + Tue, 17 Jan 2023 00:00:00 +0000 + https://carlosschults.net/en/git-beautiful-history/ + https://carlosschults.net/en/git-beautiful-history/ + + best-practices + + git + + + + + + How To Reduce Cyclomatic Complexity: A Complete Guide + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1617641333/reduce-cyclomatic-complexity/reduce-cyclomatic-complexity-1038x437.jpg" alt="" /></p> + +<p><em>Editorial note: I originally wrote this post for the LinearB blog. You can <a href="https://linearb.io/blog/reduce-cyclomatic-complexity/">check out the original here, at their site</a>. While you’re there, take a look at their product, a software intelligence solution that uses Git and project statistics to help dev teams improve their productivity.</em></p> + +<p>Software engineers worth their salt are always searching for ways to improve their code. Fortunately for them, there’s a reliable way to evaluate the health of a codebase and project, and that’s through the use of <a href="https://linearb.io/metrics-modern-dev-leaders/">metrics</a>. Today’s post is all about a specific metric. You’ll learn how to reduce cyclomatic complexity and, more importantly, why you would want to do it.</p> + +<p>We’ll start by defining cyclomatic complexity. After that, you’ll learn what the problem with having a high cyclomatic complexity value is and why you would need to reduce it. After the “what” and “why,” we’ll finally get to the “how”: We’ll show you tactics you can adopt to reduce the cyclomatic complexity of your code. Let’s get to it.</p> + +<h2 id="cyclomatic-complexity-a-brief-definition">Cyclomatic Complexity: A Brief Definition</h2> + +<p>Cyclomatic complexity is an important software metric. It refers to the number of possible execution paths inside a given piece of code—for instance, a function. The more decision structures you use, the more possible branches there are for your code.</p> + +<p>Cyclomatic complexity is especially important when it comes to testing. By calculating the cyclomatic complexity of a function, for instance, you know the minimum number of test cases you’ll need to achieve full <a href="https://linearb.io/blog/what-is-branch-coverage/">branch coverage</a> of that function. So, we can say that cyclomatic complexity can be a predictor of how hard it is to test a given piece of code.</p> + +<h2 id="a-dead-simple-cyclomatic-complexity-example">A Dead Simple Cyclomatic Complexity Example</h2> + +<p>Consider the following function written in pseudocode:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">void</span> <span class="nf">sayHello</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Hello, ${name}!"</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>Since it has a single statement, it’s easy to see its cyclomatic complexity is 1. Now, let’s change things a little bit:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">void</span> <span class="nf">sayHello</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">sayGoodbye</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Hello, ${name}!"</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sayGoodbye</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Goodbye, ${name}!"</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>The second version of the function has a branch in it. The caller to the function might pass <strong>true</strong> as the value for the <strong>sayGoodbye</strong> parameter, even though the default value is <strong>false</strong>. If that does happen, the function will print a goodbye message after saying hello. On the other hand, if the caller doesn’t supply a value for the parameter or chooses <strong>false</strong>, the goodbye message won’t be displayed.</p> + +<p>So, the function has two possible execution branches, which is the same as saying that its cyclomatic complexity has a value of 2.</p> + +<h2 id="why-is-cyclomatic-complexity-bad">Why Is Cyclomatic Complexity Bad?</h2> + +<p>Cyclomatic complexity isn’t intrinsically bad. For instance, you can have a piece of code with a somewhat high cyclomatic complex value that’s super easy to read and understand. However, generally speaking, we can say that having a high cyclomatic complexity is either a symptom of problems with the codebase or a potential cause of future problems. Let’s cover some of the reasons why you’d want to reduce it in more detail.</p> + +<h3 id="cyclomatic-complexity-might-contribute-to-cognitive-complexity">Cyclomatic Complexity Might Contribute to Cognitive Complexity</h3> + +<p>Cognitive complexity refers to how difficult it is to understand a given piece of code. Though that’s not always the case, cyclomatic complexity can be one of the factors driving up cognitive complexity. The higher the cognitive complexity of a piece of code, the harder it is to navigate and maintain.</p> + +<h3 id="cyclomatic-complexity-makes-code-harder-to-test">Cyclomatic Complexity Makes Code Harder to Test</h3> + +<p>As we’ve already mentioned, higher values of cyclomatic complexity result in the need for a higher number of test cases to comprehensively test a block of code—e.g., a function. So, if you want to make your life easier when writing tests, you probably want to reduce the cyclomatic complexity of your code.</p> + +<h3 id="cyclomatic-complexity-contributes-to-higher-risk-of-defects">Cyclomatic Complexity Contributes to Higher Risk of Defects</h3> + +<p>You’re likelier to introduce defects to an area of the codebase that you change a lot than to one you rarely touch. In addition, the more complex a given piece of code is, the more likely you are to misunderstand it and introduce a defect to it.</p> + +<p>So, complex code that suffers a lot of <a href="https://linearb.io/blog/what-is-code-churn/">churn</a>—frequent changes by the team—represents more risk of defects. By reducing the cyclomatic complexity—and, ideally, the code churn as well—you’ll be mitigating those risks.</p> + +<h2 id="how-to-reduce-cyclomatic-complexity-6-practical-ways">How to Reduce Cyclomatic Complexity: 6 Practical Ways</h2> + +<p>We’ll now go over a few practical tips you can use to ensure the cyclomatic complexity of your code is as low as possible.</p> + +<h3 id="1prefer-smaller-functions">1.Prefer Smaller Functions</h3> + +<h4 id="what-to-do">What to Do?</h4> + +<p>All else being equal, smaller functions are easier to read and understand. They’re also less likely to contain bugs by virtue of their length. If you don’t have a lot of code, you don’t have lots of opportunities for buggy code. The same reasoning applies for cyclomatic complexity: You’re less likely to have complex code if you have less code period. So, the advice here is to prefer smaller functions.</p> + +<h4 id="how-to-do-it">How to Do It?</h4> + +<p>For each function, identify their core responsibility. Extract what’s left to their own functions and modules. Doing that also makes it easier to reuse code, which is a point we’ll revisit soon.</p> + +<h3 id="2avoid-flag-arguments-in-functions">2.Avoid Flag Arguments in Functions</h3> + +<h4 id="what-to-do-1">What to Do?</h4> + +<p>Flag arguments are boolean parameters you add to a function. People usually use them when they need to change how a function works while at the same time preserving the old behavior.</p> + +<h4 id="how-to-do-it-1">How to Do It?</h4> + +<p>What to use instead of flag parameters? In a nutshell, you can use strategies that accomplish the same result without incurring high complexity. For instance, you could create a new function, maintaining the old one as it is and extracting the common parts into its own private function.</p> + +<p>If the flag parameter is being used to enhance or improve the behavior of the original function somehow, you might want to leverage the <a href="https://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a> to reach the same end.</p> + +<h3 id="3reduce-the-number-of-decision-structures">3.Reduce the Number of Decision Structures</h3> + +<h4 id="what-to-do-2">What to Do?</h4> + +<p>You might consider this one a no-brainer. If the decision structures—especially <strong>if-else</strong> and switch case—are what cause more branches in the code, it stands to reason that you should reduce them if you want to keep cyclomatic complexity at bay.</p> + +<h4 id="how-to-do-it-2">How to Do It?</h4> + +<p>Some of the tactics we’ve just seen can contribute to reducing the number of <strong>if</strong> statements in your code. For instance, instead of using flag arguments and then using an <strong>if</strong> statement to check, you can use the decorator pattern. Instead of using a switch case to go over many possibilities and decide which one the code will execute, you can leverage the <a href="https://en.wikipedia.org/wiki/Strategy_pattern">strategy pattern</a>. Sure, at some point in the code, you’ll still need a switch case. After all, <em>someone</em> has to decide which actual implementation to use. However, that point becomes the only point in the code that needs that decision structure.</p> + +<h3 id="4get-rid-of-duplicated-code">4.Get Rid of Duplicated Code</h3> + +<h4 id="what-to-do-3">What to Do?</h4> + +<p>Sometimes, you have functions/methods that do almost the same thing. Keeping both increases the total cyclomatic complexity of your class or module. If you can limit your duplicates, you can limit complexity.</p> + +<h4 id="how-to-do-it-3">How to Do It?</h4> + +<p>Remove duplicated code by:</p> + +<ul> + <li>extracting the common bits of code to their own dedicated methods/functions.</li> + <li>leveraging design patterns—such as <a href="https://en.wikipedia.org/wiki/Template_method_pattern">template pattern</a>—that encourage code reuse.</li> + <li>extracting generic utility functions into packages—gems, npm modules, NuGet packages, etc.—that can be reused through the whole organization.</li> +</ul> + +<h3 id="5remove-obsolete-code">5.Remove Obsolete Code</h3> + +<h4 id="what-to-do-4">What to Do?</h4> + +<p>There are many reasons why it’s a good idea to remove obsolete—i.e., dead—code from your application. For our context, it suffices to say that that’s a “free” way to bring code coverage up and cyclomatic complexity down.</p> + +<h4 id="how-to-do-it-4">How to Do It?</h4> + +<p>Just use a tool that lets you identify dead code—even your IDE might be able to do it—and then delete it mercilessly.</p> + +<h3 id="6dont-reinvent-the-wheel">6.Don’t Reinvent the Wheel</h3> + +<h4 id="what-to-do-5">What to Do?</h4> + +<p>Let the developer who never wrote a function—or even a couple of them—to perform date formatting cast the first stone! It’s almost like a rite of passage.</p> + +<p>Writing code that simply duplicates functionality that your language’s standard library or your framework already provides is a sure way to increase complexity unnecessarily. If <a href="https://wiki.c2.com/?SoftwareAsLiability">code is a liability</a>, you want to write only the strictly necessary amount of it.</p> + +<h4 id="how-to-do-it-5">How to Do It?</h4> + +<p>Implement a sound code review strategy that’s able to identify and get rid of such wheel reinventions.</p> + +<h2 id="reduce-cyclomatic-complexity-increase-code-clarity">Reduce Cyclomatic Complexity, Increase Code Clarity</h2> + +<p>Cyclomatic complexity is one of the most valuable metrics in software engineering. It has important implications for code quality and maintainability, not to mention testing. High cyclomatic complexity might be both a signal of existing problems and a predictor of future ones. So, keeping the value of this metric under control is certainly something you want to do if you want to achieve a healthy codebase. Keeping it under control is exactly what you’ve learned with our post.</p> + +<p>Before parting ways, a final caveat. Keep in mind that no metric is a panacea when used in isolation. Often, what you’d really want to do is to track and improve a <a href="https://linearb.io/5-key-metrics-fix-your-software-teams-quality/">group of metrics</a> that, together, can give you the big picture view of the health of your team and project. Thanks for reading.</p> + + Mon, 05 Apr 2021 00:00:00 +0000 + https://carlosschults.net/en/reduce-cyclomatic-complexity/ + https://carlosschults.net/en/reduce-cyclomatic-complexity/ + + best-practices + + software-testing + + automated-testing + + unit-testing + + software-engineering + + + + + + Mutation Testing: What It Is and How It Makes Code Coverage Matter + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1595528879/mutation/mutation-testing-1038x437.jpg" alt="" /></p> + +<p><span>Photo by <a href="https://unsplash.com/@wocintechchat?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Christina @ wocintechchat.com</a> on <a href="https://unsplash.com/s/photos/software-testing?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p><em>Editorial note: This post was originally written for the NCrunch blog. You can <a href="https://blog.ncrunch.net/post/mutation-testing-code-coverage.aspx">check out the original here, at their site</a>.</em></p> + +<p>I’ve been fascinated by mutation testing since I found out about it. I thought I’d finally found the answer to so many problems I had when writing tests. With mutation testing, I now had a way to really trust my tests. At last, code coverage had meaning again.</p> + +<p>Then, I was dumbstruck as I realized that very few developers shared my interest in mutation testing. In fact, I dare say that most developers haven’t even heard about it. And that’s a shame because they—and we, as an industry—are missing out on so many benefits.</p> + +<p>So, this post is my humble attempt to remedy the situation. I’ll start by explaining the current dilemmas developers face regarding the reliability of the tests they write. Then, I’ll proceed to show you how mutation testing is the answer to these dilemmas. I’ll explain what it is, how it can make your tests more trustworthy, and how it can turn code coverage into the valuable metric it should be.</p> + +<h2 id="the-problem-trustworthiness-of-tests">The Problem: Trustworthiness of Tests</h2> + +<p>When learning about <a href="https://carlosschults.net/en/unit-testing-for-beginners-part1/">unit tests</a>—or automated tests in general—most people will ask the same or a similar question: <em>How do I know my tests are right?</em> That’s a legitimate concern. If your tests aren’t trustworthy, then you might be better off with no tests at all.</p> + +<p>So what’s the answer? How do people deal with the problem of test trustworthiness without relying on mutation testing?</p> + +<h2 id="making-tests-reliable-without-mutation-testing">Making Tests Reliable Without Mutation Testing</h2> + +<p>There are techniques developers employ to improve the reliability of their tests, and we’ll briefly cover some of them in this section. If you’re experienced with unit testing, you’re probably familiar with them. Let’s dive in.</p> + +<h3 id="keep-your-tests-simple">Keep Your Tests Simple</h3> + +<p>The first technique we’ll cover here to improve the reliability of your tests is just to keep them simple. And by “simple” I mean with less cyclomatic complexity. The lower the <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of a given piece of code, the likelier it is that it actually does what you think it does. Simple code is easier to reason about, which is a property you definitely want your unit tests to have.</p> + +<p>Keep test code simple to the point of being obvious. That means, for instance, avoiding loops or decision structures. Also, avoid doing anything fancy to compute the expected result (more on that in the next section). Hard-code it instead.</p> + +<h3 id="dont-duplicate-implementation-code">Don’t Duplicate Implementation Code</h3> + +<p>Let’s say you’re doing the <a href="https://codingdojo.org/kata/RomanNumerals/">Roman numerals kata</a>. Resist the temptation to automatically generate the expected values (“I” for 1, “II” for 2, and so on). Instead, hard-code the values. If the repetition really bothers you and your test framework allows it, use parametrized tests.</p> + +<p>Why would that be a problem? Simple: The fancier your test code gets, the more likely it’s duplicating production code. If that’s the case, you might be unlucky enough to find yourself in the situation where your production code is wrong (it doesn’t solve the problem as it’s supposed to do) but the tests pass. That’s one of the worst possible scenarios. It’s even worse than having no tests at all.</p> + +<h3 id="ensure-you-see-the-test-failing">Ensure You See the Test Failing</h3> + +<p>Ensure each test fails at least once before it passes. If you see the test failing when you think it should be failing and vice versa, that’s a sign you’re moving in the right direction. It doesn’t guarantee anything, but it decreases the likelihood the test is passing due to a coincidence.</p> + +<p>Here’s how you’d do it. As soon as you get to the green phase, damage the implementation code in such a way that one or more tests should fail. You could invert conditionals, replace strings or numeric literals with random values, or even delete an if-statement. If you manage to sabotage production code and get away with it, that’s not a good sign. Your test suite is either wrong or incomplete. In a sense, you’re testing the tests.</p> + +<p>Developers who employ <a href="https://carlosschults.net/en/csharp-unit-testing-intro-tdd/">TDD (test-driven development)</a> kind of already do that by definition. Since you write a failing test and then proceed to make it pass, you’re seeing the test fail. Of course, the test should fail in the expected manner. Meaning that if you’re performing an assertion, the test should fail due to an assertion failure and not, say, because the method under test throws an exception. Yes, this is better than nothing, but it still might not be enough. Since a unit test represents a single-use case, it’s totally possible to introduce a defect to production code in such a way that this particular test still passes.</p> + +<h2 id="we-must-do-better-enter-mutation-testing">We Must Do Better: Enter Mutation Testing</h2> + +<p>So you’ve just applied the technique described in the last section. Good! Not perfect, though. Here comes a problem. You can’t just insert a lot of defects and run the tests, because you wouldn’t be able to identify which defect was responsible for the tests failing. The correct way to do it is to insert a single deliberate defect, run all the tests, verify their result, and <em>then</em> roll back the change. After that, you can introduce another mistake, run all the tests again, verify the result, roll back the change…rinse and repeat. Needless to say, such an approach is extremely slow, tedious, and error-prone.</p> + +<p>That’s where mutation testing comes in.</p> + +<h3 id="whats-mutation-testing-anyway">What’s Mutation Testing, Anyway?</h3> + +<p>Mutation testing is nothing more, nothing less, than automating the whole “sabotaging production code and running tests to see if they fail” process you just saw. To use mutation testing, you need a mutation testing framework. The framework will alter production code, introducing defects that are called “mutations.” For each mutation introduced, the framework will again run the suite of unit tests. If all tests pass, we say the mutation survived. That’s a bad thing. It means that either your suite is lacking tests or the existing ones are wrong.</p> + +<p>If, on the other hand, one or more tests fail, that means the mutation was killed, which is a good thing. The framework will repeat that process until it’s tested the relevant portion of the codebase. When it’s all done you can check the results, which will contain the number of mutations introduced, as well as the ratio of surviving vs. killed mutants.</p> + +<h3 id="mutation-testing-makes-code-coverage-better">Mutation Testing Makes Code Coverage Better</h3> + +<p>One of the most controversial topics in the unit testing world is the argument about code coverage. Some developers say that getting to full coverage is essential; others will argue that’s a useless metric. Who’s right?</p> + +<p>First of all, you have to understand that this issue isn’t black and white. As is the case with pretty much everything in software, there’s some nuance. Of course code coverage isn’t useless. Knowing that your codebase has, say, 10% of test coverage is definitely a useful piece of data. Such a coverage is way too low: Seeing the green bar won’t offer them any confidence. That’s not to say that having 100% coverage is necessarily a good thing in itself. You could have tests that don’t have assertions, for instance. Yes, this is a contrived example, but something like that could (and sometimes does) happen.</p> + +<p>A more common occurrence would be to just have tests that don’t exercise enough paths in the software. In short: Low code coverage is definitely a bad thing, but high (or full) code coverage is not <em>necessarily</em> a good thing since it says nothing about the quality of the tests in the suite.</p> + +<p>Since mutation testing does verify the quality of the test suite, it’s the missing piece of the puzzle. If your codebase has a high code coverage and the results of mutation tests show that most or all mutations introduced are being killed, then smile! You probably have a great test suite in place!</p> + +<h2 id="embrace-mutation-testing-today">Embrace Mutation Testing Today</h2> + +<p>In today’s post, we talked about the problem of test trustworthiness, then proceeded to review some techniques and guidelines you can use to overcome that challenge. Finally, we saw how mutation testing is the superior approach to solving that problem.</p> + +<p>Here’s the thing: The techniques we covered are good guidelines to follow when writing unit tests. Your tests will benefit from abiding by them, whether you employ mutation testing or not. But guidelines can only take you so far. They depend too much on human willpower and discipline, and we all have limited amounts of those. In order to take the quality of your tests to the next level, you need to embrace automation.</p> + +<p>It takes just a few minutes of googling to find a mutation testing tool for your preferred tech stack. Do that today, and stop missing out on the benefits that mutation testing can provide you and your team!</p> + + + Thu, 23 Jul 2020 00:00:00 +0000 + https://carlosschults.net/en/mutation-testing/ + https://carlosschults.net/en/mutation-testing/ + + software-testing + + automated-testing + + unit-testing + + code-coverage + + mutation-testing + + tdd + + + + + + C# Unit Testing: Getting Started With TDD + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1459979937/testes-unitarios-iniciantes-min_povcse.png" alt="" /></p> + +<p><em>This post is part of a series. <a href="http://carlosschults.net/tag/unit-testing-series/">See all the articles in the series.</a></em></p> + +<p>Today I bring you another post to help you get started with C# unit testing. I’ve already covered the <a href="https://carlosschults.net/en/unit-testing-for-beginners-part1/">basics of unit tests</a>, explaining what they are and why they’re so important. After that, I showed you <a href="https://carlosschults.net/en/unit-testing-for-beginners-part2/">how to get started with unit testing</a> with a practical example. Today, we go one step further, exploring the TDD methodology.</p> + +<p>You’ve probably have heard of TDD, but you might be confused as to what it is. This isn’t your fault, by the way. There’s quite a lot of misconception surrounding this acronym. Some people even use it interchangeably with unit testing. In this post, you’re going to learn why they’re wrong, and more.</p> + +<p>We start the post with a brief definition of TDD. You’ll learn not only that TDD stands for Test-Driven Development, but also that it’s not a testing technique, despite the name. After that, I explain what TDD is and what its benefits are.</p> + +<p>After the “what” and “why” are both out of our way, we’ll be ready to have some fun. I’m going to show you, in practice, how to get started with TDD, developing a solution for a famous programming exercise. Sounds good? Then, let’s dig in.</p> + +<h2 id="c-unit-testing--tdd-basics">C# Unit Testing &amp; TDD Basics</h2> + +<p>I’ve mentioned earlier that TDD is not a testing technique. What is it, though? And how it’s related to C# unit testing (or unit testing in general, for that matter?)</p> + +<h3 id="defining-tdd">Defining TDD</h3> + +<p>As you’ve seen, TDD stands for Test-Driven Development. It is a technique or methodology of software development that uses unit tests to drive the development of the application.</p> + +<p>Instead of doing the more intuitive thing, which would be writing unit tests after the production code, the TDD methodology states that you should start by writing a failing unit test. Then you write the production code, but only what’s necessary to make the test pass.</p> + +<p>I guess you’re now wondering at least two things:</p> + +<ul> + <li>How does that work in practice?</li> + <li>Why write code in such a weird way?</li> +</ul> + +<p>That’s what we’re going to see next.</p> + +<h3 id="the-tdd-phases">The TDD Phases</h3> + +<p>Test-driven development relies on the repetition of an incredibly short cycle. This cycle is composed of three phases:</p> + +<ol> + <li>First, you write a test that represents a specific requirement of the functionality you’re trying to implement.</li> + <li>You then make the test pass, writing the minimum amount of production code you can get away with.</li> + <li>If necessary, you refactor the code to eliminate duplication or other problems.</li> +</ol> + +<p>Since the functionality doesn’t exist yet, the test you write in step #1 will fail. That is, in languages such as Python or Ruby. In the case of statically typed languages such as Java or C#, the code won’t even compile. For our purposes, code not compiling counts as a test failure.</p> + +<p>In step #2, you have to make the test pass, but nothing beyond that. What I mean is that your goal here isn’t to solve the problem, at least not yet. Instead, your only job is to make the test pass, writing the least possible amount of code. Cheating—for instance, returning a hard-coded value—is not only OK but encouraged, as you’ll soon see.</p> + +<p>Finally, the third phase is the only one that allows you to write production code without having to create a failing test first. But you can’t create new classes or functions; you can only refactor the code you wrote in the previous step, to make it more readable, to eliminate duplication, or to solve another problem. And, of course, the test should still pass.</p> + +<p>People often use refer to the TDD as “red-green-refactor” because most unit testing tools use red to denote failing tests and green for passing tests.</p> + +<h3 id="why-use-tdd">Why Use TDD?</h3> + +<p>The hard thing to understand when getting started with TDD isn’t the how. The “how” is trivial: write a test, make it pass, maybe refactor, rinse, repeat. The troubling part is the “why.” Why develop software in such a non-intuitive way?</p> + +<p>I’ll talk more of the TDD philosophy in future articles. In a nutshell, applying TDD ensures you’ll have testable code from the beginning. It will encourage you to design your code in a simple and modular way.</p> + +<p>But perhaps, the main advantage of TDD is increasing the developer’s confidence on their code. By developing one tiny step at a time, you’ll never be able to get a lot wrong, since you’re doing too little. Knowing that you’re only one failing test away from having working code is reassuring.</p> + +<h2 id="c-unit-testing--tdd-the-hands-on-guide-to-get-started">C# Unit Testing &amp; TDD: The Hands-On Guide To Get Started</h2> + +<p>I’ve covered how to get started with C# unit testing in the past. I’ve also covered the required tools and how to get started. However, I won’t assume you’ve read those articles. Instead, I’ll cover everything from scratch. So, you’ll be able to follow the tutorial even if you have zero experience with unit testing.</p> + +<h3 id="our-problem-the-string-calculator-kata">Our Problem: The String Calculator Kata</h3> + +<p>For our tutorial, we’ll write a solution for Roy Osherov’s <a href="https://osherove.com/tdd-kata-1">String Calculator kata</a>. A coding kata is a programming exercise, meant to allow developers to practice fundamental agile software-engineering practices, such as refactoring, and—you’ve guessed it—TDD.</p> + +<p>For simplicity’s sake, I’ll ignore some of the kata’s requirements. What follows are the requirements we’re going to use:</p> + +<ol> + <li>We’re going to create a class called StringCalculator, with a single static method with the signature static int Add(string numbers);</li> + <li>The method takes a string representing numbers separated by a comma, and return their sum.</li> + <li>If we pass an empty string, the method should return zero.</li> + <li>Passing a single number should result in the number itself.</li> + <li>If we pass negative numbers, the method should throw an ArgumentException, with the message “Negative numbers not allowed:” followed by the negatives that were specified.</li> + <li>The method should ignore numbers greater than 1000 should. So, “1,2,1000” should result in 1003, but “1,2,1001” should result in 3.</li> +</ol> + +<h3 id="creating-the-production-project">Creating The Production Project</h3> + +<p>For this tutorial, I’ll be using the community edition of Visual Studio 2019. If you don’t already have it, you can download it and install it from free.</p> + +<p>Open VS and click on “Create a new project,” like in the following image:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/img1.png" alt="" /></p> + +<p>In the opened window, choose Class Library (.NET Core) as the template for the new project. Then, click on “Next”:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/img2.png" alt="" /></p> + +<p>The next screen simply asks you for a name for the project and the solution. I chose” StringCalculatorKata” for both the project and the solution. You’ll also have to provide a location for saving the project files. When you’re done, just click “Create.”</p> + +<p>If everything went well, you should see the default class open for you in Visual Studio. Go to Solution Explorer and delete that class; we’re not going to need it.</p> + +<h3 id="creating-the-test-project">Creating The Test Project</h3> + +<p>Now, it’s time to create the test project. We could this in two ways: creating a regular “Class Library” project and then adding the necessary dependencies to it, or creating a unit test project right away. We’ll go with the latter since it makes the whole thing easier.</p> + +<p>You know the drill: right-click the solution, go to “Add,” then “New Project…”. Then, choose the template “NUnit Test Project (.NET Core).”</p> + +<p>Then, you’ll be required to provide a name and a location for the project. I like to follow the naming convention of naming the test project after the production project, with a “.Test” added. So, I pick “StringCalculatorKata.Test.” Finish the creation of the project.</p> + +<p>If everything went right, you should now see a new class that looks like this:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Tests</span> +<span class="p">{</span> + <span class="p">[</span><span class="n">SetUp</span><span class="p">]</span> + <span class="k">public</span> <span class="k">void</span> <span class="nf">Setup</span><span class="p">()</span> + <span class="p">{</span> + <span class="p">}</span> + + <span class="p">[</span><span class="n">Test</span><span class="p">]</span> + <span class="k">public</span> <span class="k">void</span> <span class="nf">Test1</span><span class="p">()</span> + <span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">Pass</span><span class="p">();</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Let’s do a few things. First, get rid of the <code class="language-plaintext highlighter-rouge">Setup()</code> method. We won’t need it. Then, add a new method with the code below:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Test2</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">Fail</span><span class="p">();</span> +<span class="p">}</span></code></pre></figure> + +<p>So, we now have two tests, one that should pass and another that should fail. Let’s run them to see if they’re working correctly. Go to the “Run” menu and click on “Run All Tests.”</p> + +<p>Now, open the Test Explorer window (View -&gt; Test Explorer). It should look like this:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/tests-running.png" alt="" /></p> + +<p>It looks like everything is working fine! But before we start doing our coding kata exercise, there are two final steps we need to take. First, let’s rename the test class. Go to the solution explorer, expand the unit test project, and delete its default test class. Then, right-click the test project, go to “Add,” then “New class…” and add a new class called “StringCalculatorKata.” Alternatively, you can rename the existing class.</p> + +<p>The second thing we have to do is to ensure our test project can see our production project. To solve that, we’re adding a reference.</p> + +<p>Go to the solution explorer again, right-click the test project, then go to “Add” and click on “Reference…”.</p> + +<p>In the new window, select “Projects” on the left panel, and then select the StringCalculatorKata project, which should be the only one available:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/add-reference.png" alt="" /></p> + +<p>Then, you just have to click on “OK,” and now you’re ready to go.</p> + +<h2 id="starting-our-coding-kata">Starting Our Coding Kata</h2> + +<p>Now, we’re ready to write our first failing test. So, open the StringCalculatorTest class and add the following method to it:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_EmptyStringAsParam_ReturnsZero</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>In our first test case, we test the simplest possible scenario. That is, we call the Add method passing an empty string, which, according to the requirements you saw before, should result in 0. Of course, neither the Add method nor the StringCalculator class exists, so our code doesn’t even compile. Well, congratulations! You’ve successfully performed the first step in the red-green-refactor cycle by writing a failing test! Remember: in statically-typed languages such as C#, failure to compile counts as a failed test.</p> + +<p>So, our first step is to get rid of the compilation error. If you hover over “StringCalculator,” you should see a little pop-up explaining the error and offering possible fixes:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594238110/unit3/hover-tip.png" alt="" /></p> + +<p>Click on “Show potential fixes” and then on “Generate new type…”. You should then see a window prompting you for the details and location of the new type. Change the “access” to “public” and the location to the production project, which is “StringCalculatorKata.” The window should look like this:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594238213/unit3/create-production-class.png" alt="" /></p> + +<p>Click on “OK.” Now, if you open solution explorer and expand the StringCalculatorKata project, you should see the StringCalculator.cs class lurking around there. Cool.</p> + +<p>However, our code still doesn’t compile. And that’s because, despite creating the production class, we didn’t add the Add method to it. So, let’s do it in the same way we did with the class.</p> + +<p>Hover over the “Add” word until the help pop-up shows up with the message “’ StringCalculator’ does not contain a definition for ‘Add.’” Click on Show potential fixes, and then click on “Generate method ‘StringCalculator.Add’.”</p> + +<p>You’ll see that the production class now contains a method called Add, with double as a return type. We want the method to return int, so let’s change that. Let’s also change the parameter name to “numbers” to match the coding kata’s requirements. At this point, your complete StringCalculator class should look like this:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">StringCalculator</span> +<span class="p">{</span> + <span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotImplementedException</span><span class="p">();</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Now your code should compile. Run the test again, and you’ll see that it fails, with a message like this:</p> + +<pre> +Add_EmptyStringAsParam_ReturnsZero + Source: StringCalculatorTest.cs line 8 + Duration: 43 ms + + Message: + System.NotImplementedException : The method or operation is not implemented. + Stack Trace: + StringCalculator.Add(String numbers) line 9 + StringCalculatorTest.Add_EmptyStringAsParam_ReturnsZero() line 10 + +</pre> + +<p>We have a truly failing test. Are we ready to write production code? Not so fast. Sure, our test fails, but it fails in the wrong way. Since our test contains an assertion, we expected a failed assertion. Instead, what we’ve got is a failure due to the method under test throwing an exception.</p> + +<p>The fix here is simple. Let’s just change the Add method, so it returns any number different from zero:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">-</span><span class="m">1</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Now, run the test again, and you’ll see the error message is now this:</p> + +<pre> +Add_EmptyStringAsParam_ReturnsZero + Source: StringCalculatorTest.cs line 8 + Duration: 76 ms + + Message: + Expected: 0 + But was: -1 +</pre> + +<h3 id="making-the-test-pass">Making The Test Pass</h3> + +<p>We’re now finally ready to make the test pass. As I’ve said earlier, to make a test pass, you’re not only allowed but encouraged to cheat. In our case, we can simply make the Add method return zero:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="writing-the-second-test-a-single-number">Writing The Second Test: A Single Number</h3> + +<p>The requirements say that passing a single number should return the number itself. That’s sound like a useful thing to test:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_StringContainingSingleNumber_ReturnsTheNumberItself</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"5"</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>The test fails with the following message:</p> + +<pre> +Add_StringContainingSingleNumber_ReturnsTheNumberItself + Source: StringCalculatorTest.cs line 14 + Duration: 56 ms + + Message: + Expected: 5 + But was: 0 + +</pre> + +<p>How can we make the test above pass in the laziest possible way? How about this:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="testing-two-numbers">Testing Two Numbers</h3> + +<p>Since we’ve already tested the Add method by passing zero numbers (an empty string) and a single number, it feels like the next natural step for us now would be to write a test for the scenario of adding two numbers. So, let’s do just that.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_TwoNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">()</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">numbers</span> <span class="p">=</span> <span class="s">"7,8"</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">expectedResult</span> <span class="p">=</span> <span class="m">15</span><span class="p">;</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">expectedResult</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>The test above naturally fails since our method currently returns 0 when it gets an empty string and five otherwise. How can we change it, so this new test passes, the older tests continue to pass, in a way that doesn’t solve the problem generally?</p> + +<p>This is an idea:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="testing-three-numbers">Testing Three Numbers</h3> + +<p>Have you noticed that, up until now, we haven’t done any refactoring? Well, we’re getting closer to the point when our tests drive us to include some nasty duplication to our code. Then, we’ll use refactoring to change the code in a way that gets closer to a general solution.</p> + +<p>Let’s see if we can do that by testing the scenario with three numbers:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_ThreeNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">()</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">numbers</span> <span class="p">=</span> <span class="s">"1, 2, 3"</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">expected</span> <span class="p">=</span> <span class="m">6</span><span class="p">;</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>The test will naturally fail. Since the provided string contains commas, we fall into the conditional branch that returns 15. Our challenge now is to change the production method in a way that makes this test pass. Can we do it without going to the general solution to the problem?Let’s see.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="s">"1, 2, 3"</span><span class="p">)</span> + <span class="k">return</span> <span class="m">6</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>By comparing the specified param with the exact input used in the test, we can make the test pass while avoiding going for the general solution. However, now we have managed to create code duplication. Can you see it? We’re making two comparisons against the value of numbers, one right after the other. Let’s see if we can get rid of that duplication.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="s">"1, 2, 3"</span><span class="p">)</span> + <span class="k">return</span> <span class="m">6</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="k">out</span> <span class="kt">int</span> <span class="n">result</span><span class="p">);</span> + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>By leveraging the <code class="language-plaintext highlighter-rouge">TryParse</code> method from the <code class="language-plaintext highlighter-rouge">System.Int32</code> type, I’ve managed to get rid of the first if instruction. We’ve also used a feature introduced in <a href="https://carlosschults.net/en/csharp-7-features/">C# 7</a> called “out variables.” This feature allows us to use out parameters without having to declare them beforehand.</p> + +<p>All tests still pass, so I can’t write more production code. What should the next test be?</p> + +<h3 id="testing-more-than-three-numbers">Testing More Than Three Numbers</h3> + +<p>The requirements don’t say we should only be able to handle three numbers. So, let’s create another test case to cover the scenarios with 4, 5, or more numbers. While we’re at it, we can also include the requirement of ignoring numbers greater than 1000.</p> + +<p>To do this without having to create a lot of test methods, we’re going to leverage NUnit’s <a href="https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html">parametrized tests</a> feature, adding a single method with several test cases:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"1,2,3,4"</span><span class="p">,</span> <span class="m">10</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"8,7,20"</span><span class="p">,</span> <span class="m">35</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,0,4,1001"</span><span class="p">,</span> <span class="m">9</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,0,4,1000"</span><span class="p">,</span> <span class="m">1009</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"26,6,90"</span><span class="p">,</span> <span class="m">122</span><span class="p">)]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_MoreThanThreeNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">(</span> + <span class="kt">string</span> <span class="n">input</span><span class="p">,</span> <span class="kt">int</span> <span class="n">result</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">input</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Notice that the third test case exemplifies the requirement that says we should ignore numbers greater than 1000. The next test case, however, shows that 1000 should not be ignored. If you run the tests, you’ll see that test explorer shows each test case as a distinct test.</p> + +<p>How can we make this test pass? Honestly, by this post, it’s way easier to go for the correct implementation than it is to cheat. So, let’s do just that:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">parts</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">part</span> <span class="k">in</span> <span class="n">parts</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">outint</span> <span class="n">number</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;=</span> <span class="m">1000</span><span class="p">)</span> + <span class="n">result</span> <span class="p">+=</span> <span class="n">number</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>The code above should be easy to understand. We just split the string into parts using the comma as the delimiter. Then, for each part, we parse it to an integer, verify whether it’s equal or less than a thousand, and, if so, we add it to the result variable. Finally, we return the result.</p> + +<h2 id="were-not-done-yet">We’re Not Done Yet</h2> + +<p>The requirements say that negative numbers shouldn’t be allowed. Let’s add a test for that! For brevity’s sake, we’ll add a single test method with several test cases, so we’re forced to go for the correct implementation right away:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"1,2,3,4,5,-5"</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"-1,1,2,9"</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,6,8,-5"</span><span class="p">)]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_StringContainingNegativeNumbers_Throws</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="n">Throws</span><span class="p">&lt;</span><span class="n">ArgumentException</span><span class="p">&gt;(()</span> <span class="p">=&gt;</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>For this test, we’re asserting not against a return value. Rather, we’re checking whether the method under test throws an exception.</p> + +<p>Remember that the requirements say we should throw an exception with a message saying that negatives are not allowed. We should also include a list of the negatives that were passed. This will require some changes in our method:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">parts</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">negatives</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;();</span> + + <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">part</span> <span class="k">in</span> <span class="n">parts</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">outint</span> <span class="n">number</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;</span> <span class="m">0</span><span class="p">)</span> + <span class="n">negatives</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">number</span><span class="p">);</span> + <span class="nf">elseif</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;=</span> <span class="m">1000</span><span class="p">)</span> + <span class="n">result</span> <span class="p">+=</span> <span class="n">number</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">negatives</span><span class="p">.</span><span class="n">Count</span> <span class="p">&gt;</span> <span class="m">0</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">negativesList</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="sc">','</span><span class="p">,</span> <span class="n">negatives</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">exceptionMessage</span> <span class="p">=</span> <span class="s">$"Negative numbers not allowed: </span><span class="p">{</span><span class="n">negativesList</span><span class="p">}</span><span class="s">."</span><span class="p">;</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span><span class="n">exceptionMessage</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>As you can see, right at the beginning, we define a <code class="language-plaintext highlighter-rouge">List&lt;int&gt;</code> to store the negatives we find while iterating over all the numbers. Inside the loop, we verify whether the current number is negative. If it is, we add it to the list. If it isn’t, we verify whether it’s less than or equals to 1000, in which we case we add it to the result variable.</p> + +<p>After the loop, we verify whether the negatives list has any elements. If it has, we create an exception message that includes the specified negatives and then throw a new ArgumentException. Otherwise, we return the result.</p> + +<h2 id="conclusion">Conclusion</h2> + +<p>This post was a practical guide on how to get started with TDD in C#. So, where do you go from here?</p> + +<p>Well, most things in life you learn by doing. Programming is certainly one of those things. So, if you want the concepts you’ve seen today to really sink in, you’ve got to practice.</p> + +<p>The code I’ve written during this post is available as <a href="https://github.com/carlosschults/string-calculator-kata">a public repository on GitHub.</a> Go there, clone it using <a href="https://carlosschults.net/en/git-basics-for-tfs-users">Git,</a>, and start playing with it.</p> + +<p>You’ll see that I created one commit for each step in the TDD cycle. That way, it becomes easier for future readers to visualize all the steps in the process by going through the project’s history, one commit at a time.</p> + +<p>There are improvements that can be made to the code I shared today. For instance, the final <code class="language-plaintext highlighter-rouge">Add</code> method could be written in a shorter, clearer, more efficient way, using <a href="https://carlosschults.net/en/functional-programming-csharp/">LINQ</a>. You could add more test cases. Also, the kata requirements ask for a specific exception message in the case of negative numbers. Even though we’ve implemented the message as specified, we didn’t write a test for it. We could do that as part of your practice.</p> + +<p>Finally, stay tuned to this blog. This post is part of a series, to which I intend to add more parts.</p> + +<p>Thanks for reading, and until the next time!</p> + + Wed, 08 Jul 2020 00:00:00 +0000 + https://carlosschults.net/en/csharp-unit-testing-intro-tdd/ + https://carlosschults.net/en/csharp-unit-testing-intro-tdd/ + + software-testing + + beginners + + unit-testing + + unit-testing-series + + automated-tests + + csharp + + agile + + + + + + Null Is Evil. What's The Best Alternative? Null. + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1593715153/null-evill-1068x437_ztikwf.jpg" alt="" /> +<span>Photo by <a href="https://unsplash.com/@benhershey?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ben Hershey</a> on <a href="https://unsplash.com/s/photos/null?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p><em>Editorial note: I originally wrote this post for the NDepend blog. You can <a href="https://blog.ndepend.com/null-evil/">check out the original here, at their site</a>.</em></p> + +<p>“Null is evil.” If you’ve been a software developer for any reasonable length of time, I bet you’ve come across that statement several times.</p> + +<p>I’d say it’s also very likely that you agree with the sentiment, i.e., that the null reference is a feature our programming languages would be better off without. Even its creator has expressed regret over the null reference, <a href="https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions">famously calling it his “billion-dollar mistake.”</a></p> + +<p>Bashing poor old null tends to get old, so authors don’t do just that. They also offer alternatives. And while I do believe that many of the presented alternatives have their merits, I also think we may have overlooked the best solution for the whole thing.</p> + +<p>In this post, we’re going to examine some of the common alternatives for returning null before making the argument that the best alternative is null itself. Let’s get started!</p> + +<h2 id="null-is-toxic">Null Is Toxic…</h2> + +<p>I won’t dwell too much on the whole “null is evil” thing, since a lot has been written about it already. Some examples:</p> + +<p><a href="&quot;https://sidburn.github.io/blog/2016/03/20/null-is-evil&quot;&gt;Null is Evil">Null Is Evil</a> +<a href="&quot;http://blog.ploeh.dk/2015/11/13/null-has-no-type-but-maybe-has/&quot;&gt;">Null has no type, but Maybe has</a></p> + +<p><a href="https://softwareengineering.stackexchange.com/questions/12777/are-null-references-really-a-bad-thing">This Stack Overflow answer</a> also has some valuable information.</p> + +<h2 id="but-useful-what-are-the-alternatives">…But Useful. What Are the Alternatives?</h2> + +<p>Now, I hope we’re on the same page regarding null’s status as a problematic language feature. But toxic or not, null serves some purposes. People use it to represent an absent, invalid, or unknown piece of data, or even to indicate that an error has occurred.</p> + +<p>What should they be doing instead?</p> + +<h3 id="throw-an-exception">Throw an Exception</h3> + +<p>In some situations in which people return null, the reasonable thing to do is to throw an exception. Think of it this way: if a method promises to perform something and fails to do so, it should throw. In other words: when a method fails to fulfill its contract, then it is reasonable to throw.</p> + +<p>Of course, you should reserve exceptions for scenarios that are truly exceptional. If a certain situation happens often, then an exception is not the best solution.</p> + +<h3 id="null-object-pattern">Null Object Pattern</h3> + +<p>Consider the following lines of code:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">contract</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="m">42</span><span class="p">);</span> +<span class="n">contract</span><span class="p">.</span><span class="nf">Extend</span><span class="p">(</span><span class="m">12</span><span class="p">);</span></code></pre></figure> + +<p>What should happen if there isn’t a contract with ID equals to 42? If the “Find” method returns null, then you’re in for a nasty NullReferenceException. As I’ve said earlier, null makes your code lie. If we were to be really pedantic about it, the method “Find” should be renamed to “FindOrReturnNull”. Too verbose, but more honest.</p> + +<p>Anyway, the <a href="https://en.wikipedia.org/wiki/Null_object_pattern">null object pattern</a> is an attempt to solve this problem. And how does it do that? By creating its own kind of null.</p> + +<p>To implement the pattern, we create a new class ** ** (let’s call it “NullContract”) that represents the case when a contract is missing. We make this new class fulfill the same contract as the original class, but we do nothing in the methods. So, if we imagine that “Contract” implements “IContract”, our NullContract class could look something like this:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">NullContract</span> <span class="p">:</span> <span class="n">IContract</span> +<span class="p">{</span> + <span class="c1">// ctor, properties, etc </span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">Extend</span><span class="p">(</span><span class="kt">int</span> <span class="n">months</span><span class="p">)</span> + <span class="p">{</span> + <span class="c1">// deliberately does nothing</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>By employing the null object pattern you could—theoretically, at least—be sure that you’ll always get an object that fulfills the contract you expect it to honor without blowing up in your face.</p> + +<h3 id="maybeoption">Maybe/Option</h3> + +<p>Finally, we have a very interesting alternative that is often found in <a href="https://blog.ndepend.com/functional-programming-makes-code-not-oo/">functional programming</a> languages. This alternative is the use of a dedicated type meant to represent the use case of a potentially absent value. For instance, <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/options">in F# this is called the option type</a>; Haskell calls it <a href="https://hackage.haskell.org/package/base-4.11.0.0/docs/Data-Maybe.html">Maybe</a>. Starting in version 8, Java introduced the <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html">Optional</a> class.</p> + +<p>At this time, C# doesn’t offer something along those lines natively.</p> + +<h2 id="alternatives-to-null-are-they-any-good">Alternatives to Null: Are They Any Good?</h2> + +<p>Having presented the more commonly used alternatives for null, it’s time for the final verdict. Let’s start with the “throw exception” option.</p> + +<h3 id="exceptions">Exceptions</h3> + +<p>If the caller fails to supply the correct arguments for the function they’re calling, then we could say they’re breaking the function’s contract. Throwing an exception is the correct thing do to in this situation.</p> + +<p>The following code is a good example of what <strong>not</strong> to do:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">Foo</span> <span class="nf">Bar</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">string</span> <span class="n">b</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="p">&gt;</span> <span class="m">0</span> <span class="p">&amp;&amp;</span> <span class="n">a</span> <span class="p">&lt;=</span> <span class="m">100</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">b</span><span class="p">))</span> + <span class="p">{</span> + <span class="c1">// all is fine with the world; let's do what must be done and return some Foo!</span> + <span class="k">return</span> <span class="k">new</span> <span class="nf">Foo</span><span class="p">();</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="c1">// uh-oh! Something wrong with the input parameters. Let's return null. Sounds like a good idea!</span> + <span class="k">return</span> <span class="k">null</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>I see code like this all the time in production. Nested ifs are awful. They should have at least used an “and” to fit the whole thing in just one if. But what should really happen is something like this:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">Foo</span> <span class="nf">Bar</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">string</span> <span class="n">b</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="p">&lt;=</span> <span class="m">0</span> <span class="p">||</span> <span class="n">a</span> <span class="p">&gt;</span> <span class="m">100</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentOutOfRangeException</span><span class="p">(</span> + <span class="k">nameof</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> + <span class="s">"The value should be in the range of 1 to 100, inclusive"</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">b</span><span class="p">))</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span> + <span class="s">"The value should be a valid string."</span><span class="p">,</span> + <span class="k">nameof</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> + <span class="p">);</span> + <span class="p">}</span> + + <span class="c1">// all is fine with the world; let's do what must be done and return some Foo!</span> + <span class="k">return</span> <span class="k">new</span> <span class="nf">Foo</span><span class="p">();</span> +<span class="p">}</span></code></pre></figure> + +<p>Also, <a href="https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/">don’t catch exogenous exceptions</a> that might happen inside your method and return null; instead, just let them bubble up since these type of exceptions represent problems outside of your control. Issues like a failure in the network are problems that you couldn’t have prevented anyway, code-wise.</p> + +<h3 id="null-object-pattern-1">Null Object Pattern</h3> + +<p>Let’s consider the null object pattern, which I’m certainly not a huge fan of. One problem with this pattern is that you should only use it when the calling code doesn’t care about the outcome of whatever it’s trying to accomplish. Consider again our contract example:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">contract</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="m">42</span><span class="p">);</span><span class="n">contract</span><span class="p">.</span><span class="nf">Extend</span><span class="p">(</span><span class="m">12</span><span class="p">);</span></code></pre></figure> + +<p>This line of code is not “aware” (nor does it care) if the “Contract” variable refers to a valid contract or an instance of NullContract. If it’s a valid contract, it will be extended by 12 months. If it’s not, then nothing will happen. Sometimes, that’s exactly what you want, but not always. In this example, if a contract with ID equals to 42 really was supposed to exist but did not…maybe throwing an exception would work best.</p> + +<p>All I’ve said so far is that the null object pattern isn’t well suited for every scenario. This isn’t that bad of a problem; you could say the same about pretty much anything.</p> + +<p>My main issue with the null object pattern is that it amounts to little more than creating a new type of null without really solving the problem. You see, <strong>using the pattern doesn’t prevent you from returning null</strong>. If I consume some method written by a third party that claims to use the pattern, I should be able to assume that whatever it returns is safe for me to deference. But I can’t know for sure. I have three options:</p> + +<ul> + <li>Trust the author of the code;</li> + <li>Inspect the source code, if possible; or</li> + <li>Continue to check for null, which completely defeats the purpose of using the pattern.</li> +</ul> + +<p>You could argue that these problems aren’t relevant in the context of a single team working with the same codebase. The developers could agree on using the pattern correctly. But if everything amounts to trust and convention at the end of the day, you might as well just agree to never return null and you’d have the same result.</p> + +<h3 id="maybeoption-1">Maybe/Option</h3> + +<p>Last but not least, what about Maybe/Option types? This is an alternative that’s both elegant and robust, especially in languages such as F# where you’re actually forced, in a sense, to handle both cases by using pattern matching.</p> + +<p>But the sad reality is this: while maybe/option types are amazing approaches, they can’t change the fact that null exists and will continue existing. You can’t really stop people from using it, nor can you remove it from all the lines of code people have been writing since the dawn of C#.</p> + +<p>So, even though they are great approaches, they still suffer from the problem of being yet another type of null for the developers to deal with.</p> + +<h2 id="the-solution-for-null-null-itself">The Solution for Null: Null Itself</h2> + +<p>Do you know the old saying “When in a hole, stop digging?” For better or worse, null exists. Toxic or not, it’s a feature people use. So maybe the solution for this whole thing is just to fix null.</p> + +<p>The <a href="https://kotlinlang.org/">kotlin</a> language got it right by having different nullable and non-nullable types and adding all kinds of checks to prevent the developer from doing things that would end badly, like dereferencing a nullable type without checking it for null or assigning a nullable value to a non-nullable variable.</p> + +<p>C# gave us the first step in the right direction many years ago with <a href="https://docs.microsoft.com/pt-br/dotnet/csharp/programming-guide/nullable-types/">nullable value types</a>. After a long wait, <a href="https://blog.ndepend.com/c-8-0-features-glimpse-future/">reference types will finally get the same benefit with C# 8.0</a>.</p> + +<p>The alternative for null is null itself… <strong>when done properly</strong>.</p> + + Thu, 02 Jul 2020 00:00:00 +0000 + https://carlosschults.net/en/null-is-evil + https://carlosschults.net/en/null-is-evil + + software-engineering + + best-practices + + programming + + csharp + + + + + + diff --git a/footprints/index.html b/footprints/index.html new file mode 100644 index 00000000..07f38779 --- /dev/null +++ b/footprints/index.html @@ -0,0 +1,213 @@ + + + + + + + + Dev Footprints | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en +
+ + +
+
+
+ +
+

Dev Footprints

+
+ +
+

This page is a collection of cheat-sheets for things that I forget often how to do.

+ + + +

Databases

+

Get all stored procedures that reference a given table

+ +

In SQL Server, to find out all stored procedures that mention/use a given table, run this:

+ +
SELECT Name
+FROM sys.procedures
+WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%TableNameOrWhatever%'
+
+ +

Docker

+

RabbitMQ

+
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management
+
+ +

MISC

+ +

CURL

+

To retrieve the HTTP status code of a URL, use the following command:

+ +
curl -s -o /dev/null -w "%{http_code}" https://carlosschults.net --ssl-no-revoke
+
+ +

PID

+

As administrator, open the command prompt and run:

+
netstat -aon | findstr <PORT>
+
+ +

After finding out the PID of the offending process, kill it:

+
taskkill /PID <PID> /f
+
+ +
+ +
+ +
+
+ + + + + + + + diff --git a/git-bisect-intro/index.html b/git-bisect-intro/index.html new file mode 100644 index 00000000..b75a39ad --- /dev/null +++ b/git-bisect-intro/index.html @@ -0,0 +1,713 @@ + + + + + + + + Git Bisect: An Introduction To Beginners | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Git Bisect: An Introduction To Beginners

+ +
+ +
+

+ +

Photo by Yancy Min on Unsplash

+ +

If you’re trying to level up your git-fu, you could do worse than learn the git bisect command. Git has its (un)fair share of complicated commands, that’s true. The good news is that, unlike those, git bisect is quite easy to understand and use. The even better news is that it’s super useful to help you fix bugs.

+ +

Prerequisites

+ +

Before getting started, let’s review some prerequisites you’ll need to follow along with the post:

+
    +
  • Having git installed on your machine
  • +
  • Knowing at least the basic git commands
  • +
  • Having Node.js installed on your machine (later on you’ll use a sample application provided by me, and it’s written in JavaScript.)
  • +
+ +

Have all that? Great, let’s move on.

+ +

What’s Git Bisect? Why Do You Need It?

+ +

Git bisect is a command that enables you to perform a binary search on your commit history. Why do that?

+ +

Here’s a common scenario during development. Someone reports a bug. You go see it and find out that, two weeks ago, the feature was working just fine.

+ +

To fix the bug, it’d be useful to find out when exactly it was introduced to the codebase. Since you know one commit that you’re sure to be “good”—that is, it doesn’t contain the bug—you could git checkout your way there, going back one commit at a time and testing to see if the application works.

+ +

That’s bound to work, but it could potentially take a long time, depending on the number of commits you’d have to check and where the problem is. For those who remember your Computer Science classes, the approach described above is a linear search, which isn’t the most optimal way to search for a value within a list.

+ +

Do you know what’s more efficient? A binary search. If you have, say, 50 commits you need to check, and you test the 25th one and don’t find the bug, what does that mean? You can disregard the first 25 commits and continue your search within the 25 later ones. Continue the process, always partioning by half, and you’ll find the faulty one in way fewer checks than would be necessary with a linear search.

+ +

Doing this by hand would be super boring, though. And that’s where git bisect comes in handy. It has an easy syntax that allows you to specify both a good and a bad commit, and then git will perform the binary partitions on your behalf. At each step, you’ll have to test your application and inform git whether that commit is a bad or a good one. Then, git calculates the next step, takes you there, and the process ends when you find the culprit.

+ +

How To Use Git Bisect In Practice?

+ +

Time to learn how to use git bisect in a hands-on approach. To practice this command, you need a repo with at least some commits, and that has a bug. It’d take a while for you to set up a repository like this, so I already made one for you—yes, I’m nice like that.

+ +

Getting The Sample Application

+

Just clone this GitHub repo and you’re good to go.

+ +

The repo contains a silly toy JavaScript application that implements some rules from the String Calculator Kata by Roy Osherov. Here’s what the application is supposed to do:

+
    +
  • after running it, the application will prompt you for a list of numbers, separated by comma;
  • +
  • you provide the numbers;
  • +
  • the sum of the numbers is displayed.
  • +
  • numbers larger than 1000 are ignored. So, the string “1,2,1000” should yield the result 1003, but “1,2,1001” should result in 3.
  • +
  • negative numbers shouldn’t be allowed. If you enter one or more negative numbers, the application should throw an error with the message “Negatives not allowed”, followed by the negative numbers that were inputted.
  • +
+ +

After cloning the repository, let’s test the app. Access its folder via the command line, run node index.js and, when prompted for the numbers, enter “1,2,3” and press enter.

+ +

Oops.

+ +
node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: .
+    at C:\repos\git-bisect-intro\index.js:11:11
+    at [_onLine] [as _onLine] (node:internal/readline/interface:423:7)
+    at [_line] [as _line] (node:internal/readline/interface:886:18)
+    at [_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1264:22)
+    at ReadStream.onkeypress (node:internal/readline/interface:273:20)
+    at ReadStream.emit (node:events:513:28)
+    at emitKeys (node:internal/readline/utils:357:14)
+    at emitKeys.next (<anonymous>)
+    at ReadStream.onData (node:internal/readline/emitKeypressEvents:64:36)
+    at ReadStream.emit (node:events:513:28)
+
+Node.js v18.12.1
+
+

The app doesn’t work. It throws the “negatives not allowed” error even if no negatives were entered. If you want to see the app working, I made things easier for you: I created a tag called good-commit that references a point in the history guaranteed to be good. Just go there and check it:

+ +

git checkout good-commit

+ +

After running the command above, it’s possible you’ll see some messages about detached HEAD and stuff. Just ignore those. Run the application again, and voilá:

+ +
Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+ +

Ok, let’s now test the numbers-larger-than-1000-should-be-ignored rule:

+ +
Enter a list of numbers separated by comma:
+1,2,1000, 1001
+The sum of the entered numbers is 1003.
+
+ +

Nice! As expected, the number 1000 is considered but 1001 is ignored. For a final test, let’s verify the negative numbers prohibition:

+ +
Enter a list of numbers separated by comma:
+1,2,3,-5,-4,-7
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -4, -7.
+
+ +

Sweet. Now, for the next step. But first, run git checkout main to return to the latest commit.

+ +

Time To Roll-Up Your Sleeves

+

To start using the git bisect command, you need to begin a bisect session. You do this by simply running git bisect start. You’ll then see the following message:

+ +

status: waiting for both good and bad commits

+ +

Now, you have to tell git about a commit that’s known to be “good”—i.e. not contain the bug—and one commit that does contain the bug. Let’s start with the good one:

+ +

git bisect good good-commit

+ +

As I said before, I created a tag to point to a known good commit to make things easier for you. But you’re not restricted to tags when it comes to pointing to a commit for a bisecting session. Branch names will also work, as commit SHAs and pretty much any references that resolve to a commit.

+ +

Anyway, after running the command, you’ll see this: +status: waiting for bad commit, 1 good commit known

+ +

Now it’s time to point to a bad commit. I’m sure you’re able to guess the syntax now: git bisect bad <REFERENCE-TO-COMMIT>. But since the commit we’re at—in other words, the tip of main—is known to be bad, you can simply run:

+ +

git bisect bad

+ +

Now the fun begins! Git will display a message, showing you the status of the bisecting operation. It’ll tell you how many revisions are left to test , and how many steps that would take, and to which commit it has “transported” you:

+ +
Bisecting: 11 revisions left to test after this (roughly 4 steps)
+[e159647d4d142c410894aaf10c1e11e2208848d7] Edit to negative rule
+
+ +

Your job now is to test the application and tell git whether that’s a good or bad commit. So, let’s run node index.js and provide some numbers:

+
Enter a list of numbers separated by comma:
+1,2,3
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: .
+
+ +

I’ve cut some of the output for brevity, but anyway: the app’s not working. So, tell git that:

+ +

git bisect bad

+ +

It takes you to a different commit:

+ +
Bisecting: 5 revisions left to test after this (roughly 3 steps)
+[0b8f71999bed054d8a95d9da3be6f0c831074cd7] Update README.md - Commit 6
+
+ +

Let’s repeat the test with node index.js:

+ +
Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+ +

Awesome! At this commit, the app seems to work fine. Let’s do a different test, using negative numbers:

+ +
Enter a list of numbers separated by comma:
+1,2,3,-5,-4,-10
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -4, -10.
+
+ +

Perfect: it’s throwing an error, as it’s supposed to do in this scenario. So, run git bisect good to mark this commit as good.

+ +
Bisecting: 2 revisions left to test after this (roughly 2 steps)
+[e6413a915c7ca92871394b01a8497c8df3fc46ae] Update README.md - Commit 9
+
+ +

Yet another commit, yet another test:

+ +
node index.js
+Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+

Let’s test the negatives:

+ +
node index.js
+Enter a list of numbers separated by comma:
+10,20,-5
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5.
+
+ +

Everything looks fine, let’s mark it as good: +git bisect good

+ +

And the result:

+
Bisecting: 0 revisions left to test after this (roughly 1 step)
+[053207649aefdb09cd255567df673cadbe2e38e3] Restore README
+
+ +

We’re getting close! Let’s test:

+
node index.js
+Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+node index.js
+Enter a list of numbers separated by comma:
+1,2,3,-5,-6
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -6.
+
+ +

Marking it as good: git bisect good. And, voilà, here’s our answer:

+ +
e159647d4d142c410894aaf10c1e11e2208848d7 is the first bad commit
+commit e159647d4d142c410894aaf10c1e11e2208848d7
+Author: Carlos Schults <carlos.schults@gmail.com>
+Date:   Tue Jan 9 08:53:47 2024 -0300
+
+    Edit to negative rule
+
+ index.js | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+ +

What Now?

+

Ok, now you know that the commit e159647d4d142c410894aaf10c1e11e2208848d7 is the one that introduced the bug. What should you do now?

+ +

In short, you need to see details of this commit, to learn what changes it makes so you can understand what caused the problem. Let’s use the git show command for that:

+ +

git show e159647d4d142c410894aaf10c1e11e2208848d7

+ +

This command will output several things about the commit, including author, date, and message. I’ll reproduce only the part I’m interested in, which is the diff:

+ +
diff --git a/index.js b/index.js
+index 5f351e0..4e65e0c 100644
+--- a/index.js
++++ b/index.js
+@@ -6,7 +6,7 @@ const readline = require('readline').createInterface({
+   readline.question('Enter a list of numbers separated by comma:\n', numbers => {
+     let integers = numbers.split(',').map(x => parseInt(x) || 0);
+     let negatives = integers.filter(x => x < 0);
+-    if (negatives.length > 0) {
++    if (negatives.length >= 0) {
+       throw new Error(`Negatives not allowed: ${negatives.join(', ')}.`);
+     }
+
+ +

And now as an image, so you can see the colors:

+ +

+ +

As you can see, this commit made a change to the if statement that tests for negative numbers, adding an equals sign to the comparison. That way, the error will be thrown regardless of whether the negatives array has elements.

+ +

Now that you know how the bug was introduced, it’s super easy to fix it. To end the bisect session, just run git bisect reset. That way, you’ll be back to the point in which you originally started.

+ +

A Note About “Good” and “Bad”

+ +

Astute readers will have noticed that, although this command uses terms like “goo”,’ “bad,” and “bug,” there’s nothing stopping you from using git bisect to find out the point in time at which any property of the codebase has changed. After all, Git can’t know how your application is supposed to work; it was you, the whole time, who was testing it.

+ +

Even the documentation for the command acknowledges this fact:

+ +
+

Sometimes you are not looking for the commit that introduced a breakage, but rather for a commit that caused a change between some other “old” state and “new” state. +For example, you might be looking for the commit that introduced a particular fix. Or you might be looking for the first commit in which the source-code filenames were finally all converted to your company’s naming standard. Or whatever.

+
+ +

In such a scenario, it’d be weird to use the terms “good” and “bad”. The good news is that you can use “new” and “old” instead: the new commit is one that contains the property you’re looking after, and the old doesn’t contain such property.

+ +

To use this terminology, just start a bisecting session as usual, and then run git bisect old <COMMIT> to indicate the old commit, and git bisect new <COMMIT to indicate the new one.

+ +

Keep in mind that you can either use good/bad or old/new, but not mix the two. At any point during a session, you can run git bisect terms to be reminded of the terms you’re using.

+ +

The command is even more flexible than that: you can pick your own terms! Just start a session by running the following:

+ +

git bisect start --term-old <term-old> --term-new <term-new>

+ +

Git Bisect: Where Do You Go Now?

+ +

I know this is only anecdotal data but, from my observations, I’d say that git bisect is an underused command. Which is pretty sad, considering that git bisect is a)incredibly useful and b)easy to understand and use, at least in its most basic use case.

+ +

If you’re already comfortable with the most common git commands — i.e. status, log, commit, add, pull, push, checkout — and want to go one step higher, learning git bisect is a great place for you to start.

+ +

So, you’ve learned the basics of this command with the introduction I wrote. Awesome, but where should you go from here? I’ve got a few suggestions:

+ +
    +
  • Put it into practice ASAP. Even if you’re not bug-hunting right now, come up with some characteristic of your application and find the commit in which it was introduced using git bisect.
  • +
  • Dive depeer into the command and look for more advanced use cases. For instance, it’s possible to automate git bisect so you don’t even have to manually test in order to triage the good commits from the bad ones!
  • +
  • Read the documentation for git bisect. Keep going back to it from time to time, and you’re bound to learn something new and useful.
  • +
+ +

That’s it for this post. I hope you like it, and I really appreciate any feedback. Thanks for reading!

+ + + + + + + Found a typo or mistake in the post? Suggest edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ + + + + + + + diff --git a/img/android-icon-144x144.png b/img/android-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..413d533e45d579fe788214e2b6f7d6733ace256c GIT binary patch literal 20963 zcmV)gK%~EkP)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy24YJ`L;(K){{a7>y{D4^000SaNLh0L002k;002k;M#*bF002)` zNklR1&sy*MecgNSbI!eU@62d4mMmEku`E-vu?@BZCO`}%m^dkH z$HgB|2~{rV7pWAnLq*t?lrWUzkOHcpQU!m-L;+)pf*?aBF(FuhU2p(S zzyOqSeLD;U$M1lIKm-h(M3Cq(bPyeQxYTwij|g-L5kilS-UHEA^mRpFj%ddN`u!c& zyXRP*zl(l6;Gg}2|M+8n{D0F`9{UZP*T4Gb008EOeJyx8Pk1ssDbpZCS|9|rXYwh7Smmy#)vgh%b3L_52KI2Abp9cl>%S&)?mC`6a{?K)ZeCEBy4o z^7ZHdIxmSpe*2aX)-LuCBewtszz`{j0h#~`pahEN>(Id0mj?g=PA!tAG+T?!7p4frhxeOOP~vB_cF#kaFuAcZLXHdgJ5z1OJ;pic$*x z)j#$}ALX1EXsyTETC}#RudCFWKp<#PoiXi-9%nPo_2>YCT>-c60`J@t zZ3U`R``Ok8zDKj-Zd0v3l_;gFxT#v8&{!!J5(P>>*8n=f01yIWfCt;j&hwwA9WR6B z)os%Vo^RXk2S7^OZ(lzC0YuyknM5X%gyD2U37$MU)VtI}XkBPcTD#O*sI?w_ZN06% zMO#~6*ERaOM6?zp)oIeY0@DoAetA3YYgms9APM-teGa(q!0icG7h?82A5*cmbUQYc zrAJ+b+Jw0aQwQb{<^ZM;rXWfHF2J^J4&&qj=k4sl(C~c8^R~td3v}`L%S~y3<$SWZ zMP`@Jj)Bhc!eeLNY+!Cl`ImPIO~M+&DqxXtiqIlyiO?FMwMVp`2C4NlOC&AOBO;{U z17GSEe(l!dTcEV`L>Cc3bR#4~zyK9NRlp=^Cuk?&3cy}@>;UW_R4^lNP-kN?UVtz8 zK3{?pz4F+L_24b(m)ImO@7I?+hhDlP#?b(*08Ri-kdA;30FD3-8n;te0j)Uipy;_J zOKDMs;WItTdRzb<06Y^=1?(%)L{xW7#ZbM_tybgYm#*XTgesqt`6hBF6FPuK;6&m` z;-2I^!8?+71PX~l(rG-AMjDyXnSr2;CL=+zoBay(fxhz}|Ks@KpXk8tJ#poRHWSSq z#SHtoU{}jLm1$pm-WA(T#_M9ZDa2DJo*D7fpc^Bvo!A>N8Bqy22_rB3oJ{>~XZO-V z*#H+VqB@MI?i?D$KmawMmX{I;oo}OFGBoFOmGVg;kdO&IfNsPh;7IVEz%7YeBPJt@ znYq)IVdsc2 zxD`&d?Dq5Y#;#6JCf{8ZyV@0A&(5dS_(mn(D0w_};)w%SPV5{i4itlEfRSf=!f`J1 z>nqp*iAiaLpmb@@AVLCT15cbod5(x`Y$HrRCt(O}VfuJIP`CiHf zAZHofNedFiP2sL^7fK1164q-35u}BcVzm?&cRZ#O^fd<172x@j@gMz%eEQbgHi34x zGhge@0l2xU8s?(F*w0}C){gdj~SH*7j&L^|s+2nk)8s03nfk@Yd*cGBW<<5-A z4Cm-+^MAJu$uK|^TV9dk1|lM(xGj|Dwv`FmELm_1$%$b4AzMP{au?hpJ_8^sMg?T0 zm|K@&7sg7$vYx_#TbFxREge(sT&HfmWq!I@C)sV9S*FQ+s-6760_Z7#Ta2u0o`M(e z5O2MK<4^n;Zwl?|$rFD%RhLc0%qol5TFSgDWp_1|{l3=gtLoSLYB#g<$yE4sGCVDY zXKr{_sAo=GI}$*JC_Rn>VGMI?=5{i-lNCR)mXp=8*i=_jjrgKvZxb% zH>1omkxtN~IMS~fK)(H5W0O7+cRvHX^Th5x`x$=plb^7w{p4k?rOc&zt&`WXtEJ47 z`+h3rdMO9xAx7wl7-AYWgs5b{`R;u}KN1t}&2XYI${*A!hkG|sFbwFPrzVIou zcfMf#_PI@OKJ_cA?yAjoSLZU-{Z#8!b-$X5T~FpWliSnD_;hl6QjJdvaZ`wEC$5az z8?ehmg@6wqC{Y3_J>_$HhDwjccs3GeU+A2KwBh#zv!cE|czo9>W_BMH zD-!gV_A?1YQ$~Oi*#cYy&LNw7_}shCeXdjM^VHPlZd!V=8dELNnk%{iFe`;N?da2V zws9XU00Dr-@IKEg{g8HRar?sJaPQvMvZto2V)Je)S9Pja(^Ri(@teu*rkdSM#;3FK zSv5SZ?%-T&YR1VG>U4+B5*DZ(Zoju+tBToM^tGpuVV>UAcjz1wbI zd_Pa+W}3>)RQySGe>xeTOok^j@w6JAPQ=YbT@_&G&%6DI^rCc`H<~bH_(tlc!q<6S45cQc1eIR5;t!jNx+jE;A9(cE&*iVZ1Cbncme8U zn0Idbz1#I%{ARBHbSnOAa(`MAJWpoB)0uiQ6E~IES86UmHORSD@+F0Y9*8DImwF5I zE~yW9CN%0~Su0~m57G96u_Q0Dk$lAhF;fH=byjT{G0RM*xq)V+i!5Lk?F=f$a3YM1 zw2&s5LllEy!Rn2&&M0YpyhLjry%$AKw+=9x(Y%me2!cKO2gr$@XW)%DfG<2D@E$J8 z1qM{Z{tdJ1>rzUo#cZl(^JLu5h1dIHPiD7g2_Sn`jZbFkW@oyYiJKjDH50oEO$Bm? zm=1*^q-X&(DArJ4q)wn=SfQ;fpPnq(Hz0|KtelT*ptfyC=TJW1{MeObge=LBGK1U* zH^`hY7|hZJnIQo*(O3i3_?4qxC0P)R_K zfG)C24sq_$+7iNG=QGYx*4N*=84TIhsmgcH5%P$1;$EYCNUZMWN26cLPPHB@$TxP9$fOW@Ai_R*Z`SM*>HLoq}3|SUb@g&{s0LnWA?@4=DmV zC!!M3W|nX0gT@DX`qo?MJ*XhDccXp6fbNPbM}4c};~$%D-h5-)U0uy}n&w){z8bG4 z{ zstaf#tTHx%Er2$_(?@ps5=0MHXjmV@9Iyg-rz{W-%1N0+7Njdp**MLjLnss~(I-Q% z#Olmi7>GmA4gs7xw3@sTXr1g~*24xDQ4efI5@!JAdYnz{wE*aik9`!aHAb0;r&lJw zcTkQ#RoeB0H=fNmZ@#&kudjF0JYUu7SG5caq-QI zQVU{s%8VQR^@9VT>u1li(O+Pc;?v?jApZS81FAeKNZ zomxUz1fBv|gO=Nw*fD^Fi!Ahp9)O7yu>hou$t+8Rlx33RMea4umC@ zcnx7`!qNwWuXnT-T27&M46Vl=%dw*!yV|j%&nZQi0oyj!GgUBZuMdRUk!X?;-N?p`P)43e9*j5`d2i&w$b*?3 z1Ra1lNH|GcBsBn?WSCJLiSKXz=5PIA0O)uB`#*@oix&uiYnf?nXTd0fs>yavzbaF? zns?Lnw41K$RBvkWo9cEmIdA3!&()6D&8A%;Ca2soODFs+qORGxULH(vavxZPCa^<=o3P5Yf| zHyfrxR3k{K2?z2B>ht_hygDFL)3h|msQ{m{`59sR=kV3BMIaRsdj z2_VQqL_fC>z3fPD+fX4ik+Bldn2n|ogHkvVg^HFP7YQOsF=(ix&KiI^z&60Jf?T() zio`-}2NzK*#YMmZY6Z}kK7X9w+y@0fW))_U2|5ew-d$Ovss`@dxUa>pYV{khe(j~) zxchZ6-W2j`BCaOGZl>m$oQlauftwwQ2CZE8Ha zJK8DGj|rYQhO~6UB4CxcO4cN6kYy-8ilgH)tMgeu8&Me25k^#^&&IwItr=RFI$X`D z?nJL$F?XaFKYF^hZj8Lj80EH(RL~swsiDUFistD3TlnOiV?m8)&T2(b%-MmWHIVx zu~jZMeh(poRH$B|HksOvSdWHvajY#c@Dkm?UW}R?F%@bK)6}KOr5aE%glzmobK0HPa}Nqf!>0#1hq=)%4Wl0P-N0tDVOPi8a(_lMZdh5(t5EqiXU@aA|5n zLTLO8DI%~X5r;7pnNlMRW>?t<1whHJOsj7KO=iOa6$2+XOlF+TIFp=7>;TN$L81bv zWRk;1e_+S31cKB8{S@f;9qsw5^^1$v&z)lV{4tjIPO;prv7DM(3q%BagklZGDrRFb z0g+5%YZ%N;+~^swGetw^%Mp%CkOEMrv;wi3`pRgFsVyGssl@42+9WaLcbfpG||5^KIMItFv^0X#qm(UeKSLs!3T=;2;t{4vSHlJo9@TkmvVZf;9NkgKVS_LR)8h zptV3-I+jz%@vh_UMaT2^R(#AkXTz;TM`%>jV8re;@lYsKFA$l+(rd1BJ2SgLg9HiI>6Km z)B|b-u{vTcz*@l8Q53i;fw!Lu_unSGxCQVjy-E=OAgtFzDBC(1kTlTE>oCBKbW3`$ zlPODx3*dCXl4?4bg2NtU^)%ZUdVpQ9p1-q68@gpbc^3yG!w5t+kdL?pL(pZUc(%r| z*!og4g{Xw=NV$w=((M>lDevzuh-U{*b5j1 zrh>wTxfH~l&oi6wY!AHqQQ+Ng2fp}uVEr3`(|;iRp8o^zr~mL{W8f=VueGh`LJEVg z-1eY(fQQ0mZW_tQ87imeJYI%UUO|JPvtAeL(V=4!XP`(5GlL96Prr%{ zS;6KxQ0LZW7%|>OI?C+IB>0xU+bRbEuoLVAdV+~E7z_?aHAj>H=Rh^#Y8Kvl0<0fR z4#D9!1BXoRJT?Hn()C&abfH$E%bP}wb8+x|1P}p^no$Z*j7|y*Fr%{!^Q!~3l6B{- zSI%iI40gi=u^FgfLx2()$$@SmxRUA>vQZDnmpcp5LFX;2kL!I{pz$XR8CAXXXW-lu zX6KM0labERvW9F!_7R`9$LXZ_YOdD;pp6^1S(Wh#hXD~dH$-GmwYfKWUntFhBEdwa zG@OkZm21dBJ1|vp-W%r|XIlzG-B1)f8o4&G2TZ}%gV@6VF2q($>ggHvo*9B6j}RP} z`Hmi(>Bvs$O{7jOYrD}N05w2$Zf6|Y9L(_U!V?7Cf%-ns_xcLg>jBUx7j!@!j4mbJ zm}n4I1J#!DN zOA3e9j#wijxSsg#F$$IE*0BeR)1mXxpeUJK3=Xj5?GX(T3l!@BRUgICm(*7Q;M`c0 zwUkS$(bw(zssrfv{--}b{1vJRS(+YJ#>6IKrLYum>A)$#Q>Jvd1UUuSBX=A{hDN5e zJPxn|n4H*6ZZjKd-3Pj0_^vDHWf=ICrAT?yw{K9l)yBW^;r;$zw0Qd7_pZ~9TeboU(0PCcRYTtyqB(&=E1*xL&qm*M*`b5S z4jcoj0o8`69j%7!)JYG>IznB26?$t}(V}7L0vq8`VBxTEWZRBCSRidyD64E)U>!ju zJIp&Aksu0P_(daYF#))K>~sHBSzmPkt;0-*gcG1sAX+l&Rs)wR9w{DOI85Nw$r`{0 zp1cI-?Em8?Y{IK-#<1c{wuB5V1d$Rgrt)Y$3R~n0JL=CNO7uSUBS}85@7m4z%GPc zU?sUI6-!52)gUE+=%hJm#bhPG5=kAcV$?wF0)3JCDzqjpqOT(89f*&snIf=*H_=~%7~E)Y*eI5eU3ETGm0<$3Kw z*mY?DNEL#Qa=dAq88GTz#W=|*I$<;#1rNd{d05m`DUVr*MWZt{yPBH@NuA6_Jp)6i zTD0SRQ{1({T?^bc;l2e9J&>&+fm07Iy`x80AE46K!lSbRvXL*!hWrSqH=(W6=}5IB zbhx#%=!_yQ5RmNsN0jb;Q~(JW*+F83Vi9A>#)MW33x#6^O9M(z`bLp3Ntz?H>xx}; zP93OC*~QG{d=^FKjEC~68&Qi<94ZDDnWlE7#Qh{_)?jz&Tpm4V!#7D*8@f*-O9z)j zN8B~&u0yvSx^2*HN8EPkMHB9O(0a!bL8y}ohO)ytQ$R^cRqugFxdgQpSOm2b)fVb> zA37a{P=G{;IZTj!m@LrLUJiBQHnXSz=u!;Xda{OI6E$~Vh?x&tf#2uHd7-R0NG}r00!qS z9vAVn3cWbOg>W&<&)q&f0Cf|Z1M8@jbSi;^pt8wAimvF*u&$wXA=En{syAXi5vL<@ zItGph;dl=m?*oTh;P#8aXMb8a-99!p9tS}G+28wd{O14oGZ?AoOwHz&u_9HXHzCWh z9mx<;6spl!I(ltlSuGXeB9+1->93kFCRc(m%U!FOnMpGFgLGZS&{_T%z^TgNEG2*% z!W81vbAZc!4crHCl5iTmS$zn1^e(gjdlP#$Ygse`&0H&iu+e`yO2VNe-fCS_7dmV3S2*5TMD+{AS?@1zENpKWKH@$5Bk>Nr|drjT4ZNzYA~c2YgTNGk}=x`DCNY1E_E9{U%kUE>9WuR z9d;{sq{-TT&XI;+M^*aQ10cLqagRYJ+~}zqU74an76N*>Anzexn~M8peTb4hRNc*F zG`X3~3^{#-Mx%{UB&i*EmY{=!sDNgGJEeoZkHD@8SF3cjfY$=B-e~Hk-mOt(rHUC$2BxOJ$=#y3tK{5> zlt2Xxq?wu1Xr7vesUSw#U_I8{_B5v!vv$p}^T3gTD+%{aIvQ~xaX>1Do$}Dhz>`6X zgQr3*6N2$Oxk3{xH zx$TBx9iRU+@JId>@V&q9v2pUX1<=q$*2uNRh)88jN(YJNP_NNcw2)XW(7Yqc$|T@- zqgOZUZYW-)TGDpq#zh;#P9WWKERs1%=UL3jjp_s@qz^WSuvlP6=oI3O*7@ia@P7F^|63ANSOnyJg!!_;ByvYf`#g%*b1oh^(#+*)_* z;l+9>UA4BTGcoo2j#&Zf4%k0&JbSz2r<{R<<18E-aO}br1dyB=FPH49>7!e)JHe~I_9y)wb3Yi{sYJB0DoUg%Olj_3 zi(Ay1mdA|dL6a;rxYW68uF~h{=GH5p&6&{8J%M zl{!quT?oej4kC9Xjutpo;WP`&LadEyVbQwTDpwQPgIWV>-J&(a+6?RJwyy5$Qj0Bh zGEO_g98?%#6{>CQU@p{2*jta$O1q7-0e^43vm zWLP&6g2`IVFh9s1DZT4s7OHEI_J^{(fQJqa3dO);R4HUF&{T;j43oeK#LoKE7h2umZ@My#C)77;D-Si7_~YF!!2YFJOsWw(v=&>1ujaSBndg#WvMfB11S*RRb2{r~>HkK^z8{-6Jn+eee9 z{?Q-%e*N_~zNvkVdp~rnO*#cwXja1A6yvQq!+VVq5iJxhg{P0vP3R^zfGd<^FPW6r z0;py}ddT_=UiA=7*i`D=2Qj}|cE*l6+f<0D8mHMX?ZtT!c8hRYg=Gbn2DOHiVc7^s=03S@4xOu)1!uC9swQ)0R{SnbHE z%ohydGqXRxl^-mHvWNAP|Ijyn`8y>1UH_9m0{wyibsTQKtsObHfGwTou;Nx?sIi;E zOK%aqNxcBQiOq#Zv0;SSN{-PUDbO$}Cpr%oUi?O1(^-_46CUAump4kl> zvvXO1G7-~`n6HR>l;n1YnVG+ z1_EKG=+V1|Ln^jaSPfh$t`ZgnPZ3EG>A-cTb{*Iis+BBZ!W5~0nW9k^lEoMsH^P3a zgwbFgXvOJWqfQ6bF=l-2;?jVnZ{W!}@2v@Km3oubRcfoWuEc3U9FNqY5cf2e?#{JT z9t&Z!1)`=+bO;*a!KF6Tone|g%G6=SG68uOmAagRw*l%`Ab zL-Tu)W&S!MdX6bT>)_hRm9Pck60%blPc3*Xfnx!V1v(bssxqz%)aw{F=i4w8Z4(P& zBVTMp60OG=0}F?bdTa@>2$&+<@YfL54z!+^y@lE;^d|Ks)Ygc$1lme1i{f|!jtF}k=77shQcr2aAA{=YrSgBJZS_OJf0I_VMV7M5^qa6AD zFuDL97kc7DyTh~Hh;_6b^`2Ca-i5XrqJ{brIh$hvdX?6Nu{d>d;+{kW;bCNR!>KTK zVX+JK9S|pjdKq_p zB=n=uj%2J3+;_7cW`H?p$)`387&-_aLYo|ym(KLq!X9f*&-(yC|K%rt1D}UOVL<^7 zie_P6tkhy&t7DqmT6b$NyEQnkfx0ltYP7|{rH-WDM715&8$%7kOj$n?KEBYQ@QG^O}(RZhIIp54fe^hyiE z96FaJ*qYed(0~k~b;z@Ymzz9R$H--Y=(f$gr(W`|f5iX@06Hxrkv?P;vdRvUIP9PB zy(b@yyRz4jMJrvBg#}cEm^qpnC z5iZD$Dakinqk=Po5gr-AJxqY&d5DS^W8aiUh9XfnvALmpuvZyok$b0K1?!W}`7Ut0 zZ8+U`E%(HF*R|XW3ndT0n!p_RIvN(0#5{12L-Ip=v`FmHEzlqN{r}LHz5Sp2Q-226 zKlzjRcmJEeM)e;3$>+eUJFHg%_X4kxZ1|j~BosUVh@%NG(zHh*TFV0It`ap&rE_R7 znoJ}`nUg65N);n3g$im)UeQ_Ao1rte$+oz0fQTCVpheEaaIjY)s;F7yUJ0ISVLo*2 zt~w7_rqgZH@da>l=!8(|Azv{Bt3w?z6zkLI*%(K%9i>?3d@B8oO6$$Ge zdS{P#aX^0pv}XYTshTnonwaV6nhhER#h}=rs6;Q+Qix*(=G9nhpiBnq25ZVhVl}uE z#d9{tM5bmnh{hp7e5sT$6x1ZhwkgkUw9!Q(OF@_3g=nHC08O+emPMGB!0u=`>`aH5 zI#lRj(lJ7ZW-1H9P7pj>JvsvGLuxBWYUZZ^8i}WW`seWc_k8WeIN!GbIxh|#!x^y> zycgOGV3#CoH9$?mO5sG22n&dfQh|CQTA@w_IAnbbwGuuVvV)bd$zZEcN&;w3MSbiH z*k{|%%abr4B%IGTCQS*0;GfAzMUwS5r3H4ebYX7E!9E-Vhlx5A=-#9`y6#tta-!_O zKuN@;Cbd)%*tSzcjMo&i(Dz8|{STmRrI#ol+HwyPdf6@3LRb(Ci3`pjemKz_=k05% zRGEweK(g7$$>fzR)lfbCq@590Bvwlc6y$?c=TO_o%%tc;4w5#;Px|Ph&4TWEe5Og+ z12;(gyQypE&?)O$b3AZVh4&<*olGvY96^Xfw;%`W$b=lE?y-7P$ z%$XEz6|od*YQU*MIXX0VEjr0c!uWW#jIRp-edlKYKL8#%YH2cP55=CcNeZ>DQ|sux z55<)fKNxBV-H5dir<&j?2^!eW$eqJ>M&CKhY?`WZHyM^fH7C2jFUE@f?Z}+n7S?lq$s?6@BUUd}%l=ji=VxA}loKTVP{GDhk;uQ6_`W zM$QJ?JGpn--sM-$vU5&5!#aCX*@^)*#>fV4Othrs2G|SHA#7Ht2-qHKqsBJ6UI8O* zOI3szjVegBS*%7KO>JjbcZOwWI?aaD&T!g0rk35i#gQWHL{9hE8Mx!c;O0kIUl#y+ z>vX`ob>;`D&y>Z^VrYpm=8fqA-IZ9lxbOW?U+QYss0Q6p+UlJRP zF}>ivLx17l`zw0!t3L`n*&B;>aC8Haoka7D!mN<222F-O8@MyzssKj^mjYV_Uvq3q zw1Ao;xve5fNW~B}5Z$mA;}XzL!Xm@0ob@q*sKrnisAeeQCV;*f<*ZYxcA(C| zY3G**rYpyEET}CoL8wlYHByir`K7RZ0rs9kq>p8VzAgatZ-1A6+1vkxpA&BXN536^ z=8yk>gzx^wz>{5|SceaJIb$CalA}<)7%&-hGT>yuDrgvM6RFYRZ9*$+9I=U}BYg?(o^+J7?KD%C)nug;i2zLzhQg@Rcb#SLELYBQ zEUYb9Al6FMQ@~qVAOmP_f*13C>`IiI6@ zHNkTps}N$eA$Mk--2hoOUo!&HT(JcEOts0-3b|I(G8;~_&=Z@3tSejwU;pSMw z*d%ngbpxXWV=`0X)Ht>=dI~~_Nijilat_+;w4KxU&T{Q6y|55gDx=K7(j?CWWj@d3 z#ANxs_>O(SpL~Q<@bv+pKl#&V!p?aS*_87`zX1H|H!^=*QgtDZGX=wNwo5z{SCxz{ zH9{vb5QqS{2I3USF`9^8iRRmIUE^u*IPF}gE61`1mS$MHqjjOl*a3z?y^y_!M@Tte zb3|ez72qVmpu#fRn`~Gihwlr^5-cHB18Sv}HRMh3P&VK?!FmCp|K)G^hDSLy?_U7@ z>pz)*@r%uUqmgfG?Zmf!gm80=(0NPqKMCu8_QYz2DUTKj|&}hn5*8I)VdT3j9HUhhu;{mVc8N_v$Wd2`qjY(*!++(yaZ z%-g|MaJ+by^GLZNxhmygmxi4Ey%K%s>txno5$q z2!t2*HP}m7?@}m7bu&qBCQ%>>y2cSRxBU@&SC}%(TV*J4RhZz$yh% zkh;?KfirVngTj-{y)lOMe2Gih0*&~rBhUvaRq7|oR##V`o7Ae%C#cPaHXGN8TAOhR z#UgP*c6`OwHk57Gs)P!`x;4#m%B3<6&%O8CIwcFpZh-+mmxsWxNE^9%tVhyNZSDPh`p)rF8~>Vr4zLRFR5>z9piFwyz2Lq3ozxeH84N40dE5k@$j*q zeX2}9eu)Cc8BP=s3l&GIov3xCN-tPKJVk0N9t0f;oSbNGP|5LfmB0?rPQWUmOWMZO z5!$R!@{+n`@zj7)j2;1xd?ejNCzJK)U< z+%-OQX8^bakcOX=z{z>@dHp<3182X7mlqe-WH<~OAi9j`G{9y8vW155p(`Y&1a!^; zLj=@X7S6Ckik_ckWw0ycIvJxny%=XFZU`JCoFbwrTe;J)1#Be8-7>%9)iPaF2=C(7 zukR3SOt*hXwe!JjKE`@{06Bv%v&mHM-(a#=_b>&kvSu`P2%i0Uxw zq6KWJ=9=6}F1=PkTNwUAeX{7~V~i7sL*#^U(VS*S(2gBAQCI_LggSwa>~|cggO{+p z=@%y#_9242*nclRw)4HelDDv2`DuJ%1%CFHs73f&-w@uc!WDozMCu;0(WAyCOUtv( z^1>)qV9cu9e4cH4I=8t4Us_pvfS<(kt4ZgdV~k7f4LF^k+ZWL1jy-&@J0#jOehT4!>PUSVm46e{B3?UcMUvPrR}Ge zw@GYsy^u{ELI=???ztW6?WK@XDlb_xP@lNY7@8#+U__LCoi< zz@H<7^n^DhP}vyJ>tn1#j(5QMz_7`~ZThl_tgrQYd;ndp@B7;U{9l0o#@oP;{DZ>h z{@K9of4k#5pBg?|J7x=1C|E#Z7UL6i;1=f`oA#~qh?*?o9u&1V)mlt2o_ z1&Bt;R6@W3bTk^i*ab+sHh%Ww6F+qye0y)CiPwc3#C%*3?awVjV-|=~dM0PY7#L<8 zR*T)nh+sSbDYoWDjq>ngt@jsz0093O@T24E7ycRH&wW>5DuH?(co9$+J$*oMEe1-@|+tdB$x&O6CV{tm_#mf!L7sRGVh z+)%|pC2?)Qt`Lq6hj2xrvK*SG=S|biiVC2tf>(zX(wwl-`$H#Hj4EJ2$z(LJdFlwQ zFgB9SfM!D{@xlTH28bT>41LW2)DADs*EK{3?|W+IjuB8;yYR)6@cAY1bH~8{>(dLq z?|1%VS>fUqnJMAJ(V}jAxHASm;+z#qk(JHq9`x4yd2_%w7Pa^iP+scEc1zoq$>lUUE1d%GkOp5Mf!qCDMCzd3O3TTJ|4Rz6d$tNS}jw z1;j#O8GZUgsQ;l~{}J)?dH}TEzj*bpI!CS>pq3`AtJsHo5z0^I(C+Y8|EX`n^MCSJ z;V-_k^3Q(iba`4yN8iM+OHUamx|M0MN)hi`ny+BjbQ` zY`5jDx7ie1Jxs%im8S$yFnbQWQ*Cm_b%mbIdjfuKU?pBteSc%Drr<1TN6(5=CKk{Cme(FV=K68lOyG!iuR_%^~c@0f1g}{rp zc>p$g!g7*NgTeFX1ckCWbSNASot+I(nXo(?BI>;9jeQJ5KMye^?RquzT|rzI>d8dD zFz2aer%=+b>i z_Y&>|+ylG^aAX2$1u^Pr7eu&6s)@Z$01c;e&@YneFmJMP8zYlCGYrpqx@69;tpsi= z?V~#@U8uz{?OpSA<@9{fbk|f5U3CfhDzaxhA4&_9Rc~X*Hs2KI%E+r0$hIwQfF^mz zFViOIWO7V%PE<_J*g0eGrhTEVD(tFQ**T`!cwG(8is6|NHwIiG$8S~%rVt`0sJ1{X zoji5gp-0^J;9Uf6yV~1-9>5id z9l#xg8BirrZ0ueSzc~2GgeIe175cM@Weu-FR5R4cROhC8-{hx&ZBueP7?CRXU1@!` zA-N-l)3`F|u@C-`B~~6RqdoAC%|;HV8mt;sotP6q8UVt+WM9{8oT_2(#1n(wAo0|o zYXW;nm7AzoD8^*yrBlZa-FMnuBX1k=qEjzA_`=0I5qE+gU_3!uBh(cU0Z8eIe=q=a zv9{vpG{AEM;K{hWM#{&{N;<}tpvA}_14J;hvz&~!clu3LS;Z2t0)(5vi^ESHTmovM zI*{{8!KO^g_3S0gsfoi!=EelPv_O1#A5JRMHGJr#aH9_ZaY_Jb=Z1Zuc24ZwY<7K| zXHXN&*2jZ%Ly;y`dX;JE=4S%53kI}n zh4C2jFVT%k5o+={3fQg0Q^pI z5+gioy>Ehjg3=8u{a)Wr+HGm$!_%hy-2I+(n|IyWeld|y%_}7E_MW0{q#}~nLCc)7 z^0vkZIHbLLqUsWktf@~C>S1A0T=W`56M?j97YGIy$Xg6(#uMfFoQmnyk7vBTMK(ov zlCM8XBuYM zGRIuuezwEMYH2_)+j&6VoePpMX>J7?Paa!7sEpFrVXMPNdxx`}kwb%wpApaPMhJ|n z@U!uF?!BZ?+kLa7R@J@J`BvCGR#kJ1U}Nid`h$FmysRhzmh{p5J|x;ffT)&8PbG~R zL2c|J96$Nsp^H~tWSyz=I|(Qx15in0At212MAh^wx>@0u_VGVgUAu%HZ=b{}-=*DY!2 zt2D{rEhpdPxIw28_h3ER2EPrOu?x88E!cu+pCM)2iXXib9w{ccf$!3h%z5kpxz!BVHU|>q|b48FN{eYSip4$gST=%u@cclcczA< z?+RI(gjBm?K3wU3eQlTg!{5L02J4C3sz2V01h60Gtz|y@Fg5|R>4XA<#)i#m^_ zX|J1mNL@CSUE=P2dfMnoo$|d2?icrq1$WHuk}f84uy5z+hZ`=j@}7Y6(?T z44s)Di-WvXXpoHEhMnnQFY%1HpKB&n3UQS5q{@%-Gf>Pia7b4XNKm1eisU&9*cn+} z4Gz>h>j~?U%3sx~p!F`txV|gog}^19lBy!Abhc2Byjiiv!qLn9COONlhKHJ;$&P6> zb}F3!y@S;z_x9dQ&GD&XQVvU+qTtMv9#mfOtA}&#tG2Q$`v`wz3nuCK&?))GvqRx3 z+UU1Y(1vt>z0mQg@{Os*yEMd&+0np<*p7GRO6TH;29|Ls#5^jRn+2?WNpi}s_f5s% zH{r{J=t#FM789T7%y8tUVhjz6X(>CATKI;YY`;gTI%P_f&GE;G-uLbX*^(Y;+Sw2D8iTW;1M zS1*IxGWRsXzMmW?Z?s^OKx^|i{T)9e2@94&yrR9Wr7*e4U8gIq#7h+-^3%)GetQ+K zXiaR5rM4dveDOir#kDPwY(%k61Za~L_^i3*)pc(&mcRY#*F_C3m01xo z&XY}*mH+C~Wd*Nvf?n|=@9SM-vWC?FZs>14FMUzGIIsPA60TN)8JIKM_8eW|@~WM2 zqFwxthDKk45BDePH)cG#pt!ooKv?U8<8u?9N}G7DN6 z!hpTCLQ-PjvNW1Ph7Cl}Mjz)d&=!xh(pc6!GqsvO$6_Z!v8MTZ`}IVC8~RY}c*mKn zN4Iw9!7J=8<^8Z#Yu2FI^-ez$@*$^Zq(a<=6gdf*aVXlaUypclQkh4550^{B&&=Y7 zkD}{2wV;=J9F^sLNSH(^wLUXB%*{47%ct+Akaeg;J(9zMxLWUkGK|SLX#1%va_F0X zeX7WS~4 z!@g7E?LEQ$zIghJb+$i++W6!9_!CSzTJp4v2EHYI&r+AVi}AFjS%8mC(B#>@nfh%^ zJ{8EWplN=tAMCPso$_>9^#D*dBlE9Czu(+tQ0Z2u_Tp0J3z89`^_nfdH>y1!f}HDKZ&Kbs&k)PIBM?(STZYoa1oUafghX}nV`9Evx!<0c zW+l2sbWcBG6qS9Zw;dJd#jKZIj6X#Ulk??zT#^xR!~t9AnJoNkE0{H#0pT8_h_TEa z=C?NMKdq#HpmqimY-mg4wXmEb14dK&X`dNPH(Z<+;ZD}{nzl~+=bBiMKYdHV6TRCSE806NsBe-3#eCtv8IK+fVo)?HPdM({4Cn5knq#9!jkO-#5JDI z+tl>-@P3lt;mEabJ%gtpbhvE3QI}BK7D@LEx_}?3QQY0jy5KjR;2dQk*lf0uD!%WP zO*Sxu$Rvw#ZRPS5T-RjCC;ro#2C`i9oA-V7DMZFrF%NF}F2r)ap<&Jvs7bx<_iX1 zt$)3s^(kYPhSEGgyK;5FPc3Ypd@KvM^uBFjKWrmlRro|IsCCDap_F?nzO8)GqQ|*K z0RJe;0vJ%WSxG%G}eyfv59iDgz=6q@=DUb7dx3Xot?OiX}q?^7V&i z&#EqU;Lk5$U(_RkV@j{TRG4S&Hq1{)!VLuBlM@P62Ue-1h!hWmr#2fv!XfY^EBc6c zU`*z#fPKt?s0n4>Q)gfAa~9`DMBJm?yIw+!EX$Ft_+G%{`y(Me%7iYNJ~ z{+w}hCxa%3sS?1|Q&9Kz`5+b1$n&RCS1vrT&pGZ*3@DiZu@e$Ba#Q?!xIUP!B?h4} z8Cxp67M~u|v3ksPt2+R>_UVR%m|t)n;opuyIxkKA5&JvJ$>quz{0sWq=3l{XIYB=G z5@OLNDvEz(g>B$YI$+wJt*a*5|h&H~u#(p;z`B=!`ZST$PTFn>ZGmsX$A1=2!YU z7V0ttsZ-hawKaD!&-Wg*SHBwc={YI8fD5D?d0IW}$@fsc#ni#Q>@D+ZC=>8yoOCk{ zjIy0<@hS2owUY0L8CFs?q&l-d1pvcnItdr@eC~Kf*hUrh6ybyJTow{g0Nq zxDp`0`!mVW4F#+_T;k`BV<@Sn#1W|j? zZHDy*y+~_OMhVSXX$(QmK&Z#_(vU7ISB4jh^@oFpv63KE!Y~mG0Jjaqzvv0Qci{&J zUAw)WReDex+&0$0TFRRy7Y;Sc36#q(uFt(3a3&wayHI?Db;(IElhs>bJD!e_Cv+DsBL4eX7 z{SH!GY7?1IK0<*uh;aWipdvMEl_nx1sI3B- zaTOB2W$~`x_(O!!9mPMR$mBN7B$b?piu}qa=43Ep$F8G%D65 zU>S!wI4engIg|s(&euk`gN6{#tLip0*H9B;DwDFO{E^lNpYJ57l@DS_Ct+%2qq(N1*rAd+hc%SSj_3T4y_mROKtY95f*#9 zZvNX=868;Tuo$}4*rA~LixTUUPn7cJcj!eiT^ht$?pUn^JDYh$rNn?0OF;zGS}z+P zq$`J07@l%n)3JS|od3Hj-TI|xaFf#W|1xZ=y;UyknZwd=9rNQ#?eV}hE#MBeaHyQU zHx$aGWPC`l$43-0fD^y76{+|KN!@K@*`-9JMP!6!*~P%362f3fVNo&m$D&f~&TzP=90-KF z=Zm=fP2(Dl7V+?QT8{pS69h2)t!U=#3$v4x)9|qOg+blna&pEv)CVA1e%k{2H|AeH z<>Z{9E>6yHfT*k(CBQoh$I$;n=YJV<7YDfW-^g?|2MG>g{0Cy-0)xT>JfVPpMFsM7 zcT%o@YWQzD24*-4ASx*eZJaQ6ZI-@$++#KAI-(vG&GQcy`-X-PYAI~i$NFx1i3 hUIr{JDIqO_vk<|>r}kaa8s`C^t7)k5QSC*<{{Yr~kz@b> literal 0 HcmV?d00001 diff --git a/img/android-icon-192x192.png b/img/android-icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..fed3b054b7f76277336adc358c96de3e0e7ce675 GIT binary patch literal 30154 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 &vO5(F+-gi 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 TD&waftpE*GU6lqUNX-8M$!N4m literal 0 HcmV?d00001 diff --git a/img/android-icon-36x36.png b/img/android-icon-36x36.png new file mode 100644 index 0000000000000000000000000000000000000000..b0bc64e93f92dd1385d00f0bdfd0039daef8b1de GIT binary patch literal 3176 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 literal 0 HcmV?d00001 diff --git a/img/android-icon-48x48.png b/img/android-icon-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..844a667c21dc514f6755b9d3cc5d6581c8a9e4c2 GIT binary patch literal 4712 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 literal 0 HcmV?d00001 diff --git a/img/android-icon-72x72.png b/img/android-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..e41c7e79b6035095246e3ca71faa91add87ae626 GIT binary patch literal 7676 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 literal 0 HcmV?d00001 diff --git a/img/android-icon-96x96.png b/img/android-icon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..2979534978339f59aa3cf56fc1c6d4093daff1ab GIT binary patch literal 11652 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-120x120.png b/img/apple-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..32961a864aebd2a0d0e8765838728520ff77c2c9 GIT binary patch literal 15896 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-144x144.png b/img/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..413d533e45d579fe788214e2b6f7d6733ace256c GIT binary patch literal 20963 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-152x152.png b/img/apple-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..cc4a29dc2fe3bea8adf5aff52afb7de917076b55 GIT binary patch literal 22322 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

6#42y{r>RiJHRet@U)Vl`Vowc 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 X@bgn%lC;E+0MJm?dGtxy=GlJ%MvyM= literal 0 HcmV?d00001 diff --git a/img/apple-icon-180x180.png b/img/apple-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..06249e67a7150376d552b900a014af0239f941f9 GIT binary patch literal 28518 zcmV)zK#{+RP)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy24YJ`L;(K){{a7>y{D4^000SaNLh0L002k;002k;M#*bF003;+ zNklidj&KAv_zw}XY$L!RupI6A!yI$Ta zy;*P8(_H+hpTJjp{r2zwX%sgcO2NS$)eXfA#Rw1(bVTonwjs6+eLJI{&*-OnwEI_RcdyW1y^q*d{B!@^|JFzS)_ql0`KX`3 zFL?b+e`3E$BM!xJQwv@k7TnZ==S#(l!-8T4DS@Z2!PDT^+4?$kNQ6$KW zbIgc010K(-GxIee4Uo~y)_1>< z7n%8T;`-(0{t@}_|L))OQA6S9T~9wk|7$-0+`kVIdEF(T5SoO5(7GrW1h5MX001d~ z0wBP~Ip4Gq!gL8`^XI);Rg9qoA{T?q*@xz|fgWKb8 z{*b#L+!g>y%KIfL;&OZ33TZr+Ana+9{;}Wl&*Fdc&;3(hi+B2~vYtMm0Z1ga09pfj z0L9sQ;4Z)z!N%RWc(8U^ahZo`CNqH)jDmH53>b|hzz)D9PN)U}i4ZkFmTx7XJxpDt zz1%+`SKk{4AKcH&&pkNjBZB~f12*}!u77`jbO9fhGH4`1f)Ii-=Z2J@eT5W}AdQ5t zV&3Qx5h3*+YQ3xXuHKrWbwzY${E*xo<6@})-aqlr;$QmbpC+iEKA>5t=D^DhxVr}^ z!i-u9*F(qF#4ZqK=H@hWcbA#L8MzMxVGvx{Z_iYOog@$8K+#E_khzdv{AcTk*U>150 zMGy2I=socpEh2hE-+GVMx?1be+NQp3ifs$^E*3$>HKL@s# zz`JMQbS9z`)riAF1Sm6}O0m1r?O4MPAzwpY0>uNx4b_A~p%_`Z_MF)aU;q{%gEP{J zm*_m#!*l{y=?bqikP*jUkHmHz&GV4G9(}L&1oJV*x%~tadfJ;$bX4~2iQ9pA(BrP)K4GKb_BWs=T6+M zggVe20EyznpB8bb6}SXYZEU;*cw~NUn0d6o5tT>My1#Eb zfM-(s;Hz;DuW)#k3v)*Cs~??b&6GnA@4sGO5jea&N9l5LnH9Vyph;*DHVK=cRl){n z8{gYPYMFhgOVJ~O8Quc`Wz4)JlwsfO>DCgSHlQWo555a*EtAAhLLh>f?C$A<50F+# z6~H3kAm9Mth&&$vEaQ6>mny&x>gzNa4{v{^^UMJr0vsPeB0ucz-0NQ8%rE=vUvZx~ zzZV14eH;zI3Sa}U3OWNg=WVP2&dM_T2B86J%8O0Ee2_IClhDZ2=hpEFuBQ!X0Qgn{ zKPsRYu{a@c@0Pe3%$&yJWOcF{c_4T+;%LAPfg^z%Ty8JpsJxWzj2V@$BP_2lbjcPj zzJz_(bqb@C4$XzzKkn zsK2^Nx0(u{N)a5giV z5i$eJ5E+PNW*|AvMjGEl=wIym^j{Kw@~<_--7BCf0qqBaA^}~C4G!ldfvr%8i7eAQcq40UO8_#0kVbh*uyh2p3^)q-c;)VWu#b+>~{pBKD?G36WWz zFU7o+C<$u30rbzi2;dpuO%(@b`Db`xlvk2s&SyP zkgzOjQ=`4qW!B~1P^_brKqLhHFR(+nP(#75#|L-Ai#_s{69IAD80C#r@_`?DpVxyA->vX1CRNTMV~O+*+QW zIdSXIt>xyhIxZ3VnkG8yfindGKtbfZ`vPo+G;0Fa_38)2yek&Sz8|~}+8X=50Its5 z@85rP@8Kk2#b*A2J-|0JtjdNFBr3!n&doc|-R*2{hwgT0#m`ns^;(M`YAISuhe{Zm zT5(0s=B62~F0{h}Un*(-rm=EahJ3rOyKe$;2gJ`1pRep6f19T-ev$aZ$E_X@z8tE1 zVW~^0UP@*0L-DfI;)m*XtnN3}>}GMht!}rA*|TDNR*biWxOKy=C6KfF0UV7uSmw|r z^JiI7@`Oy(2XgajKe1<;6_2ap!VI_^AlCRbUGizzK-+an^I9R9$}9t+*@D+7x9@Fk z;i{@)n48huQ##Rw%#%mR4go#HRmPgaYVEPqre1^C!px%(#aRL48*8#8oV*s~b<`p>sr_TcKehKZp_bl%3th5()#7$X@ zbt$%#r7T{{p_Fo{?l;BlSQ5lH)%dKKJ+HYTye(u#Wa7rDqk%`G4$KP2!m%kNV3tvK zB2~Hbn~Ad?@Q;K`bjHZ3N5o`cfEVEG*ceCmW}L6v;-r|FizpIGmK$QEG84>KJUU)c zX7?pZgQqf!$04$btOBcGOUP>!Um~pbT59jLb}hB5*G`mhD^a{eYp&kyL4+=awj5w( zc?0MN>-PJAyT6PNX_$?3Bktd`et*w6pUnE^RVp`zdMLKk>c>*cv6gZy)o+UVZFSxj zv)fACR^#(ZJ};J=zXIMQpm8v0A+gvPP{~7v%!daO_IB93v_H7$U%F=au#6%jXaZR~ zA?d0WX#6HlRsvSKN)7ee zRclADBh46KuCCTH-H6C7g_+R{y;iam0>mHrfBn1o?SJRr@#ygR`PSnDnuVYvNsf8X z)j3naXr^s*wB{aBDpeL^J-Qv1;>TM3rj~M3i{BQvXC?FHXT@;45YK8>GM?3}Uf(!z zaLg0~g;Y*nX@WTuhooZe^)V^gm=9~o6MVuRrS~SvrG&lHM`wC*iO$^b$E-Qbh@V8( zy&O1pjro}KK}Y^$Bfqh$X@;HYH}{J{18E{nG!K}EJP(x8v6P^^+lbD!6t(J#J`QDu zM3U~bQUEV98lGzN`*8vNTYeMpC;sGh!}fJfL^kf|L{>@NB(G3ijE95S;ox?x#cpf0 z+gj{db$?be#dubjfS#bP)NLV-B};URL)8QyWVg(RrQCoCNfah7d|@DY#G?(k*O!xn zyf;xsP`(sJX7m(jS8TaGcfKlok&{uX3r@#XBQuM=i9t>u~}7!#@Jt z+yE~ZCSL}?2S8m7<;JZPH`1M`g{;-MRO4}R-YmHRd{*6`7q{ot>{&J37UJ1rxLv4c z3vjy-H-$RX1aoo7$9q2ZQHW5M+ajcHh%Q9~dZ(fbF{U`i|1KN882NI59C&;b+)HsQ#ko}Sus9Ek@#c`#jAx580quNV$=gcYE~eXsxLK&11voCm zp#rr4?tmFY8;#|GV{}0siY*e%CdEc|Flm@0IodgzT^X4JWb!o0z}Ud;jm4`^Dqs6U z=MdxoGxK@vK%Tcp<;BG8QZlCiGDwSbfHjjiR8qwhPIf1n5gUO{V@EI)rsOCJosJ;b zA$Edc#^`P;-6DbrQ3~7l$BAgtO*Gfjh4W(r`eSba%YpdZCxQ3hCGhI%eI|jo47cBE zeCKVi$D2}@T8sNq%$6h`*|C}(Yc@`vRbztLn3WCUW-;6xfa8HUF2u4x%R*%K2Qjas z3S>&b2&qBQOkqH`PzTW^bpa93rGl1IAqWv&Vi(XwhQ!D;n%5&yS8Go@Em{XQ<88m<}8fQ{0V@fa(i%EryVu)hc4A>0Z2y8I62sV*D=n<4Up-!M1 z6VTD29#n{mm`(S&&jpR3SsouXYQMsIR6s9py@h@_K;QCh#Ck{Qvx7I|27S!1e5>JG zKI!%CcgpeEvr-R-T8h`=wiLHRH6E++w%Y6jGBR`O7(r4qH0r2<|7E(A&@hDoWDGH<4W zREN|9>K$kXb%PqS``jf-V#MrJjI^U&okJXH2 zLby7l#A}W+DKro-pa*lVNnpE<)DSZz8Dt}TnK2WBBSEDTbkGc>}tA+u0UhhMQ@ zso4rOn^o}mMZNcrwH_DHZ@Y|0oHx}lK+T&&g8EoZ$1);wA(oO1I!mx56Ky1gk?%xK_(KXvZDbx@LX)C} zFlOw~yU=?;Ef5K2U=y$f2cSnT4YEg$ii9w`eOIZ+L$;ialp~*`=nzGi1Or7%xk02D z21YWJ#@N|tVrs9NjM81Uzn$oXXhxn1tq|{JI0bYc;(ZtIbz$Nv-!)X=ZLQBn^o>I<;U;)?()bQW+TbNouidlT>7c(33Iv@;khom+%9 zNewwb+mV0{0AZHROCmqGPjNjipr1cSk6?IZKOQZt6;XvkrMwb;uw^;ao5OLrJsj)d zcvF{pQ@q?1x0~urKoiFVwT_GFP>f4SDrhZ)4b7|6i^)jSVoW~gSxuqVh28>f3$(SX zZK1YywKdSUP+tRW4aC-=P0%@@EmHGl)c|y)E=U8}mEtwCMm;&v4@R#Z=Fq!VR}d(( z4LHX3jDlNU0Y-Un(2#aI$Q8|1AQhHlH{FPaEcS08R{|#zXHh4SCnNK0JPSAzc4Fvk zhE?J!sWBg8fSNKwbJp9G62q zF2{OP4$Doc^~Q_e6!Q_GaZ?>POGfD9VmMT4aYJ=vWxyc0GzLc1B&|(aDQyU?3T+{^ z9@<){tr2YvwR6wo6lkZee(H#Gpq~R;gIc?^X3D`$z&4`uI4my%JE-TSVXsTiHPN`M zpdv}k6&EfaDVgOsyNA%39m~n$m&QDc_Q#xLs^H*7BLSI{-@*#wY~(8FOfnDf%#mvw zu|^KmZsWKHbT9$^AyvtzvmOo5zvGYmC7kc>&_md)6190SJfK3bQe2#NDDKC4C^vN} zH?@`xdKp*1QL z=y)j5FnZu}gNmdcR3AN|%Z}|bcsLJUO@5DK1F=EaK&&J;gK~37uB0{!tH_PQ3TOj4 zqzzKhm&{W8n<~fkKXy3KLX>qwtJV;ORDoCxT%0@(sjLx6rwDZ7pJ5du$`s*w(-UK%WC~ z4#c@5Rsn0K9Bk46v)C|mXpH<>ob~8Hf_wt{s&kltP7bpQp^b=zP$wfeB%p;bDaOx5 z;jFY!p-ALwSIQWGmN2{W7f|P!+yGqwPBuUr6W9$>1F->Y34YDr?YMkU^n}aMj|XVd zSPGfsb!T{vX3mtuz{Smu?mU*_H(u=4-19KIG2@LV$N88gIvgr>Sjbv)Hqi5Gh{(h_ z#YqENn{ZwOr?u;D?Ycj=IBh-7YuCDVZRgOIxpU^w=RjWrv35*QYYm_UG@^1wX~??7 z4qC$wWbQh731(ihg3B^UMkvc|h(g3h^o{7<&?C@g2}(kfqtR<9^Q8cqq@Fc4Oz}ne z^)y$e3z(pk8Yj3ljx4J;y$=2d=Y4DNn%v*hTaN~4uLa019i1|_FiEa_4%L9gjf)$P zUhL?_Zmjr?o81gRADuY*sA?pjQ7cs|;coEU1S%pk%xvZgtqJQnbh_`jzuR@?kYi+-W$4<=ak*kfY6a;yQ>d`#^-Yk>wZxD@5!vk1GGD^li!0zGkXotMjp(0FwaQs zW=9S%8+jyoF!Er;VN^6~Axa%}XP81`ykqQ`dPv(ATF)KlS6!#~o9ILeRY75owP1}v3oekT$tF0cbmFRtdk+l3UFi9WYD7TOs;6ZsvPK8g3N&Xj5a#N

ec!x->kQ!v|qxQkI@3mH|8>pm%{kAsOe8S;!(MN2&qUjEg%D?mW?UaoYRh3$1dIXY!90t!piG18pIm9#^$@_EfSHR~g~<{dqC3=` z+A3qKjP1bKZY+;y-rFmWc2}a`H^jMFtet9#=n4()wuCYU!Ll=R$kt1CM#qZm`0H}y z?@L*fpKAab7$P&Bo>kfGdqxWFyKJ)Kyo2) zAh3YflP4?&_MYxW@Y4s`LAs)>oUhQ;Y4~(Oakw z9p&gkw4j<4n+R!0x-dti!m?5(%0#535XW@iWqfe(iuZBF@l5kY7%lg1(q>R|###_- zLEjek?ZCd>ux~fkw&x!Gd5QQ~L4RwZ-adG|eQ>>fta|%c^|9lkw_4T5ju};pIm+P4 zj+*!$nlmIvPB9E#%Z_DTr2O-lW_4q#`@fkf1O^8H7^5CEfigITUbB(a4AqR)h{edo zhy`RGLtt_6j4INgYG~8RhGuOHmOV8_s6tW`VhiDt~H*H^B)!tj9z1+0j zZ5g3k%Bw_(Jp@G{)=W3@&CVE{{CN{WnM{Mdqw9h0aa-BWo~7am>JgzcU(MD#5sivw z=#A=|scjx@E!x(iwN-6>LF)&$xV7lFF1=VRUM#M+kBh$P`HjBi#WQ`!ThH|Aj~(&7 zAHUV}dJ%=uYnlk)1JS%M#}T|jcIN+|{I+j_*W&?t^vRSX8D<7k>?3h*3F?x1 za~Y{YE=(|20gJ$j;l7s7oum2%T{@#ZE?xyy|Rqg#X z`rW2}Zt7cC4-Fo}$UP&dF^7enCX|z}9Jg)ElMFQ_?WJa5GO5S?d#!EoGZh+~lAQR8 z2u2G;?`T^?R>(Wo`;PNn!~I?7-OJAR-w*rZyJ27YnOI(&_153~YvcKMd^e7V8$3VW z=x_VZZ^Cc+^gH;i-}yGK#=Rb{E9~Cf6uf%1;pbc5{_WrXSdjT8t;YlOz8%VmK~J`V z#c-iAq;O(_nw4Z_0=NQLFu*LJ2y~4m8UV|Hj~Eg|xVprm4<5!Ah;t}T9lGm^mre2B zCcU>R-dh#-o1!;`I%0?N4r=9j${i(Khf*8|rDy={1w)^q&okKf`~fBfbbTrxhLI=gr@HJbHSclG+b|@3kQ;}l!7-od7MpP2j zz)E5OdIxh=D(}07I)Jp-dUq?5!CO`zM@zPxwt!AOkNXbXHR)9Y?i4DfJ9}=L zdR)AW!P-6p&OL2UhZOA*T4RD;d!q*z;64`12dIH!b4+d=7-@zC zzdB4Bv`QofF}TRnbv2|UG-&WI0^B659XRiY(316#wynurxNtr%d;EuTN13T-Eg+@m z=4^kAj`cwCm0Dd+^lY>wC*eKWK*kG|#X0TJNQAXm~ho^T!Q zk=Nrz=y@KlQ^p}kG$%4Z_u*VTROKgc$1xnNuA(y|$v`$cbJNIV66^=*o)M!hJ!{B; zORHM69EIKqYqm#Z0HZpW_h+wU{v{W&jub#3_J-gdy~lMz7?FBJ@ez?VBpMZfvS$MI zakR^U&A}cp1u6r#)$q;>$K7`T_wNb%aU?_g4XA;S0?-(vM;cQ-(_)R2qfR#{C-kxV zr(CBP7J><5slS zuZG#xFYon;IrKQ~orWZ@=g1RF|z}P+DZBH?@dD)E8_u}bF-+~R@syAy<@xsdon!jlGg}8c#hxh zfc61qhsoh^R7*g|A$JW6h35Ceg|;=5n%lSfG(SSvOM$&6 z#DU3E=WECHkIfF;&Ro0V9MAsj5dIu&H*id1&$ML9%Q=DKq*t;mL_ZpP^WN7-@BbHoKlnfRh#~g4>mw69=P%*g zGxklXfVfIA=9qEHN=h-f(qMeS(@DWONqRAxN4Id^?kufR|x(gSOtQCQBZ zM<1z1zZ%Zs7}nKP{CL>0n;#NzcX+X3I0_hyk?LUpfE>v-1HQ8i1&&{Sh<-FcUjz9; zTj9DaFkGA_op^>XU8!%)BQsOZq8Q`y_}OU5*y%_MvtmhPst02|8kQSl-wH!v@FFY} zH$&?ID%kUr!^~_gw_DlDn@&1ebPHm(`XZl+0BDr(rj2}XR5J!MB9z1saik=Hn6%C4 zm(JnUXIZaRF*q7MW|yAy{MrmSrV{QixAka%&N}h_HjfCa>uYWYQVF1gEtHc@u~*wN zNanl0PxWhV3`gB;7ge}X)7~p0LSRd;2i560E z8GtrHCa{QO5{6uyI22+#7`7W@U!77R7_=&I0k|4%GuY;|7NcGr#3pF#kO!g}*aqRb zjRZJ`Ji=gb#-%PD21FV1c!PixJ#|3BM-=Dazzt({`N`pU0$L5RMk*LtkXzwQy>I>0ozg6$%7m+C$Yh$6^=|Koq> zqsG^xug3%QI7`$8&`P?6(9Ez2Tt%!VtuCIMSTj1a2Dyq{VvO{S6r_Y$VycTn4AQfo zjLKAt?S<%-=m&$k5pvQ5I_Q<~#b5`6p96L_a1G!rAk9Y*ZgdZL3DJY}ND>NSgkYfu z&=6|q5ojZOvM^XUr~zzkdpYh>Bf$VO2AGAJzG%MyWg(juusM0n3z&5kq2YoKND9m^ zzx9X_8bHP(ZAd`3l23Rl-(-*A7<8$Xo+D8&rfS9Z@^lIp9^W`Hy?2%pzor0D5m| z=;}B}77t4pJbdt_^T2*gqpj;=#%uLDjLxJ5Ji9V5i&TRgY086q*#H*6UH~|L)Y$q+ z)}sM>8_8Y(SS6iPD{f96HwV`cRtRSkmm<~%UV#~lfF-~s$VEg;WdYQE^AaRy}_n)`7ja`eGj!%=?AF1=5FNeE`iG2BxOTt()YPg|<`Ew_N*fWPm{kH%g{Udm*tbC2#H~r*0@i}Ih4`@`Kh}tM zEA;sSozSHff_1_|qGGgcE@0O1_R$>H8w`Nm#&b}zVw$_`CNHxteOc2U3nrLnvSnxB z_8s6K`4@q01GYALIs*Rnf99jc-PdeABA_!6bxE5Lt5Wx3iYU5a3vq?G8gQzDH|;nZ zBUm^Ga0+0_lAg8zYKRRORwlbk)et61iLhOvXv~zP-x*;ZG@rS#1WzE#g(zawKrB*h zLe7y0wTmr;5=uI2m#l@`xx2mhqS(*9DDmF9p+!$kUUf*JK4-ZkMnu;T{+eDFQq1wJ z(XP>D>LuGx^NtH&dmknkjBSZfODXfueeMGLy|O9bcm5NXM$EtQdp~LnepT0FZwl4G znR3K7WNiU7S8A`Ba4w=Z(EA=Nk!h>21h6PYyO$7Z2sKiD$wpJ!cI&kqtoD&<6emLI zaF!*J-6}0jF-(*PRFt`MO)5|{F`5t^sTZAE=Q!vhirBND?9m0CV$ppI-FM;C1NSX( z?txPetRbvDw53KFQUxj4qtD6f1bqyk=SU*6DK+oIWuz-dx2OmrI?y(1YruAgIK3P{ zi_4G!ki{Sye8+FF_2^~0E~$ZPk~Xo2)Csf*ZX{P1y^G$H%wKwnZ&u~8NLoT#LRca) zeWlS|;+TwbNv2)&Ew9BS+>F)JcsrdbmBef#HDsJr9I6RuEy|ktu%6f_{&yY5^kEY@ zoqYg+)3qn8ze1&1TAwiDxt^y0SYcVl%-T;0?+w zKpf*%DpC{)OPa4o?ZG-LAgLQZI_pA#n6h-L2-Jqf(*Vx+kb>C~Aai^eo$TL+M6m$_FS0i2_1F z$o5DL3~OP!r>z1_pqc2pu%P-CcvG)#;B8b*_UcIv3pjGyRucbQB%Hf=7PuMF$-xC3 za{#afi}3SW9WRe{dQ2NyixB$+d^$idQ{&ii0D1gH)7iY+bXnG z*aooAC*gb#obQ0U_kf@K3E|}zK5G1Z)z_oaM<;1=@HzU>hBFF{g!K#e7@EX{v=wv( z^XMp%`L#FEEK>3#IE63LI~BlaF<-e8C#W&!OKf=eOdaRg!7Ga)l@Nr7a^gIIqP$%~ zr~+yThs-K?XgPPgj*jP4_Dn+b(E1qsmEOc8c#zR0bW)9uP9d0$$YJG)QR+y!>)wUd zMsqZTKCG!G_pf)QhUqpPVuZd;a0kwJ!rgns%P#?+|IC||)Apz%8S*XbicQHnZ6S3jUEo6F$lKZUPIBL9wWI^+ z)L;_l7B`@EhrAoS4Tn{c93Jgq%=smfGBZ&EXvGN9vam6HYi)Sh2dtzm> zXyS@Z(_j0(H2L!inM8{qnk*tL45=P#yAW5JxRY{YxS7mMW~sSpW-z8!Gt>HgERY$^ zhu=15p`vhzumfC>TIY*0wK#O)&;o}hoB^B^I5}}^#EH|nHIJc|KkSL2jo@aPHg8Te zCwc*Ufl_TDM{}d6sheO783bx<8xev<$O3L5vyPFQ=SO>zmj=+yhFfC^cm>J=EXTmj z$B5_e5clr`_b=Z7`mbkQ_T=jkDOn)#9AwEZ%n&j5f%iCkwH^8 zQ*o2K%gr*e7!|r4VxrP1n`Wfh^w8$?c9Ny%Hl0vKTAM9GTB~Gq=D~m?LgygQPMryy z2&^Q}fYO8q>9^Pjz=hRCRgZU}yxo1-f_0w=Da*2n(Zy5pE85lftDCP&`F#%$Sq1nMd!5M;fwl z0DDN3ad>W{5E!&gwh)$(HWN2W2MMbum{$YOMxBirosBpfuoy zY(3aC+-r^O-O!sUWkd{-lGF^D`T%t1-`ODQu^;AP*2CPwy~_(#YN#wdhh_lK0WZLE z5RSLN^S6Pwza{XAPZB@#SB3xP{|xxO|G-C$$G`6N=qZN*^c=&M4?#F0O>sQy#WbK- z^;lv>)k=$ILbFi!o_sk2;X#<2v74b3L-8V&5sHl9U`(6YFn-@7wQ(dL(~sQ%cg~4C ziF@%w-A20`p-tct)MmuN62Plr2lHyLot-!rVy(ow7|vZ-yI~Wsf@%~u2U^Lha_`12 zQ!nzfYP~EymZ`qr>3H5Rt`bRhD#Y>E5jQW0 z=)xafM^WfQ-nrlLkqHF+qSm86%Uhgr&jp3M`_s_cBBxnqs>_JS*mTs2B~IpjGeq-H z_a>$50_kovH>0~Tdbaq0QD-)1ccl(BhMIG3lsI_|^XA?HhiIT(aXSGqf+}OPchp~&w zYKf)PZzoza_HO3gtataemC{d;0XW`*&)))`zXN^q zcYVk}{?+;;g8=;7pEj@`_1T@UfXRuT%1LwHf8uK}dc_z0r04w(OFx^n)ey~lgbON0 zdJx{t+|8_(LKN*gJ#$BofW@$mcrbuBRgZQx(W!xu=pGr-sO3?FC^(5eI+6~cS<04G zV-DduusE?6V(G>;gc_EEFUYdr%GAAH-LRIxS`EvZT)5VO)`=db)@{sK8k(psV%UwV zH)`vq)=hmgwC3EJn|Ud=mD09lAzDx!2smgPPs1#NLXCtbU=OWZ%ST}J!2Ud;rt{MEpM_{MVl5MERov`p^FD-wFWu?tkm2zhd$8yS6XszxcVo5I=qRM1L2> zPQ!Tc)2VoRiNG1Ehc40% z>bz(hvealp{?`lOL6)Ej43&ZEj@4rTU96j-EW)yh>o&mLz^(0oM(Z=Rm>?!vK)nO4 zORZB|V{99>t;D(-S2uIIo7~w;RydH{|$#PM0j@{A~l!3wu4 zd6NeRF84o8AkX!YMCc#=ZJ+vz-~XHbogct|`49e&^vD0Me>{Hp_E+>3r9rj@=%N|S zjApj8A<1y_-g|DGy3|96F7_@oYJeDMNSp4Xr%mty*&-ix=h+z)La1YVWP@Kn`aGIC zdB!w}Hz&Lpnm{+H8Q~sqCrc5^B9tc74z5jD28g$o{FN70%pE+K$%f-JvT7NRc1;TTwMhLpFks+ zR=;WYyGl7oAYfJCC}IhshO`8<47nv3WPxFOH7wc&$3#=2an!BNQ&Zh&upTTvD!^T% zRiEwhwI}zZHE`<*=9Zwvh{EU%>VxOfo0Q*|T7$NYS~qH4sk2jOGZwg6xN-BsQUI%z z!a^!}L9wZKZ8>n}m8b_pT{_CaV70@1XjYFMk?AjiQVCxIUTnxBOzn?{ z;;`7;>bN>TSztd|Km)+-7k?D~O}}0&J>b17EXj1_l#kO$m79R6tkgQ#2+K4@wsqN7 z#H|ZwkE{)Q;9RJi4&4-J>p(9|(F`BVhxAh1$DGDk*JZ?un9WE`DKf_J$I6W)ZH_2j z)Ss{@0li1%!J+F-iZ;(kSK9{kP1+i@7G-oc>K;3oiRPx&sahB{EL=s7P#AKiCQTAj zOWup2lt3wtQaWt7I$vD7u7Q2MzAnVnpERK3@FL^n@PsGP=WHCa#MA*ckS)j-wARfw z&^M(B($-;{i|Zz?9y~j+I&?1NT8L~z6Rixru9ChK^bw&ghi!r6cntmMAx1r9sXd#? zQy3$1#%XWl^c;6((M6xHMXGTOf+wR(efTM+C9|bna_eY?+E!^bXeD$a;iFT^AkoZp zF494aCA=S`Sb%5-C`g30thRfHo54!JJz(ZA_F;6?v$nAhAMR2rxa7^m2RDjOYCUN{ z|J1ks8f=GKMO~D7GoIb+>?a0|oyJCbqm?c%ty^hf-a5UJzL{(_*=oVfh_!&L3u~da zLbM9CG>=dB_D<2qpvkD(a!#R+Qk~&ypyiesgjSQnAaD4zU`~$ec_)8-RWw z;f@Pv2V-HMs0ZF`3V&(qFMjfG#QXJQ=sILDg29;fD&`*MrMo+=ctI&$rMBivlPygw z4e*Wdjk0FJX5dzYtq@x!T4m;`6^c%&=9H8b$Q&@ItRtrYrb+vP zvK<&S4|k^*r`4rJJ+xMjt(QaVzVyze2TDVDC#|{IOlURG3el=54p3jH=**2^9ngWbuf zVlPx*h<=DUv^34aQaQ4 zoPzbfV><`h7TDHM--Nz~S_|}+_4#Yx4_$%zQpQu#Ag7YY8$kaO*6;cU{vQ0^Kk#qm z7t`z=m(yK0+%Bdsz4Iyj)W_e_IUKP9y{AmT7!*viaD^5M$Bcec3XVDPBqQY)?KyDB zy{K@spp(yB$Go8_lru9!^>ki1G#mtsBlQM`T0f`Wp3VO8;D`X1OlA5wfnX6_Ikr>Rb`G?2M>}=26SSR$jX4<1o=<2D zFQSj4f#V%e zHn0j@hQ`K$rkfN95XPS0A^HW-M&@YhK#U3yk)u-UVAIt?xopT71X6|xqcEOyHD_wt zj>(s_l4CX?H9$Q}e9!>YAViJnbiy*-2`6L9mnErtc)y9^LU%EWfC_Sv*(#KqK)nep z=fLScu-KpUk3!UNjc5Y`@Wo`CKnv#@ckq3lAu#hWU}SAYGFf9KzG z`9i|`&(k_$+0dUg@D|`rq_AusiEg&GvnO41&|r*%r$SgjN-!%r(OTB34~1BgO-Jv_ zJUa|5WTqyh1!X>LolPvH3WZ9dLabw$wP4B?rRB5Y3e4lfF)XChGkT(*LNy{x?2e&~ zDxw1DGH!xxV%ZG!D4for<=C+viSt6O_rzMD)r3{1H9~9@x4cv+_r~f-c@W>D^mO6U zWrzDz*Vi?mKd=b(19V>z>j`}uyCz{I$RL)~rbc5bqI%YycSr|9olqlsfo60*6rvWg z7Rn1@-C#vzrK}rR21&`uVnnfY5Lieq6e^&F#DWj0i;YotO?{AA(jJOsK#G^S<1nd+EXI#DonojL+#OsfxC z%c#BQeitP0v48WY@ZR6|?H~0!{(<$41L#>cIHVX@2Xq2@=Fhk&zktf#uCOWKOdsSd z+XWgFCC9vDNv7=9M3# z6-wnK&8RMzF(bOP+uBVVF-GbE)}a-0-iT!-&V@P`;AB#zR6{y#k)5UkQ@_}UnvZ2~ zsSQfYtmceOA+vIAe9{t+-#CDt>(aWLu9L5|a+8UX)&atrS6X(6+jw(x-cj8$Iv;1c z;Y6thFB~fVc6BDaQ0~F%L^b1L&~bpdkwb%n7r&}e(VLaOky~^B_VBBnJI+}dain_F z-ho$=MC)Ml9h$H-;!vrR6DNbJq}oHJnS7<}O!34(rIZ{Nb%QnoO2-30k1~8lXU~$* zlkKd0;{o~%@SLTu8$bsj76KJenQ~#u3Py`;%ryzFz%)KFs2k7*pw|iLLV2-t&Z-8h z1}=nElU35Hq2$I9iw6$Ilrk_f`yGQOG|-vAss0#d1;k;N*isF7NCrYC&7m9vky4}PeA*K!d8v85L{fg zkX#J57`)n^mMl&j3lq#ng)uvVhS8nayNfC7pAu%nae#ErsTuD5nb~5Wl|7%SHirF1 zrXuQ{*gQ}TD7pWYcN13w&lC=X4pb~uU#M28R-mmwwJ^;KI^^I!y+dbesue!aQh9Rg z8w$|h_gTO)S>DG=ssRgx1?tBPR}nqbdZbuq1R_$8d3O{a%1y=uwI?&L6oX|%9w6@I z!NkRA2a_+xvY3`iF2&Re*_{ZVU>oSl7TP#rW0#m4oM zwIGo-cTyY*{iZEB8W)Z(Tg}ZSrRS8Y_NGz*2F$m-jzmkGtZY(Yp5WH^L?@_#$DZAK|xZm4loUTuSAwoQZ}I*Xw{#Yr{|?hQnLtp zl3S3>ktU}Tm~uTM#5F|VMd_4le%8)vgiK45OgdbPv0C{Js}`{)r7wqChISyV81pcM z+EM-r$|D={;z+K|;}S=fioXupdwC}sSR-F@dTk$|TT$=kCd!34_`_a3ymeXb>}*Fe z0o-)1LULYtUym#{V{cTbE%kzBS`}sKrWo~_1>o_A8NP@&BjXWLW73lR5Xh)PutU{y zNh*eOartvt$k-Yz))Q^TEizK-n1{IBJC~$)TA`F!?S&%g_E{AR0Ge?H){mR=aju1N z2dabxOB#8^Yf9-rp86z)g!inc<%pcN{ zrwMe?1hk$6z2=xLdacZ@wQR2bM zQMSpr>Fxi9ivf{jIyfJd)c8R*uL&+O-zc{>q0xBm*2}UEdhp)_oxK_rt7box6IcJVx|@58JYPWGvU0;a5yoet1cT$ zbnzwmi9eO&dtuLMcXtqa;2B+u-*+G};Ib0Z4tW3A<^KBCRr%mxMb9jaGr*-+wvFbP(tQE4Hz9(61kY5a=o=L)fh_T zVwRK){c|*KM9!%wXzXg}ep7$_&=&I=>mA`tfiNyFR%5emEs+ThOZgF*)0m-OFF60wA3{zQ^n2wJAoF8(eF>}=ZVNsXl z9WoCedf?B?pGevj|BknkWUXU`X;AOgMhmm%QL{Sh%Zt#l911j>EE!z_!VQ58oeX&h ziwUws3nF^t`Da{Md4Kl~ml1zgXdrrvlj7wYCBBU#F?JK9H;}j}m@K5s(L-x?cNALZ zqV#KqdA@kJ>#BS;FX{Iz7K!o|HKR{{KUqO z)+l#>y(Ved8@$)%du5Q;wc-8K>UIUzdVmGp4Htksot(I)LqWiHf?>%?w_;4#eiU?E z^&uwGLKx4s5=JZ5MS_`05SB7HL&5c+7BySUii0l!uoe3os1^Quc;l1?5nem5!TL91uNw=A zMz5Qr?O@jeS~Uuv`I!6sZk;I|m5o7H*@2QxH0Z zL2>%S>RRh)N_;_^{r^^3CwloWZdLJ#aYslB_CEr=_t&DhSyD@K&!4 zDeFvdFq2{)e_JPEn(pK?&}{d&}%`xOhtwRmaFkB2BaLh@cVvTjPPu%tOPlMelSR;ZIGF^eyh z#Hvq8rU-u~Vz_KJC62oURs(HYoO8Z+%Lza4=WAgS39t8zYK=ioz&oMeXYZ;*z{xv` zfmt&q$I2rM^8|+p&i)+n27Y8iDQgJo{@n96If=Az&K=7R^rq$kGL9#znqF2m5* zfO@%=a3`htFPBsM?{9RR+XCp3;wv=7MMy*GKe3SzdT{!D1D|1T`=?TrRuzJS8G{vO z5UTc@c8OSX3~3S6J>N;wCp`(~7*)wUC}(fSkJk5ad@nU*U?y(ZmkZr`fq+gO zdN!R7yHMgfct~lM5D}R|)|G}OReU*_ilr`S4l*^;)OYysCT2-)nXt5zF0n0yuIOAwjwIrw z$z9o2cfRt%EI}ih3>i=&KhMpYutw(h?~pa$Cw*4mQ%upD|y0FNyC1}qKK2I%yBrB zR=;W`e{Q62Ap|%nAWxv*(VR8NfAxzdm_RD7(i4!r)RbGFt3@{cqcf*Mqr}j30 z-4g~(&=gvSZJY4y^Ikg3{|-1?L?*`R!(G!f^vkUdTP)x(fZPhV-`xR@eBRDqk{h9! z&6k`3?Z4c*fWMR-Dm1&YpSJHh<9wom^*1a35>lp~TJ!;(^?k<$BNvhas6*+_#_k5$ zl=3JOlN#`%tL?(wa)2^y*?AxVke^2t=r zz`9QGg*VqNp&-|;B?e5rGGd(1jOCnlGs+i6A$J96OJ#E1w({R<%H6&o%-hrJO#L+e z`{@{}BvKGx)}`K)e%^8dx3c9sCZL}p;O>w-`4>oWEPZ8|;s2~IE?fEL>+^V*sAqr~ z(9zbA5x{KUNB66Zm~hsSw0R}{EIBqW!VmtRT&p)mzyX!9Y1&QO=(Rz1@5Jt7)$_yM zV$V`=bZG!4Nm^c^AVJcf$TzgRlyHRpdz>p)kx7(P#H%be%qsY1H^<$$Q}%sB2cey! zyadIglVg4AgvFe$t8ql{V8qn<-V8;434cMrbB*5(e;4GgwkPL>cWdw>pmSFfki&=M zfWJL3Gq#lWVLK`UQ)dhLTBbeID#Wd4pA&ZvX48g9SlaX675yNs`y9Si06bijY^*R# z4_?iEVZVL>JT# z^F3T8 z?T)uqZVT|(5QgiQECT~_j4@yl*>6%ues_oYZQgKtl>fVd((4g#@1EcMPn)hPf!r9c zmxlov{_2mfn`DoZZ<0Hj8(^O{z8Dld)Ffb0X!r~}wzX2KVQp^tC zUxmH;3bPs6H7L84TL>vkU4wIL5gx113#|g4E5|o+DBQBlMf*D_3WG^+n8^vPFlIm$ zu}<0wW#p85uw2Btm|@DF(Sny*q-TCNSKAp0yC?Yip?hmsv1q4g*#&sHT}y)u4Z7qD zl}I_7=i&HOv)K?GerBsI9<>E{!g&AiB2)D8&4PLMdV|mHM1M`r!M8Vn6Vg}l7c$Wl zGcP8q9voBlToM)d`@4ebZcSt2jwQAOq)gs1o|4Hci9N+cYt=&Zs^?E+{`Dx-g*>iV zk1U`xDu%k_@;ek+V8FfoJ6OtmvhwZSWpkN zCfKY%@u_8Ky+Grox>FZpFBPrAHmWb7c)GDlmNY{UR5vETX%r`$8APlQYht|#VamGHZg>(as+3omUp|}&fDi?(^XEJzrf()+YTm*Jm1e_2pQVTvkA}7c**<=w~ zze9&Ps;<+EnlYbeKwz~DCCtbW&{K(ceVTU47HL1BAA66!50@3V?QdA*3Qn2Z-KKS( zNGf5h9z_^JtNTSWVEp-r1sT5T<8EX@vaxQu(j@6CJ@^t{4fi|RNbKJ#ZteF7$@O|?c)gcZHcpqs zubgJQM6QW0)K~hyM_{sv-wox|>ZDGC z0>p!UscXsRCj6z6C6on@xsZg#n0{y$HG?j-_J0mJ7rXg;;sCP>0Lv+1iWr=%zKo$W ztMVzj34Y04Y=yfxEib`j*uTBi!#z*0s+ZPLN3NVeJ}}>!%!aa=zFgwElWyJ%KcT;$ zm!`OJV3tHW(qta;ybJkpPPD=d#?5t(lsnD;`f#^YXeF>0rHglK;7}FS2?INmDgK?X zK`-J@WK|b9H^CKW9lf3B_AibD;~u}%SMCrw)(vR^43pemT1F%d;J4rh>>}#0kNDlC zmvfY0+;pIhN_!K0(@(8$eodtQ`{_E8{oWg?YH`3aDPWVMf{c`Dw zT;k{vJOAbW5jkTXEt zly3%Lfn$O7H85F(y~c<*?2KSfk(cWbD$0S{n)l)=`j73iZyrzahvJH(2vz?t%zG@w zps{MC&C#BI!U>g#CNli-<8bbDmMXys(qHWB=Ayj>ys^;AdXNqB)OcZi3^5MlEE z_kCwaeuCZTcy7aDig*os_+x$kb=yGGYv{_G2k<6US@&k@d#^eDBoD0C&!`2GfEdyF zjY<|pqNP}rBP*|7PgZ|B4(pg#%QbVh5T1#qPj$$Qjkio4j6K|&sjhiy;+`5>!frd) z=Og=X3SpY)cO5q0#a&U8Xgvn&KGD{sG%lK1fX~zH9cx%vyVyGNqgRm+zV}NDHa*$W zjh}5J@wtmex1+GqD(4d$JKYz+a)&h0*R2}+>1a8S4E8^@#Z8hl(Rc(q0tOlKl&D0} z&38zEP;Ev~9h1EtPnaXdFLs}rkwMo?}v)oPtM5}J!waYA>knD>j}Mva$FS>6WT!m9e{Xz}x(((INI z;x9T~8C|BmE+?4qHC*06*Ms?+7RPnigY1+G`a!dTCig7Yc(yE##`degxn?5V&tDMK zO$^ZZcwE6JTgXQRv#}F3JTZ}14Mf@eS7YHi)G+}VyhfO`;OfVJo$CY03O`aSMYp*wMUKpveiPyRLlCLLJr`84#`()-XfZ%xb&u$7oW2%Lo!3P$U7V20(^szOd!uYMsY`3*y5tG+MD{=fE(MWcJ0t^u8T2jPQRl#go zHB)F2k$o0ak`R?T8@q+Z@lzd|!Id)T6I=+4;0(7V`pz152`Jm^vLn$ws|od5UBq2< z0}<>nfNN+G_cZ`rMf3Bgej$t-2^|I~Sv^btAbKq4@OJ3O?XOOfKH!R|zNgH$3J&kj z`l@J1yjJu51-%ZaqXY+mpL6jGA~M$W%#N$-gUY&o1;k{_HplBCy8W9b?$spIY8iCYp; zY=Ra}P=JqX{R?4!c9Gc_;h#KzOdcHG9If*+ZK=eIYKeV(28&OViS|@xGurBr?@6d*`p<0{*UqMNAaHZdc z@cbkABHA4t`GmHEjV3p`sl?G?54lRcivYV_DwYh}u8{N~rlg6iwVJJrI7Y6;DG2Tw z^;1<&Y-Q~33%)qd<(Jh|&$Eqmn)_0fGWri06KX%A(Q^ZH?_Qgy)s+aTf{%E!SELH< zyM7aa_$QQiQmGYQ%vreoZtgp#6#y=Tp{5ANiXyY)EZ_q}aZ>U~Ocn!?aT=f1L&o_X`+o=t`4( zxtOGTcn=`v?q9pFCfD@1&WhqToMzwu*uW6`?#-~;Phw6gz4fV8lGh)$W7wr2F_L$6 zc-X^)SS6p)(}=hS;TII?!Fj-&W3Uuph%8=tbHN6Jhi;<~Wl#hD>``F{>GqMN+QltU zEKq%XiR689WO723*tuL>4)iXI`zk z6@#OB%!0JkoFOUz;p%sNPp|Y7aMzw6}P{tQ`zX`SoT`E(RKH6~Q>#_7dIi)^u_=S{qm<#T!V7HzR4kAlfLVO5iaYkG?J##J z8T#F~vU7S;Ywms8DZOc3zYtd&%HP2Ln~Mu|GvK^Zfp#dR@7y!}U%01L1sq08#7s-T zb92Bd7DmCqi7Zf5H;|!11rtqaRvKT9_b4B{d>p_REd9q)8wYhdSjgolX;1{#S)7MV z7|<6-K}sb-T*ObS{!TT`|8z?@Uz~LMMOtYxsd?H8-G|&5Tke#C~YggUi}hvB>vdDJhm1F zC6Fb_rshuY@hg){T6s~n#WAGO9WJLb0TASoS9@ecrZ-ZQX_bl#brjz<602~uDYGcE z0PAusVLMEP{H2>xeZH!lHy!IaChg32?GJ8zDQ9iJdKFFuwf(QC0DayU?H>)EmvdA# zHOr*>6U&{TG7_uddET?z`DiVR1@H`5F)RD!j$e<7p4zFpX;%gA(=Zf7CPA4DMO@p* z@5ISUjU0V=c!1s_%fJn`=X=&#K9Oi4wK~3g-7Nn6n>LpM#!|Vpf?B4mNt^f#Wdn=t zxgrziv`8y^tnW3M+t9`Db;8pYoaC*@%os9tU&1B(EFTEJDu#?FqLi*zPktUY(k^-t~Sbr(WlW zFRtEq&VrpUPiMEa!tL#^SLF6N{`L3nLU*KB!-~FNqWWSXOR?LpPdUAfK7%EWuf-0k z{w=`gD}Zl{hSvKQ(g|l39fhQsID8t)qLY6NSW#!E%(D?#dHj`%+)&^4H}<$1H4*3= zt{0T$S4JY999eyMl%n>H-`!tc#llDa;qUZMMW%>77&)@xYgls|;VbLf8POW&&DSE6 z`7O_+e?N@lQk_kKXrjlOmM3`HaUWBkoB?!5?pXR_UItSyar$3wW%F8(oHlj%>+Se+ zE+$Xcy)PUt{O(;=Ctvr;ZG~?wAZiesoG0DGtM3B-rzULdZIB{nR{f5?%|~BtM+3vw-H#~i$b$zr*$huML~RLgJ86a( zeOs;2j@2tCfDD^gnC{rxwVr-X9YJswT{oMKcGT|VFnjao=$E-%$ldCLa$%TwP z%q)daqHWYUrF!(2UwuU~Q;75UwxV|cF6u^5xjgX^a*xcE9)&)Pm%)s8oW9tV3by<7 zOX-8(MuVMT7HIY5qH|5?Mm5LE|9uiNc$ET4BtI^H0Bp=VyifWtTZWQ9ca!4*PQu<% z^q+v8`xnox7r@j()x@&m_+(_rv7n%&UqQ31 zwrfg6k(iHm_$LN@?MUd?8_@pTkM%P{g?fp>HNR=y+TjgIbNWy2S~N>{Z_26zs{9Q&I`%=)8>t^ z&wmMg6ab&iUH~{1t-d#@Cc-9l@6KFRnA~*4biMC8G(25NRO7X1hG-!^Sf{=8o{|Sg z%^9~w66DlkQkKk!=Z4v~tyx)h%pF|7io6Y(j0TK&Jy}e8bs^rrWRF#-s&sLPse~pB z1Ny3Bjl6?^uhrJSU);BC_lWySap`a#03g6QaNYF?KQ9HLog~2T=TsIR-8W&W3!PQ3 z)=uHONx%ErtCRiFvZc#zvrn>~Eg!|UsA1|Vx&#nj`G1CzyvU3=z0$ zte#ah6I8|eSgdse3?_N}^-(?1iEtE-eVWjuY(N9OJT8M(XBtP79z-hOelpkXjSIp% z$8LgkQatjrM-%t@)+hHxAKOW)U$8Ja0)5(h6RL)H-a6fIqq#@g4talh3?zS*i-k`! zn1QmjJ2&q?-PS)>^K}WCFEy|(HfaA@U=7vTMFg1O~Pz4LmHI^9l|Asgf5Pb;NK+&bHVUu)S@NnKZfYE|~9(jzS6 zj#w5r>9$%SC1N7E(_9wSjhrev(UyaU+IQbhjF%tCW!j?N;3 zALK6>?@}*gre^L{P2|Pd(BDKFrNe1IU!`%KS*ZX@g>xeOPg^;+CqnqS*H|4Dce2C1 z#pp~qghZW2YA3`pXI(PSlo+ztNp=pF*{4wO&ZtB83^u*ykQBxQU{S0NN_`7Id@QXE zw4esb2owm#=~k9ljUo#Dh-d5`I{5kG{i5#%%OY0Pf<=|$O4 zPG);v%k;E|4_j@}=Vn|@pgowkaGz{oS%_zTeCCaA7zi91wr?Z|TiNuwl7|Y=v5!_E5dIVz9XsAtrzYT zBp4EEtoD~>y!<_ZI{;WMbQOLbFFU;+2;cKw-mf3unq#CP%dY&$!YX1*gb>)9J>t0> zV4jFL{!{3BPXn!-xWRgfptmLN)L1}s=ifkL(VtB{OZjxPd_PzNyBUps^%WT8*kR_CAb?36Z zhBzC}Oem3RK$Q|Cxdz*Ydnvo87snjrGoMyENZe8;2r9d~iD3V6`|>B3nt??`MlNE*lw zbf+-*>4RUVsj_yrwXWgO>6WD(c@x@D&evF;rL#KGZl`n6E+x(OAW~}V+FtcBYeV=% z^F7_5jQn*L(k%tkSGfS4QYu+hVpy-|#94<#(u5BsFHH>@Lviq=*bDjV@ty4?&O(W2 zsH%gvW)Q~?T_A&H1pMy5$ggG4ki82-eJ@+?Qa+BPMnwb7^*V$nTP?><2ghtf(U!9R zOoDw=4rHhM4h*@S*<-xen?0X#va@t?x1i%^Z{X#x?j?R7f1Eqa`B9tdWk=X~#$dCK zPS9cbL+e6AO8aJKlpo|vzFmHrBhSc*&X>sz$=Yw5PdnbXyE#t`?_1>W1+lR`l{;P% z&MMjPzh$OFxISlm4PXyESw3_9_J=TSPFE|#eu=zMf%^{zeO?>L>_dC` zl!M*zSfPa3WSIM*`WK}qzF4$eIx8|n^QrcrF#IY%h?TCkqJ@%B-O`AMCu&cW1SG~= zlsscr8FKI;`RTHOwgk5p*ej>p&!lS>*c(SRn^-!yhO=ZT$#LMB0cc!f$QhKL`>-VH zi@8HKfZK%|%#NagXNP>0LVBv`{`xNm^|chDxK;U1aY+dDA?tx0=PbLo9rd_F20G6Q zM7K0Oq4Q1UNlP<5+Fcpa*)DMwuD_VOv4R;nL(rB1;&h26mhY{S=drahoTex^r?P2; zfTceqpwzmLJ`$|Vi-UA+G=0wJ-Z4?+G(T~Oh!K&Pl5hG7^bX_jz$SKBK9HhbwuRxJ zjYsc8aSY%~jsawgWEu(dHg#8Z7j!pbw5>WpauD9vI!PZl{Ujf~<8MS@9x>l$W07hH zbz)aiH~F1R#Ft#enP_<9 zF_18}&RqW;)7%E04D5?qm?F^TsbPu=)=3nz7Mmx-2F;Af)q$8IX}fsq(?6D8L(oh@b->=ka8|D{gg=Hms7 z|8w=mS**Qai`K3sHDW2knP-KhLPMe!t7Z4@)0x1LQ}(V7ximA&S&TvLaqG&Q9?v&T zMVn3;t3yxeSVG60E3^d1=gL}sRELtLcbVQ zE8zL8%l}d65)*>3r3hIb^l24NxNCZzTBBA&bC$?(`23)Nt*R6P{wOOBH&#>O!&rM~ zl*qgo?@^LG;dOnNZg=+7FK~8d?}L?BDU9KYKRKwVFHM>v1~zT<{j(cozQYh3`*pUr zG&PmL7C0^`k5;mT{4Y%EGu9DOF%`HBW&>yssqM;v`0Xr0KKKq<+T|{2ul`j&}*!HR16F$>3!|T#?ZO%>z3C z9*9j(LR%TgulxQ{1_zUmq1v(KTg=4WSfO<{nFz?|5t-stHc{t?5>`LF8X!@#kryh- zM3IY&E&$B@)5mM)sG0S)4g>x@T?7$nU6QzF6r=D(fLw1Aj#m zF->1OZW>6x%Crx{171?vm0&l6tMoWtwTMTtme9|~N1%4cW2(cQR0CP#2rw6BhDPN= z*<=w&G?M8JA%+Gm`eCsQ?g}d}JnY(k>9zebKT046VD|kBt|VD_Truf<4@?92U9v1f z8d$(&2B*m;=iE#pvGG#Mnv-t&l5BlnVXQ^LAH?9-F{++*`FwUYc><&mz%-8FE%g_Q z4!6IcO#gjwtndYCXVP6{+vm;=4F5;MH!(6<^4Bwip^~F*gYq!Ut}t>GoJqf(u*;Jy zhbQYcF-1RUhd~x0Pl`L_Z>qvK`yFqQ!xtS~&0CsJ%KqErY`&Kz{y%f3Fkk8)IvyOl z`8&58eOw_;bS-4QJJ1YULZPR;2MD$QH9Ps8&6R7j76$p9sz>d{U+&X!um8`>^MC=w zUr#5nbuR120CcxA8t^wQu&EK)jL*c`40-`TbJtlIS$G&(+0|IN`B>QaIJmyDu<)_4 z{1!pN|Gy0E989guJ^$YZ%cNDMPy@;T)ZpS^4t6(kHUr4m8CjSq7+F}E*idjWaWnBS z@=~y|uyQc6a5A#8Q7E%=QCNb(j(p6_?(XhPR{udm4=9?+!P#Oh^bG0{K=dDvYL>2c z#(aDd4koU4X7*q{J|!sB1;APYX=VN&nE$GikI&M~%EA&1VC7}Q1UQF4F@*ok&;Q0~ zTA6|^{{xx*ONj)9eE4q=1uHu}YQxT%!T{AAS_npeO(?}Oy+~!8CTxOg`+?>Yj#ys4-EN13LCOjRZ literal 0 HcmV?d00001 diff --git a/img/apple-icon-57x57.png b/img/apple-icon-57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..a8a06a8ae6d67fe68cb66d0820fca9b341eb4bf8 GIT binary patch literal 5625 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-72x72.png b/img/apple-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..e41c7e79b6035095246e3ca71faa91add87ae626 GIT binary patch literal 7676 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-76x76.png b/img/apple-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..ecc6981808e90956f78c865333ffb954adee3597 GIT binary patch literal 8380 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 literal 0 HcmV?d00001 diff --git a/img/apple-icon-precomposed.png b/img/apple-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..2699dd3eee4977891bb4aa84fa219e9bc3c59aee GIT binary patch literal 30726 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 Py(s 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 z zo28CVpjY2SQR`n&AkCrPHj#aWd`uXHwQjrF0_7fldjqVpG-?rg`+jGjQCb0+0==<2 z*qsTAnTTwJ7o6eroL#`EBcJu|_dXDBy><>So7XXq{$>U6#t0K)q};Sm*@H)CjUIYv ze0T-!#m`aAiJNN;NFsdvnVkYHVF>|zSI`BfzXFTR2rbEVRqJWNO5$-<_A`&-@R2I` z!k`_2nA}*wzvA1H+n)V;a=W1frO&p`0yp=hAgvFwM^8q#WO7;j9(JF?_+WhTd|)#Q zTf1Yh{INw;&rTe(A9Aob06EgjgA|T#1R#EqL{1QcP#sYO!DqdoY{c1PPZSyA$e`CF z>z2c&v5uWT4svE}0kFgJA*8l`=eti~$vVIJd2qMCNa^dM+*jY0$EWfS%;&g_0?G}n zoAh1Awo*Nmh0ld?ned*VeN$Gd=|x$DzFZ7p@{`3YK6gRcZdm;s zUs)P#fK_DNhxoK(kZzUk{`N9g_4CB9ftv$wjt!(A@0bITLXo=dEAI=LBV>zl9)F`q ze_vc`q$}P9&etB`F-_v!9`vU7{nnAp%uqhmZ{jjJm%viI2Z_TkhXreKA{Ckb;Se7E zDrfVcP9F#-DJG85wC8E*&Gh~F`P=UtYFtI)j8_-A-%9d`x8tIn9G;X01Aw9~KIbw{ z&)omD;HDw)78eWiq^|;gK!POeI_Ohy7-qbOj^?HG^gQJ80_ ze|#zD^&sT1jV$`15l2h7V$NVb0n{g3VCsQwqlTxBVHX+HUfZQ)035!i5BGGj4{Wtc z3ed||${8lrH7T!4QX7vL;h=8UyE|fvnAgLiRLuR%DNTHX`9oiMK!K5ui7el&9K`aO z0xL&=)CVGwT11ks6{r**?Y1Vm0ozS%44)060Lafl=a07--H)4lXW`#@yN|HLhF$^{ z*xo;7wu)9g`&;fz^Y@d&IkE<&vNfEF`S9bWcW$C*ZsV%#e)xE2W#`es{d@=47@dM< zD|GdwX+d)#5tGiIz%2o@z87XIiiGuk5xNVo6^c@T3GVgj83efL=z#}z$&c4D-@+z7 zsN3(}4A<=sgQ8Z0!zm@1A1&}<<@-c_5~3QzKjY9gOw|!cP#c-%$8kpar%YkE^+ak9 zahE)SzaQ8wcb-jTYnQ&Ed6?U|9$H~GFCCcLx`g~|1Qmk}P$n?qhvSJTBfnGcZhYjf zCSs_I4{6e<*n^U@5qc2f<EP-{DbiE@fE>7;si7Uqobi`t9) zh0>wtd#TZ%_&e4sCsd}?fT#vUV&OvZyIMcDGVX*3k)@a#g{GXE_Z+(1QUapTXBeJM zgU1?gTb7sSp>syRQth=jSAMp4+w{VxqmX$B$40cM%ZA7Ihwb%-ysrw$t?B4=o_F6C ztgwQ+dTRfF7V8cF@kEq!RL^`7tjVU@yD~G?jg}%hS%qNzcy3&EXY`q@a|bw15nYsIZ8*fUtysh$xGZh$M@vzduw~NGK>MNYL#+ zH2Q}|3wryytR|kI8wAk&*P^LwfTz8zteUq&fTxp}zpShw8tMlS`Go2cLSv}^7v_KZ zl$CXLa&vL@2Z%@(zg!(hL#Y105OX(2e^)f(58&fA8bSNN5PEK&PW~ZKC&2&QlMvL) zMe(bd{{O2dJySFaAR-|nB_<{_ W;!^FpW|8Q&09xw$Y7Huo*#84IY+W<} literal 0 HcmV?d00001 diff --git a/img/apple-icon.png b/img/apple-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2699dd3eee4977891bb4aa84fa219e9bc3c59aee GIT binary patch literal 30726 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 Py(s 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 z zo28CVpjY2SQR`n&AkCrPHj#aWd`uXHwQjrF0_7fldjqVpG-?rg`+jGjQCb0+0==<2 z*qsTAnTTwJ7o6eroL#`EBcJu|_dXDBy><>So7XXq{$>U6#t0K)q};Sm*@H)CjUIYv ze0T-!#m`aAiJNN;NFsdvnVkYHVF>|zSI`BfzXFTR2rbEVRqJWNO5$-<_A`&-@R2I` z!k`_2nA}*wzvA1H+n)V;a=W1frO&p`0yp=hAgvFwM^8q#WO7;j9(JF?_+WhTd|)#Q zTf1Yh{INw;&rTe(A9Aob06EgjgA|T#1R#EqL{1QcP#sYO!DqdoY{c1PPZSyA$e`CF z>z2c&v5uWT4svE}0kFgJA*8l`=eti~$vVIJd2qMCNa^dM+*jY0$EWfS%;&g_0?G}n zoAh1Awo*Nmh0ld?ned*VeN$Gd=|x$DzFZ7p@{`3YK6gRcZdm;s zUs)P#fK_DNhxoK(kZzUk{`N9g_4CB9ftv$wjt!(A@0bITLXo=dEAI=LBV>zl9)F`q ze_vc`q$}P9&etB`F-_v!9`vU7{nnAp%uqhmZ{jjJm%viI2Z_TkhXreKA{Ckb;Se7E zDrfVcP9F#-DJG85wC8E*&Gh~F`P=UtYFtI)j8_-A-%9d`x8tIn9G;X01Aw9~KIbw{ z&)omD;HDw)78eWiq^|;gK!POeI_Ohy7-qbOj^?HG^gQJ80_ ze|#zD^&sT1jV$`15l2h7V$NVb0n{g3VCsQwqlTxBVHX+HUfZQ)035!i5BGGj4{Wtc z3ed||${8lrH7T!4QX7vL;h=8UyE|fvnAgLiRLuR%DNTHX`9oiMK!K5ui7el&9K`aO z0xL&=)CVGwT11ks6{r**?Y1Vm0ozS%44)060Lafl=a07--H)4lXW`#@yN|HLhF$^{ z*xo;7wu)9g`&;fz^Y@d&IkE<&vNfEF`S9bWcW$C*ZsV%#e)xE2W#`es{d@=47@dM< zD|GdwX+d)#5tGiIz%2o@z87XIiiGuk5xNVo6^c@T3GVgj83efL=z#}z$&c4D-@+z7 zsN3(}4A<=sgQ8Z0!zm@1A1&}<<@-c_5~3QzKjY9gOw|!cP#c-%$8kpar%YkE^+ak9 zahE)SzaQ8wcb-jTYnQ&Ed6?U|9$H~GFCCcLx`g~|1Qmk}P$n?qhvSJTBfnGcZhYjf zCSs_I4{6e<*n^U@5qc2f<EP-{DbiE@fE>7;si7Uqobi`t9) zh0>wtd#TZ%_&e4sCsd}?fT#vUV&OvZyIMcDGVX*3k)@a#g{GXE_Z+(1QUapTXBeJM zgU1?gTb7sSp>syRQth=jSAMp4+w{VxqmX$B$40cM%ZA7Ihwb%-ysrw$t?B4=o_F6C ztgwQ+dTRfF7V8cF@kEq!RL^`7tjVU@yD~G?jg}%hS%qNzcy3&EXY`q@a|bw15nYsIZ8*fUtysh$xGZh$M@vzduw~NGK>MNYL#+ zH2Q}|3wryytR|kI8wAk&*P^LwfTz8zteUq&fTxp}zpShw8tMlS`Go2cLSv}^7v_KZ zl$CXLa&vL@2Z%@(zg!(hL#Y105OX(2e^)f(58&fA8bSNN5PEK&PW~ZKC&2&QlMvL) zMe(bd{{O2dJySFaAR-|nB_<{_ W;!^FpW|8Q&09xw$Y7Huo*#84IY+W<} literal 0 HcmV?d00001 diff --git a/img/configuracao-dotnet/azure-identity.webp b/img/configuracao-dotnet/azure-identity.webp new file mode 100644 index 0000000000000000000000000000000000000000..b3cd4e02801e1cf678624f8e108f991c0e92bc92 GIT binary patch literal 40650 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⪼3Fr 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 literal 0 HcmV?d00001 diff --git a/img/configuracao-dotnet/configuration-overview.webp b/img/configuracao-dotnet/configuration-overview.webp new file mode 100644 index 0000000000000000000000000000000000000000..52c4efeabec4edb3febbebef86c78a8b91805606 GIT binary patch literal 280904 zcmeEP2RN4P+qd`3%HFe#5F&eT$|i)YvPWc(?2wV288R|6N_N>>WMpKkWM%Vw)Z1Hc zkw>ZY{dG8wsN4PA_jR4u?>x`nxh{wb3Gs+RfG7&`$tcLM5ixInALuF;14`pWhlb5% z#1bW%OqN7Klw(6wj_7S*yrt_vd3~UJ7I|bqQ^U)N5pXGk0EC;$G0xQAP0Dy%>Q9rx;OD!{HBizkSCYx_oSBD)FOJJ7(bFo8!{Eb=w{Z^R)e#C_ADBvET zY-@Sz>N4y2yXBVmWg}%B_SlD}_8Q|;E<4T~*}&Fd>I3tR$Q78_w($TP8H+=g4cPGnn7 zTTC0QtH>*a1Duxt6#%rYl*NE&NPU3z^%JX*OMt1^d8b;(iyNBuo^Q+Um(@FEEr9}X zx3ZSF2aq?^VM=S>KyG4f#J5T zprjjLkkmUC$e%isgZCSXOFEQ~PxOzU=oKrLd zu`+*n2|sM0N$u&I$$39zdHf-9wwAio1m#m-n9}*jg>ic&ap&QQ4Kn`FQvB4%;s=LW z@FwJDPQ5<@$GXa6!?jlB>YoC+9|gyq-xJn32FSy(*^UA7XQc3p9XJNa!-0`wfc!$J zenQn81LWb5GsggV43J04@i_*_V}LvyXgi#{90TMrKpq3+o~+2Ri+xDM+c5`uI4tln z2YEPr`Y{K2I3bB+fIJ4s;~>qU*y6_=5Q`=Dt)h^wj)o)V0o6Iu}0_!lN9akZE(__Dg%Q0{zPU&PW5NBQ99FbZbe zx>l#!F};fuPK=11Cu5p^(F1Oag4F6VVbIY7+*cNx9Y`k>ZpF)XpWax;&h9 z;v>}S3rX!KmNsjkAUn_Q_j;cMiIlsg(v)0aJfFii94ph!ISGTm6g*m*2@#0*SPOc4S#eZG0VQLT`1bF6i*Sr6bW=ilni8 z0R^*O;5bwOX5j8O+A!+O!UAo@(#o*HCW7V8oE%S(&~N4g1IkK9QUq1!@&m7BVr z&rIM3-Z;1OR(V?w=3kfH#eig|kQ)p4tyakcRac?)1&?!GQTt3(! zeQ-(YI55RCLKS>-uKsB8NrjA)T=@`YesKg2DmT~RTM%K5JLTE-s_S6wh%b#lm}Kl} z_x(b2{`S@;t%Ndzfy(f^mrf!kt3(?(H7mC<- z3uw=ShN~AQ`^8T~B6mpXb@`TOpQ2e)v>ram4C%pP1q!w$4da#ug1^Cfx`NsFjlgh7 zqLQ8e(0jbG$K1H5a`7utkS9@ngTP1>QPV(IFqLlHrm?(1JZ?gwRd=2qyIY^E$kbd- z4ThG4LN1t(DKD+f;gZ@C1mxI^EvSsi%b>>6itI?xw{8nM5D-uUo6k{3SR`p1ZV4;T zh-WbRID$2#fm|wdvBVz@7d&%*bdC*gh@735zzhi+Rq#X!HDX~Cw(LdClXq}DixXx^ z#s>wTpHt&GjmnD8Gb6(kkCl8=OEPv=Az0F#hA_Ka2tae^Z8j%Qyj1C?a6A(& zFu7=d*JM++E0NW{*adM;{gYECZoA?4H+kP{)uI&1?X$LI@!hGt=mX3bPD}ie%P7$hWF}U&J^IJ2xltYhNSw?Q*Am z0Z~R&FaS!BkPWBq4vKp8mi@DsmK1&_XY^HtWs^Fum%wWf6QH zZLA3}A#zn*e!(tX2U=9W5KN|%+)9;$+|*t9*FhIp2AKA^Ojzy9a`EwSzdB+(qtc9dNhv)?jm$2 z>nJAQ9u;q;3f#FZ@!VmirL=uPD}()Jw}q<9poE~v5+={HLLd={Io?tOak8MuSC_ng zY1T{y-ROmDE;abzf-_F0Lvr^z6_NbsCl*dI?fSYO! ztb>6Od?a$=gs^(h<@@Iq1$;d2C~&T%qAr)gx0yUjN==)4o)e#2TZ2D44S_YexJmw| z{6pD~9Z_z>W!{L;DFrW&(mKG5$k=oo3lW?dL~sk%Iv4ixeD4bkW?QwpCL05=0qWEi3^y`%tT<;*~$j@b=d1< zP`ZluR7h~vDFMZ#VQJ1UoT;lh&Jl{$*gfGjtkS;l)O1d@!41J8`Q=!vBnY*_{lGv; zuM3f~q^Jefx>%-&&LmY9XT(jVZ4j1-J!kt*)C;$rJc&yGI+~3~W#o3}%S<8Ol|5{{ z+eao@{aZ}lm}p}Oy8+Ix3pong3QA4_$2vrq1(jD9sC=>kGBqp+jmh@GKy3;!h! zfi_93kkeC(%diW|stF)Z=BTh2DPuX)o}^C}+cYPsiD1oG;2@_;=e@n+QBd4J5p_4G zke3uRM!{b;2|c331v_D_&DN#4fITFj&OCo*VS0*!SYigPYxoUnmmQS39PUU!-=z2m zDfD3o>_q=Zdf?Bwtc8W)4Ep3>#plt7udDRcz>`4 zF9o}v*iynU%vlZOA@%dEGX_`73yLm4Fl#(-OHPMruHd{Il9o!!$%(y+b`K+dxmYiT zqV!a&7C)xoMS*jajZ;z0Y1jzScOB$u8ZNv(1urL3O2)+TkhBj4Wgzhyd-okm*0I|-^GnSX}Uzr@kO^BsWO4a0Uqy!4);RNcLYSRT26Kz z2t>CP1>Rv_v_iN$9gfiFCCdL6*5E2>8+L~YQkpgFJm?9?A;&!o01u%fQ(&@-cltf? zqxfER4B`s?+ZJhiBFgiq5xkW8(gmWBNKsx;*y0)EbVL%3Po?A(uVs@mtDnw@g?j~o z=En+KCS~#V#+VvEs*vWxsv9q$uKCqVj42jf&sf=Zr^&Ckbs~5^;_+*%XLb!{4J2jO zP@$J{Z{5B_>+!`kPEL?=M8~-gV-lQdjXtTJu%QjM`0yqqfw4`CqnDR@_lWS6qz&!Hqte@DOet!4_wVF zGUOZh-QSwAYgnpYQ`?Z2t%6pO;CmCloLbFlE67!hP-?0p&B!E|3xaX}7qGE*lO6WzA z42bZlLJ?1w8wgNmQ*cGI5qhS23>a$IGqJjSJK~vPny>-|0XIp)UaF;V-ZW|8pspYy zq7pG`DLC2Kzl>=js^jeDo*~k%o==(lyq^=Ad5moeI*dMt07mWwlu_gw2eWz%Y=s9q z{UC0b;z~>4*zX7kY!<-!%U7OCcaWmp!o; zT0@x8MeOmm4B<`r+o7p%(V*4I@~9SE2LXE;oa4-rE<hyC9wyr`+xL778}!T(nCjdc<^^*h--_I~`1unh-=l*|MS&ra_ZtG_iQFW;?->jiM$Ry57 zX_yu4EV0RZScye6lh(2V=a(3Z7nNU)dv)_XncfQ_v*hk+Ni1il6$?(>;O8$bZrqKl zdPmQD*@~DF*X?qY7Tt3tIW@kTJPgiN^Kf+-;We?ReD~q#+LF1LyRU{8=!U&z9*64` zy2S9ZH#M+BcEU)`@B!92Z2mVVDaHG0d@rHr<}=HyWWxuUe%6}~mRS6SF~(%YkuF=A z=tWR3ZUkFWTV0xvAaF?q@G?}=pKmqB-sJVJE>6Vm7rq%DQJj!MSbl|}Md|e>Ra-f| zr1eX+7f`yEa_^&R>8e?S9}nm^2kYbwo5fIyRgmafxzk`0dH9YbY*kDQz@38jm(62a zz0#0r2d5_=(Z!TB{^qklHhH2tmMPstTM8nP*Fo6Yes?-taG_!POso_>)64$8b6dEn z8`YA^E_2jcnkQguG;LcJRp}~h+z>2<`1PNS+@FA@ePpW@bf)1=#)`R2W=j&5T^MHx z0~Y2~$g6C^@%zHO@6+W_)X!NqPRfD*j{;+2pm|QGnsFEV5{24WT(M+vFOKy4M5ZlA zMOA@%X@2Ogw6hHyEczw(zRyY|;&bqpNvL3(0;XqA1zVrfmT)x`zQ9{V-%sk1Yy)Fz&G$A}7N;Yoo;KYz-n8xw7(}9BRh`e>@tB-v8t-z$Ht-?V zP+%A>nV-Xb?o7ejQJx?R!q#_2K+3y0NR)u~V=xZZsk-bJ<&hinw@ zY^WSxo!h9xqx4L1K8}bUHuy$Xx0a5(Sr7`7wypD!h<+T2_?_tCD*xr0)2qENIx0gKEs@a-*(A6zE=DLJePbdOx3WCrq%o(? z5TpO#4kiYQQOQ2#(JkFKHf*0%d(KsKL6XbMCu%aWJ>`t=?jGfTvfZ`=%2TTW8!pAP zuuXA~UlBiTIU2nhfZw@&L(9(%Qnx$H2;iRjy1mR(`o()8AL1>Tm3u{SzDThwVFBy# zuuIriHg~Aw_R;I`J;ZCM&lyuzT2naQ{(Tztr+?HnrYy*DJ#r(cU~h? zvF{_4X%JB9dtmr317AFL*W3!=rRR5Fxj#?{0&!~p_2%~lh5fGFam8L=ur0HB6a?CS zCJ8iDTncC4>bAqVNATltQalg;F8j8Ss;AmR{r^PQf&U=se^$D!X-5~7rXt_&s-&1dwt)$ypXr&HHZ9Jh^U+ji@&<_&U)EX^MN!heM9kWSG@A4HZtc!0B( zyd*_3G7tyHBPeH-9O0-mWCM<8Jd(27$vPHaS3-KG_;qL$&Fc%ar?96Z`kH?lwht*o z92o4|HywZ8XLqLg7rmr~;FX<(O4bSXgjZB-HFE@54g707uw2^rk3^HP-H-IQ=X@}Z zEB?EwgqdeC_RU2E?qC4pH2s_J;D1L#WQ>n=-af&WMfmKSv?J03514mgGd-${8b4vU znHf)iQvuWb`Bj-1bKW>BI;Z^-O%HE#e>$h^``HDaNQ6`g^5eT_0qt!g{kZztAq+lP zBnY>s)Z3=n3HeM_wze{#*&tr|_Mm-3T^*H6zMo^at?3maeSYKV`=Y`-Dc0rgYVIq= zM4l$Lv~nNgze!e)q;a+5{v)p1DhAQ>a8o34f?OeI&vp+kZ#}ZI`Hg>Y6#dqJn5rOt zOl9>2HEU6*Sg1rW`ezKlST#QmK8FctiMdD6z53YmRzeqq%q=pOr$tRCE6n+dcSI-q zNJ`Y-Qhb8A20r}-pnbvO{o_HUb;$1NfBgal@g+?kHAgGTXv+ImAxFk2!bJ*P@2|02 zkMgR<;GgzB0q=EP73Zc_H5Q;m8Brkp?-&!XUmt@%z_k9$Oe8bP%Eq9^&KkoG^M;aR-2mw(tY% z2LG%D^py+E-m+XM%)<@W1x`KSD=kDAa?eK71H zmxk9lx!Q7;n;Jppf5{x1ov}qnj%VF*1wJk-S>0l=Jx1%mB2^q$PY<9~rtdIK%byp@ zy#&4N;`f{S|5;)6{9w2yR7_VhyT)_I%_QShPavuO6?W@UWm*2QhY?pFXx6i}l;@zI zmZ5d4we0fPEx-5|vA#bH*+-PV{#OUTvSPS%Q;tpp4wPzLLXRcN0cLiOu+T4XOMYBS z?^7e!ks_bGf2PF0i|{Wd{^$dJ+g499J87~%jm*HsAAd}bF-jz#d*>X#_@-bkQ8f%TF?8{Vt)1T_%13^zuCUl- z)Vb+q5YibD(PF(mD&%3f(l7hh{5tRGCw9PpJ1^)rCR6=@kR@hD#zw158vw?k5yh_h zlApfRKXA02fSm}-H#ye7F?$9GaVTAd2S^%Bg#_OojKD0fW(h9Q{e7YIAEF#~80+5{ z?*EZzWY<~a=l5AKdw!nQmt1sFbS~qF3+m25-rtz?_agwv`g$dKQ5lIZ4D#9q!U85c zJXY|1OGCbEmj7z4yhEt$Ui0$<*!LqV286}QItHCH#$N$rF0)L^7jx|d(TD7|!}E*} zca3+-zF2=_+CLBr`0XW$_ge8GggHg#d@U1NqwxI5RraWbKN?)sUojV6ayf{nM}N?v zHdME6$o1|J^$JC-)zMhLZw27PQT+>)l;w7>>s9&{GjuJ@S#oPx0f&Ja#PXvub$Az# zXD9gg*}wiKN9b^&=EpyXb=-Mt42dvyfI-8uebJy0^ChQ+Lv;k2W{;kAIfD9$-*H zpq3Y8s(Lp4>IE8`jHBA_YA2g=7bELH0P>ssL^;DdL6eFi^QUp2^p+=;Wt}JAvmo@( zKK|dL`L}InkBui~^!iYG;4%`HG_TTOPEfKOQQB{(w)$_-Qro1C%Qi*b7*_^B3Xi_GxAmC%K3OJ1GEddy$y7GHW69 z>y&^aL0Rn7{ry;=_)i=+$4d(LyxOmeKJrOe?iD}Hn8Fct1j{P^f-v6~E((7uV;kn< zDjAOXBCJ))u)ae62kf>-aZtqHq@}hUQb+P3A?hS9H(eUUJO&zm7_i@2lniW?awmQI zs0XD!X{qfs%@1s0zT6nipI73C;ftd2-pYF67e&Ip_|SuX!e6$g$?K^WZ302MbmP_oR(ifbk)K#EVD9pFLFx{jatX~QpO|!weqP3xpbFk+CSdXCgn2)1R@D3L zu9-0UcAS^H@Q=U#|E+**mfL<&5i@ZXX{LK_)2S03=&eDtTt-$7zxW^@6ihpkH@`RF z0a$13&@w;1TgUzB<%Gp$`e6EAaWtOkxd~(7JR1G@sF|tz)%XGHk{u3f@omAxZW_p8 z@CA%J?2EkZ;$J4;6QFLWP)DtO-FEmCxL5fkD7(Gp;r*XU3jhAWW|Ic_3^_fN+*bN| z=_bKYnF9W%{ZQjKJFfeTCp@&H4W!I}Rph&S=xLgY<}R|QTveu|tVsmB>WW0pvm+*~ z`}J$y{k?vf4FlwG!a7=W+t4+N=gpl+uU1toyp-kl>NowHpZ_1Vxo?^O;Q%JEciDSt z;(t)4t%DZhmLJo6v=uk_xywQ=jQ6F1G0OjQk6-!=!rz}zdL$uWsw4FVlnP0=pnXwD zkXxiyce$<*ld>TkhJfsZ(T6waLp;Z$D>c$@%f&P z{Rx!Cx?_k;PL-X%PNs}b)E)&IeZF_O_}2M-+l&835_sQsioX}}fgfE(RagCk^L{he08PQ1Eg@$pL-ciwez^i(se9lN4<2ff1K2w7JEnpn0NWOKTL+m-3oNTtotx?jND62vyYi4D zg90DeRh%O;Q0Y6v3co=}{^uK@^XxsPT9@92GqW^LrMJpcZyuGl_J1SC^2y+<6N%k0 zbc?%al|v#0!vxdb@@XQu4nrW?#aNp`-Op3TN=)+3E#F$w>!?xiq(jmrPGQ~I|3zCSm^ZnBhCk}7T5;|xnQp3=(HjZO8b!0!My z0uUc`;7d4|?ixpYcckh!CN9oqdKVd={?XARXbkb|AOoR7kD_xz0Ox9fI~Xrp-NF{{wZERd_o2& z8d)eO$OQ>B?d={0HJ>I4{2E=cpVvg8cm5?Kp$w3m@h|0j|8b=cI&OZ-@9`M(WfZXc zH&BM*;-VR2<m;=Z*#!$jiGjyMhe%hlYrD>&tM7kut!4;f|U(#Dhf z^BcVNQMT_1#ADzE0+j|Vw>#YaI}hVnia+ATL8W-OitHicie~!>SM9pR+w72Nn}Rf+ zln+CA01KmiKU7Mf_WhTHO#PCkK zQr<-#xRXZe<}~jZeJv&$+O@+0#}fS2mK{`r2k)ST*x_}O&|$#jM^q&%(R;$k%{ukk z*pWNcz$G_;3utm8Ke1cbN62)uX`U8gox+`%i8Y`E&jb0TMUpv@PCi2qs1d~ zFfq2Kj+Gb1KM z)|%#ib;WXtC>Qe&7AXGhbj1#(-*FNoBSo!*7sOY*G|CFjj7%nNiNA@`yh_4^7Wml4 zSDNB;4D82cs;%d*2j=Z#$|!3MRnp>0z}^B+2@$-k+F+_KX(UC>G6u^yH#FelROC;)yss6{VWV@D-={7f@z9c z-Y@YMocm4hv<7pyubgbFxfA>*bAhw{084Uk^Vdu=rV(6yD#`Wnmb5a>h@mcCQDMg; zov|Qz;y>6fGBNK!l$^gFf7xV$H13;bhY^S16&OC152>AuCm+9TCnfHCxZ8NnGSKmd z?@PWAxVC51vKJ;v5?CV*rm_+G&c5qXxw>?K9FN=E^SS?-a|XOVD?4*#Zrm;cWu29a zo`5y*PN2`1hqwufd*|0BUX=vGrG?(_?M~gB4-fN_E&D)4`@e$zcQXU^Nlytm@b4l+%!Rj~a@QBq=>S&_~Q9r1s#(hqSB zK^$QK==6RMAuHvWrqTAbnjRPg!uHsVoR!NhHqSEgm56x@y!0_w#^@MQ`4&ozoz2Sp z!qI}Ok+{wm(TTXJi8SA5OCIuqxr_bOX{`bbr)9`aL^UthIU5GB9MV)_#B5K1gc2}o ztc-K+q^_ks3FdV+`C{MdcLAP`Fp7pS>=S`O@R)HHW`Ils@u645=izI4HbdS>+WQgf zoFc|I0~ZA)_d)~J0L=1h5{<3nlVvv&T_uz30K=`QKGBoi-Ycj_K|F}Y7lAN^!}0or z#;s6+o46}i@=2ZIGOxq?1#t{@S)z7YnQCshM>#u`vGC?(`k>x59gZ<>SDqayoR^hr ztknl24O(LKLZvj>EYZ}ex=}Wl#K`Ye8G*-J%|LXHuvLK!bXF(ao!8;@hE}PZU7OBj zlq;Ck6Ib84Y9wpWbfnk;EF>Olg8EYr&e;7>KihZ3Q^ zz)b{SAvG*=1fRSc-8721p}}zS$&+AEXUL4_L-zPLrD2w26lRI++vvbpCp{hjptEHl zC>=u#@O|=vfa$|{P=ouk?M(Vd(>@MJdEhmBlhHju`zLZ67*o_8Ne@D$bNTKgWXoxk6fz6Vs~k&}y>92FuF= zdeT1KfqGW)kV4a}kU3$rIqO{%t-{x|pMXm_JD?ZHVl@0Ck%F`OSn&(X+v zBC;J)pjM0zDmv(tOTEXqJd@y%Z%6T*ShM+%4Y?}_nyHX0sSRXG1@0pBGxsl zxYE_8nFIG?D-xQTQfy9oF*2)*JOEoyBSZ&(LXPHl4P-*IQq^X7OO5%d4eh#~RB%`b zBw%WyKD0O9{6*nub_iw-mzGhEHBt{Y!eG-k_E?>$FE_6yoJoma6_=jVYpt>((lab%+S~kaK;~#ppu(s;IX-E+`=;F79WZk zP!IBSTALNs!g*b&vK*Cn{gjL1WvJ4Ci$F|TWc*Pc{>#CN|BV&=mY=K-MBukIPJ@ri zIKc1Bpy1f*Mxe1^Iz3L1$9lnxPbOYVqxBL(2x3#XnX`xTb&TaExAK%E{tA0sO@6`6 zOUf0P(&ao65f~@g(89#9UQf@GAqqSzOeq&`j^$nZ)m1N5p#KjHi z$B>B`O}vc-vDC51IG{I|k$s8~sdXuZbZK$k^bkCg|J_gR@g)%F$Ftrr`J9j_HJWQgbXyG>yX0$Foc`5cle8<-fG& zp+bm92fzrvJDGRZ5(Q+Pj-8hmM54t7(VT@PLdu4G|4Dd2CoO*yur7^3{DY~WCaqdZ zy7T)?CH%}cFfyfeEKOm-Gpp10Xb5+y==}EO<%&CD^zV0Qp41B5@Yc&!+D>b6MIAMT;p<{Ob{HiCh z}YOG7ipQ2CQVX? zY1d@ONH0ClmAz~)tbfWAG>(D{M7RhZJcZQ{mKgL@!iZTyJL(cL`l37}AB3(&HIIky zERV4ov&+TkOgO^3ivV8bQYoL=I5s8%9whxIXJ>R~UR173BJ$EICP-cOx8z`eMV>Vb zMytVr|Bz1AAdnrW#NI^mI)05ZaCL|RffEY+Dmz=$ls*u>FMpK3{=>nO1M(}vOlkk_ z|F{X!Lq;&9^F=nOas5GN=`Z4N7R{Y$FYZ_^6?bx5sG8!t-A*RQk!ZT)=%ZAFvErwc z<)t;-c%igm$0&Ge>WOwFH>b1ups;(V`=AYrH_0tPDU58YFj*DEwu0hoHOlDf2}-Nb zXXH0~7CkJ(ACI&l4}wugp=-r`X$#vd=*^yoBMgZd-m-w&Np_8dtqwjvV5T7NA356? z*kB2`l-arHa@r_t8k?F5sVZld#1K+nY~o2P9=L8{EiJD@{w#jxg?k1Se$-I? z!*uOIX`yCsN(!AP5%W^pTtq|*Ef+0Tiqu`*d3ZGNduQOvlPF;`FCySX&Z@3jBjgXA zyx|?T0?U=HnLh}2xsbd_GJ?WX1PXn$K#<4p8_DqWa3BwU!U+o6Pltr9H6=9)Zze53 z84aSvO5puY(=wQeo#sZH!ke~W8J>m~$vIV1R%K7_-E8A3(+vgGa!>gZ zSt4GpA}Weg28tW0h;XFnVs+lsvC7+;M# zEAYoI$LKyxc30n#~JXSN$hJ9<<=2lM+@pjpD>H0jlOtE1Alc z!@{(l6F8GKX_E^gQPYYN5hGrH+E6wE#~8+mN9mO$&dR+&IR*RYD6o}2#?3wPwLlbt zA2^)(NgDsE45-ALL+RS*-MhLMw?3q|GGM(jBDW4Tr0+2A5ws(PIj^_aK|Vr{kl2;k z&0nN>{ye#N2?t?+d-nQZTE0d`<6P!FwTAKmXjl>2 z0W%Fb^~gL?99tRHTgj#_NK|#2QT_uOMQDuJe&c22e&>o#opye>e&O!MtL5u!K8$s% zzR!qqn7UlfS-yoB1-B;=yyK8GDy!*OvVNyKo~m_GgiWp4d2!v>``(aWA$SMbSXGlf(zWnfBK$s`S{T4I5)WRs24Gs#GmMGQRraa8=w(gm^+3@YKZ|F`XKnf- zq&(UO%V=1)oOz50MoC6p2h3uLT}s@N2 zJO<>*q_4kWolJot9AoBFsYUrWYPdI!)&5{W_U}??Qn6eX=qm!ar%B1^A1}swzx{8fp1ggE#do{r!7Vth~&C^upjZ3dldPPGsi4lZ6RJW8OVT}{% zsj1mgi(pNM6-q?%;QXX^WezdPgM1?~cfh#VzkJ9K(XhZ1w)St?fr+ zu75b!4gX-l+UfkxU)?|SgHNNDV)vdbtdPSKhTP?}?GU+tE)Szp-mBGvwp>1Fg5*Ae zcfdL%k4-3Y50mXCoWK^1)l&gs^MB*SA1Dvfe>;cPIJCZX@!^!>teP-&p)*Tt6(8>~ zmxl>j*VY01ZU0?HBYWm{`la-*&5PKHgM^U|vv1X9xHTtBFfUhLoT?{c?tE{D42#j- zh!c$YJndTRaH(L;gCre?f z`_neS?8`xO!_p-MRey0o=cfX`9-7T}UBk?m>#BoTy@ml~fsjk`r7W@FLEZzpJ>d)Q zgy=8w%S7@bT>`#`?_cFO{Ek`PUmz>H6AHKSkj%`DrL;bfY*|;R*PfeKLSmHIcu&Jx z-nd1=QG#o#;WhzWDe&aD&z~Hqq|-PNmCQd4Y(oeu6~kXXQSXb0iLK}(Z_yF&^tANb zx4eB@ed$KJ)6N*{nI`ypjj_x^jn7`$w4SMLxz=gGE%OaLetYbXO}nqmsjukjK@WxM zftT}s9&~NGF}E~Az*B9LQ_^49h&(9O>t;K z=6-X@5eDo}p}#?I>&@2N@y+Y46J(VySR>xSX=5x#^izf0Ws6K_U5YS`Bx#0}PoxGL zaUtAKmwZwNpYHv0R_TH7;(w%p!n>Q#?p}AjCpJ&v*K9fO_iF;+RSwI?|B7a@?qj zu=jnBNjdXmlQ#MHG$0P4%T^=TR zwCZ+2tM{Q~Bpz#R(fdy4x&%|GybUV78sAAooKgie=`DEKA8`$IVGPAL3v z0?(eu5iQAd1ou+ z{W#b%9A$L4UT1?@tJO)>TS+A3>N}+w2dy0YF>u^V>IdVhvztc8`dfi)e6cEcB8wTw zmT*5&@i$p7fpSX|XA_DnXa!#K&PL96KUZpe z7>P^2y|F-G+u`E-e~-#vEb=?2BJqA`4r`%(BC&72a*DR%7|1k%!Tsqaf)l5*!q1W< zcckZ}zRGMqb03tV1RG7HF`2c1n#0o4<_WK&>i~uW4B~%HW44@gy?=iZ*>gn&XNi7OPAjzJ%k=lJ1rV5{sy1);rrK;+K<>K24rBL7>u-6dUewwQMV4t{8z8- z_LE614T>_TJ|<}Qrh_4QR+6C5b&wv);JB+rMdor_bW_uBK9M9Q^&%3suMw`+lXA)k%WIx7wg z*VXaf>v2OInYkGcprhp_P~PEB=-=v5SgZq%cDX_AT`g z^7lF|p%@DOF4vX4aeOa=`U~FVUp!0RJWxU55j;31m1Sg_41%c`PsB)`iOS^5T2dn_ z;}kCwDGr`_Ke6-9z+#z@R}%&sjst>^>z&$#acb3GTf&MtGAK28OSgq7(&$eU>G6dt zdPPYd0mW;(ZkqO!FNxxM@T*C#b zM@Fg_r&j7*a2CW!(Lwu7ir)n===RyT#;wJkI+zQ#cQj0{C`*_Ud~AL~>xQMt2V_Q288s}ZiwNs_TnYv;o8KhDqz2$M~Q8&*8w z>+22~m3X(G?7fZuS^K2Map(;Llq(X1TPWuo(IA)a!}4DQVF$oM)H;SZ+=IBfbvaps zoSDJ12rGaxr7ngONoUd5JJ1Mb@wQNbFuTunKj-Edv3GQ+8;(`Q@3oia3}kDthlHj{ zOp_-JM{7-SDMUJK-!RIUoCM>d?uAWb^oP+f{;qi@&^+y@((cgs;AM zy$QK~kZ4%)IfbtL=7S38jYsE62c7PCt&|5>aiD-;NLgKM3NH(GVHRY4wT|kr<#H*s zxq(tF73BI8rWdA2^wZUJI27>1N=2@)F3mCxqYD1AG3s3&ZUV;YC~}~!2+=$Md8{%I zb2E^tG>l}7Njw6OB^3b%5J6NYdxHu%KHO>?6LIb#Lm8d=QT-0FshiE?eQ)@ELW**w zjN5QH@KE2rC&Xh)dpQP!45F<}?c~`s>}~Qo{-tpW8+PlKMoI`7d_Keji5}R>Yh{#@ z6pvn6kAZv43B~F5EeoIjSnY9u`VAHr@5@nj4aL7YOuCz1K3t~-NXm>s1*{8bY6_e`dp;Dgu%P~?W>+D8)NU_8MO9p>+&{ZFF?kpA@KxK|Tu ziV@m-BoSwaKJFOkUaF`~oC_@^;A_hzkwbdMjy*ypXlZRW^D41dk-c88mYtnfE00K6 zoRowzavkLL*U+WVo-8C25+KuLLcwP?_nXeQbciH1pLHD+xH?SF&`>922zRr^(k6cq zHLPj%Zb)Nepze#)k_k)#I%0F#XKpj3JgK4fa>lNt0-FGpt%iwtLsph$6Pr>{Eazdm z420nSZ|+$@#lrlR=0!U3Z9_lD8F};8D8B3YRw7NArn{1LiV+d=YbvVCJuwRY7b7Ct zE~Z=wz9$ZV**tCU(A_UI^XKdnS4_iHp2AzM5iD&mb{GPd+j64Lu0m zP-A|ZV+==+=2KaXap*owDMolkrd9|gF5!BOcrnaHOL zaLttJkooBLP6iN*a#Kycq}bFm%(7m1x=@el#uh?urPZ@0$F>!MF$rIhiZP6c*&Y$l zybp!VQezlw2vg?n&Y>K_3+||w#B(ip&@O>ggBlUizB*+oc%yyI8I1YDNkS!K z61i-4M?nwTdsa|7w=%I(^pUjLGe2*mOZZkukqx-l3|t-Tkjvdhvun+|E%ay3xdd*B z$P_5Baomd;n+1;niMSI<-;rX6ENPNDOQQIoT-B_QQ?LK2Xgv251_4q=^xlh6`9i1Q z>#n(yR)l(Bm|l%mEAh|Ax%1GztnPR-cjGtzIq^F-3C3dvgTg16b#ru$7`|QZVzp6k z%PtDn_gy(P&U-Qb`J6^|wgli5vgp9SF6Qyb; zJDarK`X{i!+66l?WL(!$ZmLITO1{w@vQq_=Brm@#4Ib*i>!J5|qbz@b(%tauxiT{t(ZagYpA;C`;d*}RtZ3f+ZS&5| zo(`CLi@Q{ol%mLVfh7)f<+6FC`Z+j%0pJlTK#@qbPae?)Nm)y4}gUr=nx ztC-42C-|jnhs%teqshnh@T%Jbw-36$evQI1URf1uuT)t`d#fhg_hVEym?WEk*HfziV9SF0_;qUf7?36iB zsOM{ej(Y#G2m3EO?!fKzAyBYD;>yR<`*nnoHAw`-%9=$`tZLn`zgMD=qK~1 zIb`6#$wN#@CQHi>ncX-3O}ecixb96f595$Y6X2V?*dZSBlKxXI``4;1)^XP+2Cm24 zVS4u9Q(pSni(c)92=Dc&M=3MNTUAAz=1A?eZ=`!=UuuPJ55HjbZ&zhL z>SlZ(c&1MCyWtmGic<~DTR(VDegDWTBRUvKp6db4_%Ar@K9=$;S!GO!8{m$Te z0{}pL$I?S9c2z_%N{A)a8JtQ1_UTH-_8Kop8Es-5Y?{-tCGp=a@Yu*IPlAull?S|r z3aGsPNbY<9vp73%eoy+DB;8CSvxh=N={df_tP$16dhfq0cYvP|SB)O8MC%RvIaLpx zQEyD%9DD4vNl_-F*ri8^OVI^Oe2ITR<@!OV6>W$~xd(y>Pf=I#ol=b+;8n4S@GHjP!9;^!L*sS<+ zi&?27^R-f_p#jpT)PYgt7!ywR5OJO@BHEXl88*6W8upi6v4>~G{ ztCz;{vQ!NEUc)ww z`9kmXzB^vzFP9EzH1`kz69a4%af}Q-VUv1sqlyF2CxtvOo8YvK!7_l3MkUathl@KL z*)dV^L+eX+`8C43Elnikg#?&?R=Pp#h2V#ocldH2je`R<86c=Sn7r(TqL)J>Anm*982xNrPibYww|w~AG_B{nrH$MupqDa?v$QG z?N@nc2WsE-%ZSUtaFF-q4gRdIHk8L-|L;}+?6Pdle({;8m4boS9rKtGEw9EiZFzZ$ zUr(29YSw>c*Bz{!`p_GNe`;N{31t+y_C=NJenI^GUVfikyzl+`p1DLd)~PZwf4rhUqmJ*OaI62N(3q#m3(+RWf?M1m}8jum?A+MTNe3;$BvpP%ADqrB&RKK6v#jaFY0+l`N8vjmb`0^*8}y&8hK%O$ddbMY|P(+3X)4z zUAU}(tRzkiP-n6%K!aNuK#N6xyD6U(m zsy`~j9N$R=#Rn190E9u?+l5{=y#+;=-3;i3M|LvY4Q{vJ0musCf4r7o6`kLn%=1?m zV(bjter+B)0d#5R1BD!i*N-%|_)?e7kg8(rr2&so_v?eQH|m;XpTGr-XBcgrIfaLR z5kOUCTf}tFh<}y>Yp>NkwsgO?Z}zlwOLxe`LR%WZ%QAhk3xh2oO5iU-TT~*_cyH}r5*&W?jnj8*Y`~R5LV6D4rAza%_;!*`;TX>0y zIcqsI=$OlA98;vr-_!0{4DOKK$^6~~9WsNH{EvF;2nD4av|g^3%Qkd-hm$$bRp6s_;%`2=mL+I$~_G!n5`|Ecbsp3H=++#+|P;za0y>lX(|>3@00Xoi;7?i13j| zoP^kMGNb^H`w9U$iX?Bf3xcbdH=Vl&*}sDu?>*@OwRe?!Um0oNuhTQmN*TrE`>M6j z*DCi5sQX`~(pdZSgvOn=REg($Fw!tiI6b1z+VV2lu-?m}H+fi>KelOoBQY=02&Sjn zy!H;Pmx?WQN(%q})!v^p<^QUmXDN-OxY=~y=`FY##mKn}<4yqo)10c8X!fEvcX&;X zhn=SSB*nxfy-a0gYy8ao3lgEqjFqt%p;MMc$DsX{_4AGY*Vg8l!D0f?5OK=7$*>)W zn_&+#!MYi_r(4pInD8Vbrgxf+5&N=0aS9^l+HJ&X#Eb+L z<8nXr{szj3`=4YxquxM-0#;40*W9^dpTbf>Td`2Kf5L{*p+uI{T29?U2I$KF+dWtBE<8tHBjkdTl@DW$u+Q;-&r zZVBn`ZlsYCM34rhrAwrxq(M48J-(&Y^U7e@X;Z|lM~My3vjdDofIg*fh_RyC;8X6Ew^N1ef`Oz0ZErrGNi?+Yi%v_F-RL-}(^> z`>zR$?%|jZ-9xvJUTT@2gyDKo7bl;2`Ch!*Aoz=BpP4lEi9xZtVc2d!-rx^=-)^gN zXz`UxVG}KN>aDzQ9NF+cm1Gp)bD&o^u_ZnAhVD(}mn^hsoJ8iZ`<`RlK7?kS4Hn(e zwi%oF)i_f!q_ma2SDyesV_c`~qd+0$=uP_-I{XA2eIO(Vyl38@;1<4fgrFP_t%1$F zzdw&XPVn`K+bv?T;=D6Ks&Tim3sUbZr{udUC~?P=7O>@=Mp}L?_@`$7_XR)I-k~*( zy*2QMhWb;>+SkXqWlru~VZ5%C`1O?RxVf#`Wz7J%TepsIR4M5z*Nue(24C%UK%Tgs z^6wdbLBc;9kKfp0y{`}y_3kf&d+moh0F#_5mg>g_jfFO@Nne{5eM)1Z=4c_vUAK<4 zPaffR3Wv*Eq*mcm=^eUIYt-LS%HKbB<-@ci0E^nrbbavgBj{22FQ2B=rv})sJ@9wg8+6uSmY|}$}O2|K}h`&68zjlF91EvFd_b@xIdqvN! zTgd-*I}{G5#4gm7A>%+(n`2tb@Xm`Wg*&<0OZ&gi9sg-4lLGt@*I4%_kAPiqeZ84d z_^-t3s@8gX;|f-Ow((kb`)Pw?*8q10=_Rb#uQ5zdF$%8yJAFuCA+lsg*iXp&A2J62 zsR=tJ#DLLD=oo)1(-Z0}zGtLJwL+X7Gf2B*UsW5q@(<@XSI3}ie_VE95j`49aeAcskpM)CCl z6*XM0u%Rmn@u(*i%L*4!+NU*boR``yM{op|DUn`GhVU4k6Sw`Edi&I%eD$)<`-0eh zd}S=w=~8{zJ%8DuXM51JG1J|IDmgfO0}ebW`q?}lJk0Ft=>v#B)rTS};A=CT!0J1S z;Mp$-eSKhphhmou2NU-O&Z8jp@=XvXGbTEy12&aR_%8?sp%CH z;f6M)ZOvRV6XSoH>UXl*0Cj6!C|hCIkmzs@>_k6PV};JCwL$i}i!4y|Kw4(+nr96v zjifN!urmKdPgQE)9)AIDP(CoO_)Qn0<7`xMS)8eRx$&g_H%MMopWM2P)%s?xxPaXg zT#8~RU3Ivgh5a>4-RYIt-GA_gx@b{{)B6GW;PQjIk{8%D?A;dR(5uJgH~XmEl!(T4 z{*7xjZ3BtSzSa57fY*=*MLWGRz2NZTgr(xqW#p%n5#oyd3N z*D)R!=tMLsa&`2*du9wCJ!xF9RbPCru7tflG#9sv*6NG24p~m^r9T7H)P{k0htXdbO zRxDkv1i12|v`BKQDb--M3`U623GDDp5+qmHYw8%!POd#qMaI}wbK$Fy?B1xNm6V81 zMskGb#}W6r@_4*w8xh`1v4Ny-@Mn@MW+(xi` zv`9!yBIMR6K_|bwd&(Uj&&TK=Vz|x-OzjGTIu_@TUJvC49Ydz~_O&4b_<9LVD~PMW zV?tFF${KC0d(n*tD$g!?)FX$d`VaLn$`8|(xEwx*h=5NQcpDXO33LT@Rt!Zo)DE83 zaD)M?i*{V9$-M%I$6Szaw-9BUSPMR#o8pB+FrzZ+K|GVz4G^H1;PbqCq5l4JJTOHtGUn(z}DW;Ss5<#u(P{Al$V4L5kybjsmy*WZb}y zHaU@S%Tehd_`zLqW$#7F=%5X?n49QNz&T}COr^|rSS;f*yydi{$hjFTUQT<3&9EoF z-l&>K=(am~=4(aJo&C%WgufL0{K+35&-*w<^A*7XBB0HB$gE4LP-6i_Wbj#P+n)~p zhfz5H!2gx|vPceV9&?7kU!1&1PD9LRxv!73BAJ~r9bMgb{z<0G0okKx70pJsv%lN8o?QGoA`ycAk=rH_)c^r%Q_P9zb{g$6)C zg0oEuBj(-l>CRt&T>7t7{`?^>Vuxg|Y}V}#10Z=X51t^>|I_nYFIr{`w-36A^YsL` zV+@H+xj>^VT`E|Y6|djw%)v=4Cz5Kfk3tDt4t91*YcuoS+17VCcgq-gaPXc!V>urBfZZa)6*(S3%L0`U{ct?JmK(N?ltzL{oIsdxEn zh8-kWb5Gi`sP?bhn%mz5VQD_lZ||2$-+zI18HZ{-Myb=u zXAL{jqa)7GYhKuPe-^)e(~F*>7lMQhHZ6zrCikANb$Vp*4la=)tg9eSACo480q>e~ zxSPhDws;quXzy!p0l_9>$mDQb{_IClmasylt?BE&y{`FG{DXT zV@m~C$raW`NH>r1C_2p$mF~^%j6Rvq<8euqrNzfqnNL^fHA`332G-_^E`6BVWrd&le+(#DCD%a!gh$Z z2NR|qmaU0lu%)9&PkXk6V_tUUSe4{D9p2O2zF1=GV1?#eS30;n-8$%Zol!l%vhF5I zt)5GJUnPWYhH_gL^&pEC2-$wjT3XtMJgB3pb_5ndM3><0en$w;1(pm^Odn28+_`-) z>*Vw>MXhGt2<2C-`6O9E6U)fXVIlVGD4czBYx&^Slu?uXUfH=Qjy*&HkA}BEVIK}L z80((iec~YqT`@T^oZB(Piqn@-+|jzB)EZBOQOo3i6OmJ0lSEd)WHUOnjQs8azx z&%7^(Y36HqzA3*r4#y%d33|4ZcvvJTi48;zRr*;!_lLZgaU`zR0o&aJA$P9Q(gCMJ zbMF>Lpb-?0ZkpDJl!lokQ1GaQuELI}4bf_bUZ;9|7hI@U+rXVb6AYGrZ*tZxuN(r| zs>nWYPA+~pmL~5^N*Gx4+LM3NBQ!5$SKFy7B%BTl@mDg+ zMvY)LnTJA*&m5*XL1nMfOu0rTL5NZHF)$^EFj~q#O0GmU24$d_--T))Vtf%YYBq{Y z3q832q)}aO;+@*$yw1RoMp|d4^)VWOJ1Oc9@ohc5xc3{ znWii>^;K?>S{i6yd9+uh4p6OA!t?;60^xOw5%d_(unc3gz8mGScX3YMJm4=Bn+eY3b$mLifEV+Zc!im+E!(|idZ&S;JV=#BApOIrkpre>sAJXa8^D^TDR zMFvJAot|W9kpkHLZ9O%92e?rKp$D!vAApZ`>3i1JUxEt1fnc1V2pvJz0|FR-uBWMeH6HxK0+B)W?PBIsQIQ( zDbtn@M&|XzCf*i-k~DQ-oCf=D7hr9@s^J%1DK>Cw3i zt$$OfY?pQJ;}#fvHeb_y>ao@I~$54S)g7N*9qG&AUZ}ns=TP>f^luR zhEA&AEZOj`(?0^n{N5Y*QV+Q%J(G|KX2_wE6Ywzn-qw29fL;-f<<ztO`)F=U;2_IR;a%aq`3xyo%vpGjZ+AOhF3-6BW&U&hEeu(I zrGvT4AWs)>A}*m2k=b*ziRY@%EX#^2Q@%A$p_$;~WZ|bcp^ef4%DAkpdT81Jnvl=S zDH{4JKy*MOO|m@~NRCy-$P&W~vNGh&hVpQl3Tl=8He(|-xF9)^x5P_lld|Pvp=Dbh zIETR^KGKcKYA-dDW{~1XN1k0PY7cTC$e_)XVOv_x7EwD%ws(d<{#t(a!eA*a zJrPq?H=Zb0EZ%9>r+5wZbM@2zrf7Z4I8C+4yBzh=dW7BD>EV zhWy#oce!@|Y1?O$$aroP_w=NspRelsOXwqRMRa?O%E=%s^mJ>>g_e9mJo%iu_}4y? zR&2hauNxTrH@ns~=#Wu+l4#o0macX3_(-)QQhAJco8NO)XBpm$%x6hU-HV@l)y^+8 zX=#_Y{UM2Xq1@NU()W*i!P#a1pQu%zUsl^nd`^UOms-68(lDXuLh05&--C>!i^;Iq zcJ1@~o_aP2;x}p^ScpSC`iRf{L*@7V<;*W##L509zx^Xf_3htlxtPp$cR$$VWGqEa zR&pCm7B)EkA@0YY<>8NKOpE`BV)*X;bund|aRB7!2O{88NS8DjbA-+D7hU`#*Z6{- z-nYx!cbe)8;sr}!d6X#Xk$O;OID!x`?Gb<)==yVtsgnz*mO9NF}n`$|CejJXk`DN zS?!;5MRQ(0YX}Ghk~G1rz5k_NDnClW{*=0uX|jaC4;nQbCrWTq;R{U>J}syGSGL&M zcDZ2W=)cX;{v~ts2juwkp)UmdS>sqFmwc0GMk{DgX#&b$B{<=<2H7oc6FrJq(CRF4rLgT-)O&)Tzf9yf;7JG7*OkQBWx= z^LO`}{e~_6MJ@2t87VwW2|TFddVG)NytPiHbJP1j2wwekpx?m?owsz$5=` z#@H8?#E*KfM&<&vY5>~$tU#Pv%B-Z8S~t7AxbI4A{it<2?^ga~Ys$2iJX#?DB?=B9 zIAjWFe*Sw+^RxL-rcEhImG%f(;1HAkkULC&Ypd?ROM_gfo&s<-KAu=?3AQ*q%|O=D z?%4hFX_&vP(|fJ>m5|i9XNNMRJpTJ&RLnTpmzqR=5#Rh>f_OgG`nlk~fQ)WFX!Sa| zA|t?2?LOKR7o|r1J9qeNR7SBKk_aTuxg5$_YS_oa{%$gW2cpivz)zLhn_sx<(LG!8 zDy-N&wgHmT_|wr#6=HM)R<_l- zh}l^&%fBgUA31v8a@y1C*fV09i$=cGpeq;P(Nq2aCO?M?JuMK;r7Mu%lgs7Ke=~8T z4Z>pzkG;wZEqaIZgg-_ELg03U`rwVW27W$C|Rah3uN_b2QHoMttjF-r|+Q9wX< zmgW~I-~vleC?Rwr`N>-X0H_lBGbhsn_Qa~w&drPeEfo7s zz;S`oV$qwgd};RANA~LvXz&AGOiKgBI>s;;gj7t0h2qLRIvYAzuF+9=hnx2mCER9&4{;R>(H#T*_bW{R5QZH|pCnF8^0r zhyB=X?~HR@m(l+@Td(?N13oJuzz1{Q_vr=XJV;u0+eSFQDn3>-Vb1k7BC=mH`rjIj z>X~9X$s!r0h1L0y36Ajd+d5uU(|zMU{w7=r8w1!@DKPZ3`mvm7-}sfrI^sQHd##ExF7W;sl zp8wrxc%P-u5H0=uz_Twz`~MK|3&FE*I0{p5N_EN~QCXa=U`$yhg^faVc>N`2e_lZF zh`t_1K1(n4k}Ah`e#3=-27~=g8NIlLuJMm@32=KQXk9y?IaWZ)EMrA$w*jOf(;xTz zv-kKc32G8U-v=N8@o{m_j|rDL8SSponh$}JN9kOSe+Fjj*|t4P*)4=oiRt}Ka`xW| zyV%ye=||JooKHJM&5w*f(Wz09QH9I9b+LJfKm1D0YIR=I-^m7$h78pSa35v8bTVo0 z8_?6u5F0GqQBX1X=pBHL>jAPhb=JDcu$Cz`n$e*YK))Hurt!li@M5OG+cZIigkhm*Zxfz%CGz5UtO2~;(TWv zPfjPfdYOLNg#D|S(1Pzn7syZ`PJ9WgrN^i~wXF+xOA;1-7QpWX53t^TnBTh`)-`-d zTv${!Yxs`>RUa#^e^T7OTi5}1Nkf1=N#U0FD511&V&5_U@JBj?XS5T5 zi%04BpZ0;*6V9pKBSzKr(xRiZ{|S=$|M5HkG9J}Ubn4yX!DwNlx;f7&=_LGQCW;jh zlY3Z1AYFxUHm^K5AA=VXAHw`hLi%2*0$_G;JRB0_mHXw}v~)@9B}WKSKbMJOHUq#Y z-?P$Fwh34cg4F0fBF_FyT!a&Vgv-9@r~C!$0iKmw*yAK)f;FR0073xw)z&hp0m$Cv z=Wz?(S2+WgzyB)uhKp*SP%}v0Ra(}nt&dqg=UoZFy!XCdM>NLp+bUtYyQ4b%lzS!W zNM*}-t-RVJ|9X)E0z>dwi10Rz>X4K+jS*xJ&ll- zB(3GKIO)Y)DMcFNG!`5z3b+a2tH4sb^*xb#aZ}T#)BBf$>!iSZtiXdG|DBY>Pq>&r zQ6TZVNCN^0wtcC@74YO^n@N;mEI}Sq;snv!bZl^5pMhXJxg<@W zAXg-cd!IR+c|eqiids`JO7aR~**&_&yYACBV}UM5y3gLcDqPq=ltvSWSxAV;)$*DP zm}MqiS~9>{Ojd?m?v}O}jSOxOHG>B!I$GY0!AKY zZa}9-X~nrfDvQTWDP>UB7)v%Vs(G$L(qE#V<)Xv_CMh@(}40T4>%H-<&e z3Y5M%1Q$3V5D8A(CFn#CAzGUoaV;4qUEJd?!b9y)%V*JsGs#H9JcK(AH(t3?(mc&t zxPq`A5_1)&kY0<~Fo?Pix3|n6BO#1>h;Ti*(~wL!f538BGXO2ip%IDflE!U{N*)x$ ze$Feb7A@4^CT{(++l@Mowy32*n57w<39G{|9f&)Dp?pzShvVUQa$>N>u3aPa^wLn} zNTx-*I$nVVU(2<`(r1rbY{7e-lJ_LbxHGJ{(LX=LwnnD=+MZUZsEO+ukoeA0TV57`c>-#d@-Ov3|l$4Dd!26Q76WI>aWYC$pcy=(YvbI&W#(s$ZO|b! zqxu}nbP+M#=)I{Vb(TOd%54vY1MaZdz3rm8UNO4crq;T>Cy3ECoWcXwUn?mPfHSu7 zd}-S(=yIiubKsUctn-%>2=3F7s(MOCS9Q&f$ne_cfjn!kZJSqA#1FONG^ zuf=NVzOIkLH;iQZAF~GH3G8M!^H5lZ)EGB#C~(6!MHg7A)!bOej?FxqA9eR8a2>m9 zIV0^4rpI2v(;7gQ1x-RBQEM8=cd51BM!%@OUTIxSH67H$Li^>=Mt3=V1*cFK062K<>`m z2)4Ih2cdz1f~RF1P@6dEGxP&iiy-e5#AsGdklzwVEbE-OPN-X1KdX zA8HRYi=nHt3lgq=TeM4`tY89~ctGh4maE*!)Iy zq8P-z6?W9O@Yx{~48m41{g$OLKwO)Kfe-Leu!XJ&7^>EFGX#BGeBwyx5uD31wB-0KuTpXydk53u%*L=oW}u*s>-*u(HkBS> zyCah33M@f-6YQk9BR<*%9|H4@pl)WobegC)Vcybw)~zx$NI;~zeNs3SS&rg81M1qU zSyu?(4GKvG6piM>?>(fJ%%)WEGHOU)ydr!h=w1Rwn+8U^n!Czq2zYg8u0T3{9U8b> zSKW08HY=b!&evUhTTmM~Sl2e~{c3@o$gjUE%(+Zy1zi&7!;S|HW|@fk@K!@1;X>3~ z?hZ1)e4f_`xEe2xM_RvWIz)4~($5yQ{f&h9ogp##SXJ$3IxrHcE9!dpL~*3b*57im z70v?T9<|9cCokT?m{*uZju(R^NTWMP_e4)5a;s66PTOP9O^Ak_)yHwP*dS&nLj=Tnnw?guCUAj(+v{5 z?Q@dl2}IB7VBV@~8UB(J!~!%lGyP4sEy>1}vWRz-HwFx4pJd{?<^;V|2)s!EuPu)U z^xRL6H7WcK1$GhCZNojO-CPaU%P7}?r-r(=tNs$LJvXlV=dvh(3Eh1?8t|Qz=(z{z z>5-`eQkD{gOYJ30Y~1!i4NfDyy^4Am>N_TWwI*~qaXvH7+$xXYQdK3@9$iAldOR1O zMHf6_=z14s^o6~;z zTily)eWr!ldhKpEEEdef+Tyg$Ic)=8M6`ATn;+I9JGflqM1SFOgm&w4*fSWx)CUD< zENKIV*Q%{6kI~d}ty7FpR9P^GUP4umyE4rbW~JON;{U>s zzcA!E2ms4{(BlO#==YFLQ zKhaLVO!hC6{fS6iL;?RjYW#CY`6ZCQ1QGxR5>&iQNfXXer0ymPp#QN?Pb5P9`n%`~ zB%F{BzOp+yZ4Ucm72o%q{e4TOH`3iL*V>XAiD%^QyqH2ZrzoCYhhjlfy0`lv-Z!uO zkXxKjUe%fK>Xlq-4#cn!xhQ;Zq2`>npr7>%@Irt+8~ls(>$9F@KfxrlFaG{>NqOJU zN#Jv}Ru}*JSyh%PKo5rp@CAIo)bB?Nbo_i>DE>Ryxww>F@RMh=L;!h+^^a_Ackyii z(6bi-L+f2Y9)Bsu3oO!CKO(lT4+M04?0pI7(|QXCL z&BbSArI3Nrz+uDes^|ReG+@q+w`i_=AbAn#&xE`D_S)(H2onE!`0K&16*y-F;MM$C zRLpFcU)<+;N1LNAV#o1xSQ;Jj68<|RWJir;uf_RswY->FFxaHzO=}Nqn$^WX!w3Gc z$Nm16YJN@8Kv$+Uk?OD!^6XUjAL|&x+#EzM^*@^MmS1S=0E=8rdYYW-s%?BLH5zuR+CvELp;;s% z=_*-imJTa!3}?=hxD_a_y#5Y%j+EUa5^hB80VyYQ#v$=#j11)DC(j4j5;2`rd*sVi zmvzyr*i!WLiPj0^YPX*)Rg1C0#650bhcB5e(|LBaz-jj(a7=ExcCbP*<8#{CceaF_ zL`dHKVDlnuVLrfYCQnGzU&T7Q;HH5Cxf+*qPT3s>OPvIC+1`UHo!+Z?ExH9%VPPvL zTSnxz;y}TSDO|}$u;ekE16;GT{i2H$yn;+{X-h;fWd`^@=9^0TH-kK2MI=|YQ#vz` z)8g7=sfz;d7K`6_g3{j~SyjYVHCcbdV%18SFSbLvy>U`jQfm%u$EPq!dAT_I6)&B^ z(ISD~N#iB&`3*T@2yuouFfx(@t&<4c@f_##T}{2Q~qUM*T>>77+n{6VhP{naY5er)%Km5*A;1R!nVa>S@J z74;EEE%UISG?DMidiIF8iaxQ~f#Br>;wV$FTN~|aTW%!uh)j93@Gf5;>e5)+d^W}S zW(>VmW_&EvXja-J5hE+Ic|$` zi7rPNf@!WUI*G}1R;?$9fiur{X;sATs)?c}*C_r;0)bzk9L&_}*4xRhpv$jYfxYM% z=yZ(3jSI29VnJtPin5-HPmO6E(E1qHH_2?l>>Yjz$~CKNuez(Gd9x=9!{MgdZ`G4m z$f|)-2jr+@%u)!pH_mrz#v?629MFMKiSxgZowJOz8E-*}yC)UF;~^h^OS+I>%wEE8 zgvXsOFk6n6yK`wSJLiP4l;Tmqrr%C{%<65lgTa_G;oee~gB-aPOaum8OSo3&$I3qO z@XADam|(D5Q~7W_*``M~%NJo4lSYW#2ClcxprYw*20qCgld>F4th)E zlEVmlK6#W5?`^2zF&keZXLlN!e%%9iW7UJ!X*-O-Oa?V{cZw70Q~S?uqNIEuH$v5lAeuql?p;y0NNS%a;N zXK|<4&m?iPJ)_y74!X%q8Bz0Ftyv=w1Ky(b-}gRh?oz8LL$&`;E4EReAXF45q6?uyMV(Q1Fl( z0*+{4^uCJ-wjCZBqQuROlCMan`b~v#Ap5X31KVgt7&P};b@`rgoAIJ`&!p2FJwSdA z?p;n&-(LW3>&UJ_JkG#|D=)`ZsO^X%-BuQqmG4Wh&ta_H`>MApj4mv4 zonll9nKkli5cWy*KJ)g&$wR`*E5(<%)JyMB*;A3q<`Iv`5@1R??A*B70k)ZR4XPRY z?sJir2{=&HgkxI?U-1Ia8I0W1P05!kN$WG_eB$u>k%zwItmAQ5>N-CPPxfKp3AdiT z7dhJj{aRoV&5Tb+c~)ymeXjWBY(*l{YDln%vJU4utfsN&cD1ywoM|HD+eM8}oqBoG zyypD#cw5c0LoVmS&WM6=bk8_R)W|;80fyEWzQH+OKtjNv4QgcuSM}OsVV#24U%}V0 zUL`G9k=>X7DW5SVJ$zj>-HSnubg5PkIA&Id=mO0G+x7t#-}LYio7kAxmq^Y~VrB=j z*B{LwT6otVk+-qeB!Sj|S&c+N9hih7S=rBwKAvFhMB&&92-<5&tfLG`f@hW?<0lRq z(HnEQ6I#U#478SGrFmEv9Ka4*sQ}7mK&~B(yKp}Q41Z5#?0RI zIg-dAA1Po+X!@tb%tI@(8P_PH5!NqRX!5WKsDb#_&>fS2Ji#Lf> z`10Xx#aHOSmR8xCkZL$zhcw&jK=u@H1Rk(yU3r?xQ(|GSq%!a@jhPw`W8_X919mP9 z6^Tnr&$dC}HOC!U$I$rlzM6@mCw!gxg9afW**Fsfxn^hzyAJ~iFyGxz6fm1Xw}Dwy zzPledS#gX=O_K(!Jat!;!J+zCFh%y+%cQrpCN7=B8hbGL%)Qw|zUxB$x@Jh$f^QcF zFOSI+*9cV|_|Ulo3SJX+U8~y!f;S-aG#WDV#!Z|x%WY&xoTz_j&LhPQ&ROaZ!d{;C zj68f63KIsD*d8)qxo*;)TYG597HywigpITJNox}&l5P58>hV_b8m?(gyTWel)vh=& z=0i&v+5OCG;2aCAG^h#66_-q$N~MZiDSVdAji#fL^?J*5vb3L@;q8?6!Q6!PYAfy+ zD7BH^pCSQ*Ou%|=M}L`x7(ztA7F}peIq2F@w4di3F2(d)si1AUG6;~}vP9&o)Juz3 zM;l?^G2}x8X0Ni4VGp9;tLV_ul`Jm146b?S#eMpF6S_5fxY)-EFjKGEZTS7;^_Oyl zDXvAV^y5kTg5_O-!+hS}6en0EqyXYxJ!-99#D-gM)kD;GAeg3E>alkz$->_dn`3Op zD22_%B0(d4{+X0Vcv&S@S9px^dMeICa)dzDA@(A_YZHeW2_2%vLfEYnn7g+){02?M zAg~eQ@kD3kWT4H*_!g2adPq#~C2Iwv(Rn2bZ$E-)mZ!;AC6r%#4MgY?1a>fSy_Hgi zS%iy^F^`K?(0H?AWfyBv(O3*NdMteKzSQHF)DTJigDZ~tKuNBP9mrrlg`=+~H0x!JMl1B}jX=tswz#bAyU_Y$yra%}G zXJ#{asF;+I8orkKW|j_Cpmxq9Mu98buxW86RFI7u2OWcd+L||@Kn%3M(!5y1%Pl)} z9cVSfzk}=TmAxRaUd+|g4Yei{oxFw#@)*X-Yn|0ZVxe8-HtiU*LZDJ}yY2Wu)54<7uK(w4x zTTbgvdLb68dIw!oP~u`xs7w@g)FJwf`KSFA%k%_tM2=u+CLlQ{s6~ySmkTzVS8&}r zC!IvZYNSS)H0r^dwlpbK#j-t3Kj@(HFub5^cO&_H<*y?rVEBp$h;58cIc2pZ6*Kij z?j{Z16H6;ds&Mn#^c>D89xg~-QP5V+ejo#Bt=Uh13H^SouQv)Ovtmv9qoy849Odp= zghNOH;~lqo$9v_(R`L@ip{V{`@5(J)W}|P3MEHqSAxqv8Luk^WdTP?+a?@Rf4vTWUdema`oIF?QTx+TCIy}^^Fd55=P65FlN4eS(Ms;0AF zGM))>O=yg6%Hdg4R`7E(d^XkCi%&3@T;`!8m=Oa{G8afcO2;4{de~eLeM@12bp7EI zKCrN)=u1p1wI|O8rF3haAma4y+C9s4ZF02Ot+#Qu8_Z8#xo3(ppppcs0p1WhF-Pw1 zw`3(>w}qy|QzcuUjO?cYVGSp|cg?zSQ=}oDa`TcPy7TMcT&}=aVmr*nYcnoD+DYcm7eK-=i zmyd9VPVhDBn9k7HGO~s49We@5c}_a7@r?(J>VXM3F>cspNes$En%|j<(0nGT4!potuuRL+i9kIo{FS_fE8!}Hh{|%^gpX|H} z8Ulo{I2qG@`{&roT2hJN4clW_u;^T}m{drkER{I?1)Ruvbk$vIF~S2$^TLp0>Xvmf z3K5}tMLlGErQuv}!v!U|J5r7LS^U$dTROAE6LZUO9kRQxzpD(b><9 z+{I8-FT&HdTR)%J&}~`ar&oD-6K&14c_viyQG|CyQqO&wMc@Y(EhTMCmwDqEXb#g4 zLkLX=Y^CW9KugDnG44J{y}A zCgYJ4esp2ww$Q=2|1HxQRx+P zY34%~<}ssADz5(K%1C4pyfO~A79tPH__s#tBKeWAGt3-K^SAPon7w%YSaJ&uqfsr$ z34_V*NjqDnbKr8T=3}Cam@>%*`@>B(Ngd=lWK&QsiKkArjis&_QP53BmuJy#@hIru z)lM6QP3wd(>qm2mSOhY%cSGLry^O@0s#>-o*OauL${e;+LdY;6t^{q@|1b%oJ|7X6 z75L748nBjn>SW`ZY`}eW=t*T03&cd{g+Hs&SW&vVArUYxTGC z4x(DpxfoZ>yblqh!OSRvQX4)ezly3`nUT4{RF~FFGH3&B^eebfI%CRw5qtP@zJZhk*XoSl_ zM49Y_Z5nj=4HY}b;3VW#rlk3+3y4G^>$*#|Ly>Gj_cwVxiJXI9gq3JJUxojduJ%11=VI#n92CA#t4Gdq$6tT#yec zvFb{0Hw@>DDK{>}B|l%j$&O8HyN-A_Gv24HY33N}y`k@7%9#pM6P|b_VzECsWy1aU0$mg!cel z<1+Hfvr0E*^b^!Zy%9g%&Ugfy6r0Idq-Znjuaj3UUs2`zZe2j98l`XF=s7+CQT(m| zrVXW61ZW?1kn1*nVUkFR!0WSkUd8+^WGHQOjv#1lhnq?WYRVjKPOxy7)+1M2@81qEWF(K1cFl0Ta>exhcPwcq|S4ZT#pb#37 zC&HcavK6u02|}6*J9uY<%weLwC#|=c9z`bzWvg(1Xdp5GrU5y|8T}HU_4id)cF04j3xI@%~?8B5$H#pFas!Zl~_sJ0k z+-icQ#(0tKBjX2PPzv@Gt`JOz6SMi;N`u9I2Hl+7girx!;W^EdJ$K20ou<(bi?#8v z7&ga~wU?1l{Uo;UR!!m;4w7$RNAkso=5>;j?p7rgR)s^~f0U47qF`>zV)Hyj0;%>* zsJo$o&buvLL$b%%n|d-nj?B;uoebD3GoO01OPS+f zp9IV%!C1^kwy)n*TT(@mIHbZzb_bDZ)6eq<4 zx82C>N68EbGsgV<${eMS-sxPmW1fmKAwM{IVE@*P@^M4hrD1DQF;=ReqP@7s%PfJk zc)S&52X2`+!b7aVUt%$X6NS1z8nw5g3<`Bqp1u#U!g+Yp!Ad4jaRhOaP=7b47({?^b-4KE8>I>cDh$Y8qOQN}9}(6LxjiqBNqwo(-`9)mqxr&LQl4KcWcjNEr0 zTaGUmm#|F+bt)XwOsvN}oW~o#irE-$$!Q<>ialF=0}R4#oS6nXF~XAl=(PlxKTcwa ztZW`)SJ7*mc=jliCK6bQCnh*-yN@l7-|p_8^gaNJ$i!<~d~Wc0!=8zjOlJ zfqE%bXAN!vi$8y5h^4URc+UljoJvu@^oizE1JUq3D)m+ymmT_-79eJbYpk;j;M>b) zNp{sR4y^6vs~QvqWA(AX_Kx_9rN$8%F5^%QZQnb}HTNCFh z#Ks#7$Im0I4*OhB~>P*CLHR?W%M#MswW zQl7mvUer9F8Mm>F_>31$?OkZ7f4Y#}605Vuov|!*jAm5$qq?KMSMyO*3^%!~gQuO# zsY;}dI*ulpDR}IeSeQ1wwnWU;%{51YZ^_EH`*#Sdk`nSX20l|AD7>*^dOMs(l2Qb` zhkV!*E`W}#ZJ!_du=r-!^SbhY-IR%GF0DWjyeD_{k~+~h8hmZ@tTL=f$m^`>jq;&z zm0e)NbpI%II~u!xq7 z57C8o3zvVH_bovSJCjZ>QBqQ496VQue}j=*{t<_$E3{VUq!_le_?pNdYb{qNDag~~ zEhPv1TjSIuT<{(sXh$upicr zuckVLqCoYaAz7<4Q4WhA1&v>ZSiVbUuJ+`Lwqm7oO8jemvYu@Z`}#bNE)cI>b*p<7d*mhPr{@SRSIQsxs%6&4#Zhc#h`WnY$~Ye3U=?~Pf{}Tr)Z)f?VAdRwZz%3+Ps456OAb8P{f<2?(;dy?tvB(S-r4U@_+K4Z8|7~R*3e8SctWq@hRIeW3z(DFbq=**@oks24 zeN>OHx^fL_EGy~7=M~G62?g9V!U`g?lVD!EHp2UEUb#>om^vaI7Z;tnPcZ8@4Cqah!cn#vL|SHHVi z;nQpw9TV|<@!fn(L3_|qcm&U7rzl)aLCP+dt#ungUCD`EE-)J>+eLBvB5fs0y=l{x z8$h#{T$Vhu`0ni;=`cN&P=q@KGY(ESJ&KRE8bB45qG_p#&V>`FFX=goDj5b3c1;xb z?)8!ab9OvN>Sg-ZR^JSRTW|S>XpyCO&_3HRM_!e{HB6C-GrcVwp$voVr8%P%Jn0YszuGWfvrTQctg#&7$ za8As1y>5~fhjo;Xpd9n98HHD3{NiOFI5jv*k&#Q~K5O8^g54vPqOL|TAZ9%KJJNA? zgOMU1B5^qTw&piFKea~mbqss$LM!-WZ`z|@Rn84;&-4Y|Ab)0u;%FLqx42D3DY_XY zhKih_0dF^N7RXzL2u?bwuo&FR<1Ml+-XI}MXTzKgJwX~S23cq z2E)go)qGVQ`=2Z}-;VC_y`zWvvW<6?s@QDT9aN}wJ$1vO{y3QLw)Nx8$IZS8ioFp) zW~RfQb9)s*?yyb{FG6BPr#E`<3h}(A^uMu00^5bLZ&q~Z=4m}9Wq&d$AsiXW?5Ix< zX%Md`>*AEOySFD2Ch~t|yknFu+t#I4>*b1`V~l;4J0aMQ*9TIim+*;sIeTwFm07%EmME5)BGX=@9zc!`grsja^b$ z<*$N=1FvS1%Dyvd;2emD{B*rw3bfK_=`SjRU+LvPl?@JKR}3ZXklMT~r|JYwhX-x* z1-|TNT%OZ5B(r!~nM)YHI7NIeG6*jb^YRAj$=K)q=CZCZIthq2fu#goQVpt|ZAfPA z0;5n8m&evfSuwZ*v-k04T8kD%3IBAIm)9uXZt{C;${v;;5%pyF#CVH{Z+tNO58I+n zGS&H%>Q^^cygtWgXo;+851S>l){cBMcJ!g7ZuPAg$G29QPAudZ9<;2jjd*$*pS`oT zhIic8=wV;j4xa8DLfi|HChRiiA*&YK-4>QYQ)YyhsIG-&fCJ^Ag8|=|+(i8G3KOz8Nq<8#!Y}1%NIIZDk3a^sEBNyIc~{*^Ur57wLt5~H(v>m2*J&USq@@FQbE9ba8-PT;@T@jnBM?;9^=I@G z6$ea<*A~u-IgzTshy|^np&QCE6WVugGPl0>W(?nMj+6i>TF#$+f{5VgX?ZNLhwMBU zWwV*HHWFh`U+Syu8N}7wt~XJ>)AHWuYsw44RuE-Tdbc&Kv=_EOpSnr84{=YvD<-a* zdcoeVtjOZ_-J$CxPHpye9(d>}Y)4pcHl5;A9iyT~;hjh%I|fNvY%}NO;Z%I1X-u4c zNZn;)lF_po%Yg=5Pi)MhrpS+nXP@j}N&Y6fT*L*m8F@QpT&6uEF)R_| zEo9l-QhH^J-dIs~n0O1IuUe&?5gSkE#u%S+W0=1h1(ZsH(i=mB6r# zlVI+!GqS>WcFX0Xh?jl{9=i;x$4bA6$=Bk|9`oE&pdqcTw~ zD*Fgv(Dx1{zY_~d+3A8jzR}OpoqaqgcIR9M{<)Bm$Uj?Y!BD4Fq$BitW5iAdK^O3; zbN7|~3hR3OO)aw_a4CE%S>CWTuZe(4{0NP~TJz~pnIzX>*L7D=HD+B`7j=I>w)ALi z3-5fS)y=-T8M@Fnj(8X%P1tYDLsliWy(cV%rpyR0QB?=a00+uJ2Lt|R;!m1s`N%TB zVF^}b*x*ao-F?3a+VC+mqyf7X&hISHE2Q(QcHe^|3bG8EwcKO|Bt>nT^X>3z=ZHF+ z){$aTISMQQVhM}ceZXH*3xs3AK4{jBB>?U7rHyfMAwL%}&59IMVvkXOU%Izg+#S4C zt@ns;AtQ=|cJFrTM~dc8RIj9dz_kY%h%wfQmvlU@w`?II)1k7(g5AD=CKa3HEKIZKi`zt`#eQgL$GRe& zeVdW`xZ#F+!QU#tdn;f;@WUlPb9kUbqbv0|abV9Av-U8SvcSYg-2m5j*qhUspjd_L z`EPb_cUVrjz?bsw7GUO)Usukx3t}g8h$bOlYqGanTs!50$<_A>pz<)bRg5SYfrA`S zz=@h()$5pjVlYsS3O#golrK7I`agGy003BjLfokhqrE8Y>roqjz!$7%iUC1SBPTLT zrzB(2hLT7SdZIV$RJRPV!kR&Men6lco$cmEPvsTD&YgpL_3nMA5Jvmd^{S9LuJLk| zLZE45@Gg14CvZ$4$aylS zJ=NeI%tM>)n5~!9Ca2bPwuK5+^35paD;lky+QL9-<$FZ1#6{Wg!>EDR^COvP>*zmy_5+t(J%?`R7qtk}Ki0|c>FGtDB;8F3Pb+2YQ4At9iW2w*DtVx!p`jbiT zCVyKM10<$V2oEGwfi~bxR478@c0F~G+_xi%ooV&D&C>|H%BISvHzC24 zJd-yVFdq;^BAz(n?Bz4)#GAxqrl{+yT-PhG6N<=vvXN1kzfiue+f!|+0M-#wecz<=3wGReWkn=8rGw^K>)L9 zq&+rqel8?!4w|ova{$3eLa*P!H~%Ehx}%^s-Ybbc<30>@_Uy|4Hqm+S%k1a|6v0|K zNdFmS@dJAl792JyC*Ey@72?J!D7xp|E{m!v=vHz1p#Sb!>AM;ZZDW!mELlxdDO`nj z*{e3MU>`Cc`UF;pQH@*;eyd`H8j;E z-|4$_ohhj+M|%4qV4qrYvTjU>HemAH;|D>96B1uOXS%WQgA$wbxj{*^3Sr_#cm9n^ zbCzq`+~&Se;3pk%(P#ZR~#g%piNUrW~zRM6o!*#1nFjg5yPHn55| z@J84uIMv^zQi+_3hH{6WZX{UVwzNpjw}R)%dr4azY*}~s%rao=W%#trjc_nOt=)Mq z883+mYxIU%u;~isq|>#yMO_7z3JzM*_P{XNwFiET-T8|6BGlopih@;Dg$y;vKA3%j_+1k?3GOK zxS%k>=EAU-Vb4+sBrEMF46sbbKSr2p_FjY9pH(y@c=1pOQYoS*Mj#|gD;0QOky28Q z9^bD1)6zwsGK}~RYcb(qq`EfBs@Vequxc{@1ln;v?HJAsnulAsw)GS)@vND#{bKVnPF+2HnEFl$vTE2tz=B=bf zwJ)Q_%ah~I!|f43vmcSm4>F+&x@S%$jbqZWt&(G#usCQ^<3)#0OKUZNBC>7b%q^`I zW6OyBrxy8F!5pSy8OuzxsJ4Y8RR_HRcD7SdlrhL1so(i*?>9@V=PGCV8j{;!;b1jj zK@No2pa^|&0i9i2ZS=RLy?7fFsc{bTWTn?5Q1!9r7j}jZ6|ucl63MDApa*rv!LDOA z`s$WV7EAyg2PIyf-i}Iha2a+K>O@_KRV28+3v1l6G6-4ch&o~0aF@=_9T7&+4?xMd z7o7?-?zJGUECanQTT#<>ypDY31y>Ue>=3xdC|hc-NTf_1~wb>CCBcu7gjuR-#eDU@S|DihDTm%^XEK^`VE_<%3%eJy+72<>VUh|rwXw~5BDaxKo3Pd_f` zE+hZQ8x@6WwhLAXKu+!P%9nK;-UD&Ya(H*xfR?UYdM#hNn7H1WdOVBNOu%GFjiVYdhDq<8C1t{|{z-EDghGvU!VW0v&6 z#3RB7LRnfoVROCE^uDCi{90hEFPb18W_^Q(=d ze_U6zpvGr*c7yfG#fVgQfW~{@@R!3fE@%SCSu=E&#cS8j{dC}trnI36N6mk(P5=M{ zHUh>?aUGB^@PS}CayHNBU8TQQ!i**iBwY?7VPWh&2q2yGpU-A`^0W5qkFKr%bbHib zlSWshrL@ic9Q77MXYr*2y0AvIW_hl5xMz8|BozrywB@?qSX&)Q}P6%0T9*05FoyT}&{cwVY_c-X3UD(-I=z?^IPH+xiZr2|FzgBkH6 zFl1H$`TU9k-w3~BnfC|@z~x*6?)p)U=g1CjkgsYR#(#*Kc$;3$xLy0zDumH?dK>qI zRqu_RL-_VxuE{&R(myvcoygxUV??Pz@B4JR+e#IL(QKL|9XWYy*Dsk%-OFD(}DMl*@AvW2P6MLO|{kI{}dWZ1jws<)&b*M3_-VUas_`F zSgnw^plzK1-5Oq@WAumB$4J;&5;og77p}N~`KjHhFYQ}_^{k(o((Pt%XcMYqHrjWG z;*k-5Rt?gFohhaW_UajY^F(ZL06(d{=PP6rcJ%RuYmT^irUMK2W617pdR+#mHCUmD zC+G${=UugCyF|l2^<@RskevVnZie&jZ~3`6&Tkv}h9gI=y9HC5bu#9en!Xf1g!j+2 zDIQYoNLtuL+}lIEl1FXt_6l8zbXa4Rrmax#{WIl=u@+|=8ld30@QqRXv^Xm#UpT(< zXx|o)&2J5#B7zFO0Jx8e2hxC3e%u9IAQ5v_LU~nSrf;58$&6GN_mZZ5e{Aq6%Q?7n z5{49-NS+_e8-#lKX7m>ibiR}Gv*``hP{zw5@$7IXP3#9E1D_0 zA=+38I+_nHDst{u58%BECXt9>&bd!2wCDx#79wZ5ZM!}b8sRw_)ma%IC!~#!2e@fIVrI$+E+52Ii7)U4ZmzxZpRFkp+1C6<6bWrj3rart;LUh?9u6 zK*}G3l2H)Qz`Y~j@08QVbNc9hokX2&OUz-b^eX@dlxl}zJiB6;#UB4DKJ2gucWN2AT5l4nU_J>&X<&4V0UiIYr1LyVT5C0j<= z#*3NYX}pDJh|`|;e7U$$OHKqumi;+)NNz&z)jqZaWRE7S98u|Sz0^`$ z-FXa~-Z8Y@SNRtm{2BRGo=J>-zNTfXyU85U6kvOUF2AL2*S>CbB`8>Dhe-P(ay;_z z=D%pT)~}1){v^L}a9+c-+^h)7)w2p_yMs66f*UA9yxNul^$T{|#{$ilOlCYR zY3OwDpJYkb4(vA8RoV_3Gj2wi1rBz8s7Xl4Z)IjcSoYx0O)GI|iH5!DTVGykmUk98 zd`Y(N2X~_ck%VLWmc_HZ2jaZJOTPratwU%1!Q{GT0Md_SP2f!TYiDdG=(=KMWFg4Ge{?t|4=Ke0PVHFCAVE!kp%;~EK}0N$V$ny zi6of`NANdWwVV4mr8_{1C}uLMZ)}S$E#T6?kNq4O`Ou~>Qe;jJ^$*?#CKTXg)Ymf- ziHO(dRLZK|>f$WaIK)h0=t(KgGEj$ttO8HR{SdE#&2}EO9L_44-OsEna_(~!p4`$} z${C$INp3NVwF4Pk{$}3dEkt>?)}|xGz!_VLKq`S^p=@yzdYUSk;p2aF#i75y!JF7! zO%!%9a!x~0(x#m5heMox;)pkMgcDuNuU`XxR)<1ISbFqyzYe_q_3fxN&zcd7OH$FK zA=G{b=|Xq?-mv6)l2fJ~VC6Tq>ST*)#On= z3a3bvvE-`JjJ0m_9334`qfHc`xT;~rD9>j{=$uHHMlM~O6s*^dp1uVF!A9EFq(QOi z1ZBI=*JIuQ%uvZv&w+BVUkLS-d9~W{cQ`lBQ^b2u?RwGBN5>|7Hio4)zk7muo=&Zg z<;><}I3L6d4Tjvsk671MF zPIoD;^uZd3sVdAodLGE#gx(Bcq{~}HuEzTBd)2_l&`DCVxjQb5T8*cUcz~Z#MTLQg ztWo=mZSg>WE^IpYCmR;Uw}k>&(92tJdku`{bD`ySO7hq&8aq8qrx9}=NBPFo?4K3~ zsnMv53josD`o+fKf@UHNwj)VbLV4?ePXuQI{3!yF(ItT^zzq2G%4y@&$nbwX|NC`b3>)8CL>X_SFHei*QzuMn?I^u7^6mVPOFtH#K zq9fD#=vs+EnAPexBTJ#N+qU3GxMgnAxk15t7ee6FRTqkA(*$I4Jueg;$WGKz1B;ev zy2D2<@-p9yS!X3215>0RBeD0hh87?i`b zfB+;$Sa}pOk1kPBe4$Dot6XJW3=R;1V9p_Zj)NFM_@tLA=Oz#@PR*%dyYkj=joD1? zaRN7|@=I_TfRy|toZ>FN_r7B}N3Z$adcOHdv#rygzY21r3=R>Y_X`^Y-tg?NSF7mm2yBec=%z z-|#ffD)K@s2QzA7b0d|qGT2XmX48bC99c4?2%d_{w9J4(7AU8#x* zef`}G5lfJujSshB-QQFheiNZsngo#@Oc1Ymc%~Hm$`gX}I{j|;T+>l+K=1K}&!j1R zsgXy?h(sZdrY~x2(N_~()!N$Z(EY|vv+Q+&K=GVGhUj5LER!L^{0MlIk~M(YO*e@_ zSj#x>=V%_2-_8cJ1#y~O+c+F$E)A_nT-MByLlz_Xt*0oxw$BJC-e)Z^&L3sz!&hgWP zZ&bm#l1puNCliOc@H0>3kZ&zie>Dkf@n-|{XHl25YIG|HP$c;}+TZMJelR9t>}|0G zU>wFgG9toLpigBRF#HP(SxP|j8s%XOo;5U#mg*w&OS3S@q-;eLvxKz~fYcWJ3P0{n z80a;8#e62nlqgj^rq|4~iyGFZxef;0Rs${&1CmO~=6l8^#_Puuf}MzyP9sQ*70SwY z2ygYT>*$&Eq;yZ25R?>!Otx=G-kv#7eFM$gZQ05~XmiZ({&$`Gl(8ta^v<>eqkCA( z;6~1-x6l6(2zpXjcvI6Y+|$;WjZ2HsVTFen_F$uBRzNU4}F>IIyl0wOaV#N z+yJ~8ax_X%^4!NAWbJU-$e_Vzjpp?9E;yJyhTk21$+{DClU+m7-T@E1_uY`UEVPBS=vM$_ol}riw;&a#t;<=Y-@^8uS=X zX?~{&W}AXT`bmRCM#dH47RuDYxl^`&anqyl;!Cjprn^0PkGR0kqh%SS#TUx_tww(c zcT9rcO%z-ZdzB==nY;$EjK*C+31!4FPNLYl2GGJC-9tF=Mj~vPpsbt zT1Di})|ncGujTv|Wm-q&OKH4JDMQ;&JH=wuG$_Bwx_BD%;rO(Lu)B_eFJF8D6RFur zEU{hW+-^=5se==*V+cqaX?OjV>ZvQkg3&Ws2T9EKoDIgC$Y_9t-GdAZq(}RFOBG2z zESQBqn*QFj;B*zj?sN256e6xpl9~AT(>s&>iiRmx&vY2|HFM_FUq2LXJG--lK>Mro znr^5R?kY1Y6VK`lBW|YBv^}ku9s;ol%2g`ALu!tH-*}$4HTL)aXAB1QnBvu|!N!rs z;A%=MGqhWuNNg@9RhG!6ToEOv$5e_^!J>0FOd1O%ljEp3iE}*E2mNg$G@K(WvSGZB z)MVJG20uNp;r8e7@bpG-C5RN*K}YIWRVB+}h2hcD;G{yM%CO}QOldtmL0GV-`88&qwjnwM_^y_+7_Pog-ZoEiQuVJ8C$dx-bTq%#7%a|u# z7!MBMwEpOhPC1)rkuI9&MFv=qreu(dZ%x@BDs~NS=7z)Z^7e=3=X^+UMR%$L1wrem z2~p|2Oco;iWpiR4Yd6pOBa;Pnl=mV4BW>WgTm@p1z0kaTojzD#JrP*bo($pDlb0UyOFz{Q;tJyhnY`S&Nl}s_6$)MEf7AmlM1K7YhST4uGw@J*s*SAx!lCmu{1z-%3uLayO zCBP3C53>(K9E;DiOS=U{4wMetki6MwU2U_K(MpPxmJNVqDh(RT3nju567NEzOc|HU zDpWOp!p%;99(Us&CfUW98N9>V`O1~&6GpeUa2UN&eskZlzWaG4>nA^b+Ql?g^HGVs zHd6dtR1`lLw-`VeH?Rb`Mta*rv#RvjGyxABc3kCs?-Qk)(Tnq;6?98e&7K+?WU-=! zd=aO8lA}=XuTh5aKHqnvByex=E~to=0d8skwH1MVgzgOh;TC=->%B*i2fsj8vS%5Z zL=c=O0~8&Ph(vx(ImbYpTTk7F>yqo?5F#@(yL$k4L#bD*=pDy0-Zfd9rLLEW6Z0p8 z;yzg*liBn0LURV@quhHfSSXl2(jGus>Eh_(Z&`Kd<8i0rQ}m>$S4?#^K#nNz5EUKp z(!dr;KMxoaiEKn)62f_*eet~jo91*G9wGhGSA21mF0WT&dWrBZhvvmi=|Ck#7&k^V z*{e+X*nHt6?@$wYcb^rmt0ag$l=*Qu&{uC2M-HC7u+Z z;utUnJ=gzLzTg->IYu(p5_ApKHR*~Qo=syg{6RE^*noVIh{C)<=U!8#Wh#KBu$$iw zm3c<5uMt}6m<|U;EOiC*#|T>i(=AC>uo*#7MgAva}D_+ zCX|{#F)C!yC#sUm$#TMpapZx@<+ib6Bya1OuthSdu%hNC+u^T{5lP@_8mzOU0@HQg zmEKJw)rQoY?7g(fC89t+P{$1+x$Q7k{N4sJKez6upbu}yxFtIT zU1bb^zCRX+!LWxpy9d#(#g&O0E*0?cK+#Z;T0dO*A{|@WY2%Lmu|GJ;n-38I29Dx_ zl`|58Zw*bs-#97U(W#UMK-&*W@fv!&4LiRLDFX}1#@W0mWDl|}tBXzAK*y_x*%al~ zYOyKqSO!n|!c5z8jV`t3IkrD`i6yItGovc(R|@QnjrSoZgsiAN7&@)karHFx4bUM; zDG_&>J{&h%b7yAbb^C=J&yzS9UzDhJT{4E>NO2!ygtp)&R!ZfF#d0qZ%Oz#tgeV(g zsBYhbbtfB~QBM&1L2EK^F!9{(obg8N09Ey3%SS^FfW7%1BC%DWk&{tTllf* zP>=rOcNT|Jx0NGLlQpk(l&@>4M%Ob#+WI*G2;goq-&R%`4zK-`afn$j%? zAOHhU3@|tVTXe3h(~G=b{c?qTB+5W3!(Vq#n;8D;Xgm%L5abWQNEs6@8zVVyNS!-h$YC4lte()4uf{4t;FcY^A; zEXIZ+bYJAu^jE|0e*IJLu z0=dU)aa+w5?2|a=F^+QfaJtddqZX&)oj?+HD32~1{5c{Fk8 zc;;sa>fi_@a9;fQ??J$;l%0TPc_P^nUBUM= zigi0PO#rDcp^UD$lv{$=yp<=xy=tM|Htw9kKmt&zjttV2jYLIjDUzpn;7E53{ECXeJ$j$!7;bfV?x9u4=STBOD80$4q9MlGZWr-|qS>_iL=|1tF?@ zhWSqZR^C;vQxJ_f^)jUf1ge2;DDnE^oJuI$D@_tg#DimJ*4|`}11ms`+8j26pzWrA zxIP29&Ymq?B!H{uAHAE;O!x75Qw&T82hIT#$gwQQm~!e7@S4?9fO|itE)S8nhCpNS zS<-r-Xe4S;D)1%yLg8+hzVy#oJmjG~cL%XT;y#i)IrpMaljw%KDYBX11$R1(@FD@t zIY;vascW0p7gx4{#F^tE^wW4bSc2YgHiL7w8b~61i)4)+I*iOzdTUgNjOEO%%7qft zdT4#H*MtgIC^ww%cJ*$yn{{>0UKXmgJn-9($5KJ_Vroe}vBq_7%WjUZX(OD(9j)_Z zPmN^$;q!G#A;62l0Mo;^KWb((0mdk;V5b3KCud4~Mlbn5Ai%)c0si#!ncSlA0?y+% zw-=(1xxH=P!$rwzw+Al8RbxwGA*BvPr-doVaV+fee3bb4+}7yjTJh9SUZAEzDey-n zM9R8fU2yMyQ4k=w6pq_1IU-+`yc0;?q#)O-`^_W6poCZig-TZp{ll- z=Vt^4sb`Y~y*;q`^dMGQliI*IMi@y1TK?0uN>Vk3Y+EDvae4>gx_Xr4rumqru-2Jh zN@|G?-ap-jDG>`pF&7j(OeK;Y`sGzeA(3yZSxiBkEaAQ(gzJ{MHp5B3lDnvC4JgoM z1bY_d{~P<12uimqsp2H*ot6_$QW2WfB2&MQ0d2@s?H#$>_fB~(sMdaxY&y6gO?TqC zEJGt?t9PtcI_8ne{xyhQ`(jsR_l3Vx*E??!*FaT6<}q1JwP}TqJPf%#)HFY4pNwVk={E}Zsoe2`1&Fw?eq@UA729ku!<+5HX8LO0 zH>}sn_ZV$fM_lp?-_pGKA8waQ>cSumY_ecyyhQSuvcP!U&i_3jjdh|$W>N17q6IDO zb-#C?{{MS0{n%orMZb07)f0?;_}OZhzBE}*LQpHiQ}?NEvF4}>1I<(h%EnS+T!Frp zT7!-so=>^>&yfUvjQrkMxxuV}mTnPhq5!#h_;7T3O$H24cS9oR>ZTgZ#)HbB_={z} zsZ4YTPyf@nH>F(JY?mBLtW;VOTw_;cb;d47geqgXD=| zEu{?GN)4Zj_Y?onMbM}H1@L@l(-}=+oh!eT)FK^xV5S{YBG%uU&Jd_aRsN#o&6epM zg0wpLyDQbrxy_iyb<7kV#ITZ2#gMBpG(M&GZV8`bfW+nBBX36|W7tCM6jL3top745Fyt|MLIjwBIR_ zRszZvD8KeOzEn5OY~|Ac2Hs?_fq?^WwWBDfXE#4Yf?D-YGmR=2vQiq?!X?U<)Y z9RhNZ!cWdoX}9xC3HTP-?I;#0PuuXw;#e1e_-F)wM<|cDf%I-DJ;}6t>ppSWr{dzl z_C^~HI@m})1d0K}ybbwvBO+I}j=@o8J&<1J>htTZF&ixxb8>sDiA5ti~NH!J4QA_`+N|)iAxn3!V`nsRkSC?I?5=(eZ9hy zWqnZLe@rm|0CFJEvq9f6MPEL87CMoE$($jY88rK>VCGEh8(LfG`8oEse5}eKx&sj& zKNCCzg>v4My4HBSQ9$AJ<#sIAZU=TquNSH`0PN%rH2CgPI8CnIJAwBu>6WiCG?KuX zJ|oA4L^~RTHSeyD143D=85Is91sp691_)}`kiehF8wy}Fn@c7 zHP-`|zc;ZtzEm{zhi~xSZYih&2JL-Uoc;)#ut8xZTMGb~NEI-RERI6VfD(vHuz-o- z9JL^XCYwt)6B7A!#K_cjJ|Gqp=gyhfxu)flp~h>Q&s0r{d{*jrez$Od>hVYI))bpH zW}O2Zk7GD0UPWeX3p_rzrQ0?SjfNLj|$3;{bY$(=~9*keJPVaUIW802-a%kg`A5 ztc!1kR1QWW4x`nUn^Aj+Aml5x1b-eI($ zRPYZqLzZZx`u{tv|2RMhIEK%OX+E6q0%91j1aUjOe!Y+SRG*KgCL~dDU9yYSfal*@ zeoMdL_z3|}y$!xoRT9WKshK7yb-j=5eBaQ`nA7CB*@F*^n*s(jm%uB2o=6O+o3y6&AsylvP#m{3>x;Zl^_?PpK zaq15J<%r!m<%6SPe5{srQp+lB7jq%59NOnGz?Z_+LnZsfuG)&!iT zx2I%=L_v05OH+61^H%-tX|Qo`li~9L!p16%Z;?ih31sa1_oiC7xf?lJ+k7ZMTt^|t zP{460wD%??Jv@^l`4{w$f$Q7hn)&8zmQZ)|)wfnFL`4MbyR%M(9xb+KGkxn;SJq?Q z`dWY{$pTc)fl|~jolI%BgPH&g=%PU&vwdGc@rj3(;MYgq6!B(!7v+{l5jgI)0H2QP zZx<>Y3Hb-|uY#X$6!Nt_LNh{b2%}@ja_e0=iwA`IUh|N@`QObQ`{BST-VJ>ll%4d8 z#oZu%wndRfN&518vCEm{{(0n<4MRv+Zr+OoC>8u(;oS*v-kZitY9~NOMP%t(I{X*% zj{(mKvHisZqg8SvX2_C{b?B)Aa0=}BQ*UnWRTxnKZMHuQ_hw>HlGX~2SW)_PF#M&Q$H}!B|APK8)ZAPdBMlJyoNu0f zt%#PhdQ#iu$->9)V=F=9F2|@E^k|%xQ+AJWY~(y;Xy7RGy|)aD8hCagaEU#5Di*k( zfja9F+mw2uZO0$drj;BxjXiJ%4@*{YJq7#ok0G$;ib$lP@1zM`bY{``&%= z8;iAbfp(~UoueyeUd^JDXuV+L4*$FJH1HaY1Y{ZyAZ(2d;tq4ByP1|3D1*TApnX9L z0^6**Ssh~Vh@?AH?VQu!N`xf}jyRB&x9go|*S2`4$|)$=ufMB39yMagLH$pfv7i`g06cl1o zM$UUJ2a1K%iza7mhb%M47f|{z6e8@JM>hbdW1}UOE`8My@b94hj{#{PVj(#_!3U)1 zCzl#W|Dx0JKvFhQ@cuL*3Zo*(Nwj3n-_n$1M%7w7G1bdU$L}vY+AFO7B6u)+=lU25 z%pt!iK*Lgo1`?@`5rW3d!1&&cBQTGl_AZYd82jY@qL z3e2NpIW*Z3<<{%xaXo~MVK65D#et{n#Re`Q5JCfTSAIFQ?<%wms8(^4AH)r{hy2I_ z6!BnP@X}C^WAUfQ0|;L!s5G!-r1wXC4TkNg%7}Vk=;e7bTT0ubtm@X?jEEZOyzjdwiomc>A2HHB8k}4ACHK2#h0U!7E9+5pW7TWFC`5$wq6GYO(Zt; zUn2u3w++r><(DR$_Mo4q!x4GC9yXFDiF;_QqTuh$?PYq2Q{>Ie{J1@R3tyhIyHSrhXyVqUE(AKHw^{{dib@CR@*9dy+MXYXYi+W*IGpMBzev>k?%1tJk&tM( z8j+AEBLPmTQ=bQ)i1+4wS826Biuf7DBG|}1e;*Q=gc~KZzIj+^t(S~g8)SJ`Ao)Z- za60{YQzH1IMPk7eqi$yqZMwG4t+`*j#F`=GPwcWn$OI5GEV~(m&R~Nk+OM#I~C#_3M&OSV!2yO->sFA4ON^D$E|h zvSU(!Zlbaqwwo% zEG~<&0--4Xz1Cy(%Qd0}f>YCmJ6?O*5p_7&G$CiQr{kk&HM$14?``rh`aK87nQaI| z!ic-QMe^Z=eNNGJ5hFYgBY06Ib0R+HK9SjV0>ND`%Ywa2y9oT( z$N+jZD!|^NTZGiX*mt0SN=YzfEvw zUB{Z1KT9VSto}a-;-TPJr%g`@-FibDNJ;|*&)W?3J=w2aK;s3!$caDoq*fq}{$?2B z)fxp*l54=5>4ip9#7|jvPc}u8Rwl3(Ar|Q%3SWC#UJWcYZ>;Z-77YNS>vZ=0*KeK6`LmxbQaST%#pO*zd!%4 zfd;-4<jL5J0LxGA^ZgyYef|b|5jDHNMdi$&P4{d7zK4rZU)Trf4P-MQv z+pa7pCg?6o?IMGd6b;3K+p3)ol^i$ZB|eeIXHyze4K@vmqZuFLY@dqwA$krPXE$a)eyo>_aSYuJY_SU3!o zo7jMBPEZ{_*Nfm2MO*7=pvPYRU~cp;B6db+WX`!=#S49gxXbjXRBbByc2pVMd z`HjNAFBu?MScm3%#5MrS_ADzkeqE!hx(h-+*2)V<#l9!s)Xd8?LiRF$OeA`%)_g^@ z1-N?T=wQ@?Hz}6^<*vFP{D_Az#EyU~m_62>HDC|!yJImmJ=)Z%@#ppwuilTUv%lf| zW5J;}lNfBCHV*+tSng(@$bL{JgPr8;nW7skHrSLUB3RuYDq(3RQL6*{EYzG{`4kurNBRszk=SUPFbBB z8*T2fTJkgj$$kcJJc%{{*0eQsV9vy258o&}C#H7VAS+4sgkJC}#b2N|4_5RgYkLIc zf#F5<@?8_1ue7MZ+Fo-DC}{!erlP+YE#9-#AP4X_tX&;EFi^r@&_5On7>_iv(TNr7 z?o1yU&)u6mJQJ51p9jH>0u4}0CH@F*KP+~URU`jB;E5U5$yFMSL@y03J<>h5X@FBv)l@bg(|69{9;e5^;~&Id0ZLsx25O-?Ml!fx`#>z)&Z+1r zLhyJNeMxz1sKmfSl6K=ddPLWqyq^bDHestd;ceV#JzVRa0G|fvVGktV)()~5|*Se*RS-GEEsq?jW>zX7zg^w(>`|XhsjPxAe!hjF?H@W1v_mVEXsuYeR+r$~kT937dJ=Ck@@&>!!=8sp@)2wazgLUM`{HHueC$XzrJp}}HPX8>4H z&y3gzk28^dQ{GA#Ug8r+VHq5T@L#TFm~gBYGsjp~dfZNvj40C_loKKCdtW68_>1{# zLHZ$PO%8K_3E|Z(q=JJ(l(PHr=p@+jwL#|Sppfs{W-e2A#EeUNvTZI0jn+Vge2TaQ zcU@SexMCB3cp>VK90f#6a`dXNv__tSFn!acl+B5HYre9%Bm4#YV*x8ZdP68u40?mV z@5?ycLI;JQsa?$kqI@iZF1DgB-YkpG;cYK$AIQrt!$wQ@AkWxiZ4K^^Z%aQ> zdRgX#Yc;f9EFpfs3V}{A$Ep*h`-dPkX4$?k@csOU@>ihlgr0h=3qjY#H-IjPGCvVSg{S217RCmfbTBBN{e_8_|%D-1blcfkSe>E3L9%j zD{bAOji!1zckJNQi%x9h_N6NAyRT3z@R#zBHL=a>G4UlbI7X#m!uMr_knY+YWNR$7 z3i=YR%e4qb%y&cf?WFB8uJQstnkT(F^KxS)WOJYtjgqR+Am~*~AhXgZbly7H?q*Zj zw>hEMSbJ9TFYmL{`PoEk@DJp#0Ht-O*elw^EH6Ldrjtu{@^wV`I25S6UsO`!K3o$S zTUpJ7^=_Sd_pwT*ZkyKe?bHeBv$8z%0i3BT|qwkh~`8-yId; z;D(EY5PwQtRmW2Z)oYMBw#5W7^^ z7BG3)BmhE5Wiu)y=aTNyU)%=7yD~!qjsfk_>8m0_e=+}9Kypx}SPkS3Y|Y*BCh1GP zM4XTWQK}|@+(Ldkj(wi2#^wxSYko@hr5K4GoNWfVNlkdnyqDUzK`W&~YJkkDxB^>i zLXac?uNHCS^;ODMTO`2l=c7p3NRQv!HqVU#|A77q5e=+?qO>xj7B)*U#W{6kHjr$f z3_U_`eo4$WKUrvS$s3CH31o@KBK;iUrJbEQ;T@BSNxhFNAzq%PkOvl@ftgxKCG`zqIx>35S@(?cah@3sB_Z#H8yFHznFh4;_J2_+rrzi ze@L2-av0xX#uAe|w{YYr>scFRGV0;7kY6$(gibFEZ5VR|mDOeJPs--pBWx$$j8CH6 zQm*ftKmC)a4)0;Nsc~h8Ny@Fw0B{r#hgI{j4+qCbAD6<6>6Xlew7Tab*~dH~$6@JWOI# zm;#W1r}JShz{nAi+=}JzSRbS*ci)5p&Q4LdnJt{&I}kIsW_;j8i{ZQAKR$>|Hd+fQ zshzMFhlF$^FD$KYhg1Oo^A61JUbts}XXoIk<(!y>+?N{oNogZ0X$sT&6lO`a(h%L! z3UvZNTc1eqEs;OJR4Cdw*b?<;a!#tg_4wX!7P7XL-H0e~Qg=eB@3+H(?+BKElDUv8 zktpN;jh%XCk>NkO0mrh`1AL-#765j?m{V7QTvyWKTJZd}WiNpeVt_^wb8bRAK3yqn z^eW;73X`k-1UM?((5b8t|7lr6tQ+wM)cJwCMee?Yv$HgYm_Ve4 zIaPfG4CYGfToBO+UIA)>qDgIO8qXy2w$AtiX#}1Yc@4BSQA4RU9bzuguX7n!) zUoFh@#++y2tknEuGjir(5+J7yy0+i)JV@BBfBvD+YE4BB_=oZz@n_(7#bFEOn>Ue; zo!61_bu8lG?{CNoT{R0ic5bvyp8TbVuS|;bg0Ru+=hL%I(+x_vnTAzYRcrvn${|uK zw^`hDlEbNIe%0Gkxq3_U0G|5U$u4p0`lMQER~Efhg20AE5AW z^|U=KCU;5p75XiN9osob56Vi?X8iv}1M~vl^~2UgML`5No}yT8)bvyr&Kjr(vdMwz zsxauA9BP5MnuvJxGHrj+tVe6GObye7pUpw5=9c))j$=@)JT}Ihf%%X%Yh;5AtD^qf znza76nZLQfuL&CFG`)YPD*^U-su`==|ja6Pmg3B)%R%xEkC_sH=r|tzrK-; zsCtMEu~}5<_4Ev~zX(F?yh#=a5orQ(C`mH%!KYpj9k72th5ae48Q`Ci!px7EfDgj* zuc&~1!fuj%st==_S`ThlZ_IK(PzBu9U$NxTgE@l>T@C2hxCY0$B3UJ#ySQ}$sP}ZR z@MT!XghATC-M?&S^mwh#R~y@CAMM-!uM{LAJV#yXgx_3k~=e465-ZH1U*L zcoA@>fQK7cOm)0gquveV;Z3(u;rsQMHzs?m$i=~Y!9rQyqQn&ti^FEZF&A|wnfi?( z%2=X+H?>G61_q$=fzmkd9Sp%qLou!!1u9ax*>x_9@xO;-0A4w9z5Hg?lKOTxz=9UdIrJd9!iqUkb3re+g_2E3x}VrEL7^ezK9ufX7K*cYSJNoHWq2)C?(BT&vKUu?3aRu&Pp2g2OQU) z<<38uN}ffxUOE2U724|jt%!fokh$J@bK7HdqKQF;DP5;MTDqjSsiD6L&?dBgHE zKEZ*U{0oHe<1Eu1SAoFJx<55ncO);9DAVqa=v6#D&0fgR?5)`F*-%|`N!5~Bbh$#L z!|8@Qt77*<^xp5A&dz3AB`3G z$s$o-`SV7WC1&rUY%2*v!RNN#v~R^fkLT5Ta)>!%_viD!P(Xz15!c|-=!))Q#U3yr zZ(BLVezmC**5C^=NXcaz~;~3`z2a}zOB4tFZ$)H#-fRBA@ z1qwRXF+?_ZXZ{ns`O6hG6t&f=8#H`ZdhzguorOE^|0f5CN8>_C{7sA8{CElL2i=4^ zOh-Q&C8g+$2~XaJ>x%xW#89ghQTfR-#zwh%g{R85r%0;#@h2CLza8byUD%YOTS>)+ zng3HLJ3TmWx->h$m=e^5qQec!(lSOzYWY7tsIUA-{AnaWTt`spJy9NLRz6foer6Uz z;9j*I`+Ag(E`TiROYywLutHCpFi(0jPZBGh9{27UVAMY(mxYnV(B5?ZwY zW^>a|wqK311qRiRKJS}%BG_#14Kp&!Uw`s^j7t*mcvjb(w#FxTVp*WyyZ%|enWrpASQz$&p8i2wORiE$r6o9y=wst<`||i zdjsae<#aQr=|a7BYeChwaWDv0WYYJ(cBW3Rz)Jkjs6|3N;b(GM8tO`u$?u*mYF2f% zJqf+V{S)(RbZ|aN*Xh`c4a!$0qTh7K8XDUM6v<^? z#Si40Ci@BtGuOrX2nI(OlXO5QW(C5)PLl4U5(;M0w z{FuL7wzc6QqR-h)NMc9~J!^o>4n)0dB{@Yv*i=Kl`QNVo`J@rl3?42%js5W6CGQ(< zYe!ga!_raMo>S+PrU;){(6+3S27+><=W%H|n}shc%u+&fZ2>}&I*f&BsK{GVFNB1Z zsVhnceJeY!!hpTDyf>m5gR`}r+DC%xoUyL8SHSLy;XySa)p5t9LUo-SD{BYL4H_M} zB(W-ST$Aq8)ovokc#AW=%otvWG#y%&_*NGKa5k=_`jJA;r|{!n-eLs*vf0$WjB({p zO4Yig5{;=#KnAIyB_Wk+9FoCVRzc;F^q?S>RbJhO=Z|%1(HHK|Oq>uLYlA(_<3p^rU;c6pm2&KzvOq%(wabFotoPod;LkD{Xczl5?_-1G1|3M7b0ze zBa(^aDZ$ZwL}z^m-+d!WMU5ehi1_F#_t=8qua{F<-i*L!|GtqaCl{af?N`~xh&bqu zw)L0=YUlm?53q1dXQrGBn?tuBav<_^`??)OT|X#AXs`ix@Q`??|K%)j+s$D%%F(3R z5Tzk_uzKnydN)KY$d6J+hqO4wv{%K6UmC)fByUz6Qz>b{3G}852$k&P-?X|dQxQ|5 zV-Rl(NH~ej^4Tu>=vyX6bTzP7Pd=qwGQyDfV$3&J-RZ?@)pFQo)nWyEvi#d>SaZI9 zYNAd(NlAr6bYZj+90y>@7ox|zb2GCjUBhwCT<|$hY+7nri@CMlx*PxUl@_Gl5mnc( zB_eVCeeG#a_GB}aoNgY@$%l1Jwmt0_;^~eOeY^nP3gy==ztVyL|C5w#=mp1 z?%K*p2&JEFTXjR}p`Yd4Utd`*c1b+`VV#nA_fyiWVJI$?#Q(66ZA)DrbhxA$D8eoq zzT>FQr12G)6NHHIaxbFO=!pEA0Geg(W3u+5Ov3Fu4({8} zUjZW0E8EA7{5DX9`BNTfBAd-`KMxd|g{g=J9^$dozd@*Y0+rMKJ0?XMU`>=u)_p!= z8u!d&=f^#;o-qZZ1Ohwd|FxcM~W&hM67TgC_p>Cfu(8f&u3U^M^NP>^m#Oo$y|BJtJ^(6*HPz|4_u^Q~O?1;W0m(xN778lRrzV28IcT2X9VH+PjGK_uSySa|vhR*{%lg4n>JLV%8(ehw+@ zAi>y_CdD3@foKtah%G_b(ujI!s~3&1*yh)i=e9J~8 zk&-t?%GT1X9N<5$fxW{Qev|w_;mZZ6*u0t;)VWG2>%ZD0XW@)w4H2`PhqkvP+GmVr z4Zr}%UIX3PD`|o-QPhVc3HaCL$8<-TGjBtG3R4VMfTie>p}v<~>&`fWUA!`wl+(=9 z9pRGAVH%xcxA#h1dBl7Jyus4b!;mzB&i0>vg+_UhiR)z`pOM&TjCU5bMOPJ;Q#Qd~ z7JSK;u|Igau|QfvjaCgB7MGdoFQ(ugaslG}S7R zH^!6pvh8LNwIYeD6@Q=aO0|-5c;o3Dvnk8-Xn&TM(SYODL()eHcOvm*+hTg3n-N-- z&Ao(E+5lq6712dwY8fyjkri*+3bV4;Rs|pf!ePZOC-}e70wM@jTfe!gE-46tRh(xI zRkqBK>;+mjM90KsxiX(L0RVzQ!IgVTA~7gZz9!}u;OPS&3#cOeF2oTh*~KwYY>FM8 zzC6(kt*v1YZ{j;qd;)J62^bC{zaxd#kB@A?5OX{%`MstGgK?OaRjR`rb3XciJpf?0 z_|{I&$~JsJ{1q&uFiykWsL_2l0s(qy8Xj@IOix4MUaDR6#KC|8i92$x>9KS%zj^S$fbSC^ zylVxs`~)lf%hOL4WEQ>{3mD*%yRQ6f$W{C6&+!)ko2OS?XJH7>bRIPVx7Py|BIekR zc=a+#i?~P?-)b*VW(kHTC#hy>ekM^sO)?-4u=yar93mI0T2CM^26AGr8;I4&0`Uxq zoh>o(AoS%Yn}MY|?9OIyc_VC@1L0rZ75M}h8%f1DJdwO}jB|3<2E~1S-I=+ignbOa|4woMue!d6cP#ev`asMHuiCLp~n4xNDKD1YGf%x2g&*}V}ep}<_2=I z0JfB#G8q=5Jg(7wh*3oLtkR)rIeI7F7r&Di2E6aT10}bykidx+!%a;+W$#dpZE4$n z2mDuCgBSw4O+Vspr+5fkpn1lHc;}C4Up@sOS0#mKI{c}Fe@+DjW~s{@u`;ygq-hQJ zQLnQ|Z^{CYGaV9?Q2Gn%Q){57)3Pp^b_>vi5p?h;8%lw5#69@;@D(i}xbsmf@&}aF zy}C2^|NCTxYPhrp!k2}GW%6;NP#s=0z%eMncLgBPAn`>X?Sq$c--r^((Uj&5&@-Xp zOAVL(AOiw>)iJck*liHoJT9)-1}s_p5Jv)E$D3wpuza}=ufV+ZB43I+Q~f2z0*nEY zM?;UbZ55duK|su}<)3RlmWRj)m~1b5@p9iZE+_rk0Q8a~(@>9Igo9f#2~0NhuE^8R z=Tw*-BE{xN(1l zmjG5OaOBP3CY*%IY%o1c4JYdlTg^#i)L*tr3Il*kJ&52lg$=T7Y1*`0_%V$E-5WUpB202+w17Aa^T}`7a9{i0P;}3YQ$uJ z&h%EOf>8lG{hvJBR6e3LX6$OLgDof{Gr|v|UW*d8q6P1Ax8T9As9NzR^?mkbifHNN zTy7ArlSZNWygx%Z(c*tLccVgZcO%}UW-#(Ns--l%-K~i= zWDG&`d3!=R(c*hrdQl-HE*D=P4?HcoblU0_9|M#DaBeY4FJBrn_UA9gfBxB%k53!z zCt%#Hd-+NUEL!1ws#d4iEg1@XI^;4YGHFj+2}jPOdAG-&oGyMoVTm{0Ky*daRA zn&p^?)rrc~XTbN;XkrHTFo}fq!LQkc=$P;awDe}&Q|jXQ*!uUrKy`IsY~E|r7llAJ zOMI<;yrkTiCZVTyDmU?P2TivQ08%&;L0Og^cFi%Lw+=`LYdT0tblhA~gIi2BsC0eJ zv7N>hc0m78ZR=_IR1TN4&xHR_D6h1F2Sxpi6+%Ak%X!uC$Fa$qw{$K_KAo;^$t8mG zJQNsLtcazDimuY+N3o!Bf967O_lREWgGh;3u+s&;YZIIWRE7T=q`dj0*_oE!r~7*} zVaB^Q!`zyZY8mb2dUQIHz9?$ha}u7qeCsc@9(4`d_11%j`M$OF;ib(D?Js9(AEy+u z$ANTrF?sv$F(2~EXTd&Z<=P_GIS~U2vvl0rQI&c8n*>&1&pIHph;Q1s;u+SV@NlkiR+9|Km^TGjm z@z+wgrjHJR`fHK^w$5+guO0E}mVjM!=w*3flak!)G~gih^I;?e&f|*ARC%a@ zQ|83N<5E7=(ERKyhz@M>zabkm~W?O5r?JnY9^ay6CL> z7o1;Fh>25Y{1Y;^Qo^t%KeLc-BI-TEm)FONd$yagJ1t_jYZ={vQ2@fOC>a)v2_Wb- z(q+l<8ksk_WVab}k+cqGDH;(rsn<{&O*QK((dNbQ8ndsR{V9~DmW*(mdTPG~b*hkN zE>Ee=c^5jWUOw|w<8;cU$_VywVxC*X0tj7o?D-;Fy|38t!qFp0Mk^T#o*&du{rQjDvj7~A5n1(UXSH1*{|spdCO;iM*0UL1Ui zb=O7em3ESyl|3Vzj`F%#fD{`3F%f1ot=~4WQx#&w7X7NM9 z;^EjZ3eN9CjM{JUXyK{%?zUTA!;+q^O?2%((BPqW#MvEBt>8Q^?6h*)yArejwH$!-b|niB;T4vpR{;N`9STvaq*7PZx3`HuTWgl;Q)qP$i zyI#Bpgk<2(qO`wn2>QijinMVVKzn9UtX7~hnMsZxC=NE=OX1y5qvI<+-}twi!~9M} zy8GmV0zwNrOR0&Ou?ee_j>fJD(2;&VMk{d4axT%*H=j7Q3g8Z?`}&R94%XZ>tXPbF zB=ee2o6;YV4#wnLCT@I+&D^AjL@?Uayq6Kd%8U`h>7oDTWy0w%O__pReB~-3`dJN) z>@f53#e4u2G93h+!ywy}4$924tlhUZv|5e?Z1WK?j(VbpkQ6X|c?M>_<-7XW7}Goi z*6cn42)!z|dhH(*Mt2G}=Mb(7qnSc>J%Uq%za%KHIFzOInz~uNJOFo0Nj+2RSyw2k zV$OFpl&|0yFm!#DEyk`gyMP$#q9)&C33m)tL4t^JF4Y8m|D1gqBS1Ydlyt_ZkY@-# zi_OW;sHGj(Of)jA;PBgMb}7+AfoEYtf3%wY-qJ>$qz=sR@YZvFLsa^njx&~uPi*_X205ac`K zoDxOe7w5xavBiMkWP$>|a#%68^O@`oPiIq+)DX9HW$y&n*Lmka zQ(ztyC{O^edoZ2!{Kap)HsT~*tW4R@;H;gNjxlp?%S};yE)DH#BX+DSPb*o)u{~AE zosSANi#MwE3^nZ0MG949LxSu@Y4qXx8KY;^*J6Ts!>v-F^ zIt)E3X^qZYf&l>wOf5YimuRP>e6Vu?Ig*{wgydRXB}vB z)hi?&y)h%~RVHh@d^|dj!d%iGT_nt4(%#@zwRc@ZK)IE$qo#?hVaY_1S3#O(Ia@bj zgDher+g*^GxT*stUe+RVf1^U8PY)3@GsheXG^IsNF+Qe^Ag?~2$V87`<*Y|L*HJdr zGJ$QwupEAsxtPoR5$yLMnJh>Wt?|Z6`RVikTYf}d9(M&;37>~{6yu$`j``rC)0Y@g z8Iz}>qu6HUxud4YQ)mEy-IE7)v<^4sO~5U#l4y7RYFG^n`>e+6(S-X|aFyJQa&PdS zv%~3`>`GnW9ZP(|kJpY}fl({_6+vv4&{{|Ejzqw*& zn+RjMV<3E0nYc)8D(cTZPKt|B?8Drg`#Z+vb~1HZVT!OjZT_W=Pf7a7y%eo(R9oN4 z-tsI4fL}H9i5LuTNb~_KBC^An)wZwGhHWIxDK=v7rCTWTT?n1bHO;1*4Usmf8Ys!l z(4P_Yr>zuWpER3CF8Qmpv5j80ubF<%6vi7^r#<@+%$cJ5(AUDwKcN(p#QLTIj(dHj z6_RrKXYS8V#XcH65>sVlWO@4$t6;hgga^fR(kF96@q5Py)D_}?R{4`K+NCGQe5^IA z1cIU-KVy8(8POu!PJWZ70XeO40Ig0j;z6o#EDL~zJjqt|*}bfhM(=BwH+aXcTCURC zV1v%ZCCoN~xlUYqU(2jS-q-w2OpAzdA8LJ+R(LrHGIwMNV$Z(ISc6)uI5#UG#*luy z>~qYa^$U^;%qG2@Ov0yViWyGur4E|{$O3ffBIb^tSzP*x3UBr0*J!$~%AHsfZ4X4pu8a8{6zHgK>*uB{1_ZY@yLPEa#mG`oir85#K zq)PdwB)|?2N{)*kZJwpc>DY@;&3!0FM?CUdPgTjOq^vV{hKx+Ka!w;=s3OHyU@ z6Z~5&&~fJXVa9;ne>ofc?S*=|v-3_Q81d16WT{@S-YeKb;X01fWe9h`2jPMgl`Ps> zl?lDkpMY33ZdPQ2trh=(hjqxYa?B>2H{|a?h|lYqqyz8;p?-0KjDTkkf~D>}q!L8V zMgL~SPEIkFN5?*PeH|AVhy0XaJEIW=+Jx&|K&W!b<0P9hu7g^UzPk~?tY~)v?40Uq zWU^TF`G^{_l-WN5p<o4BgwGpfZ=(&hi;-e2o z3io>!{DH#(RsP-A?>b?5P04&;-78@1_74`rqA!)XiD{3_Sk6yy)Lll{GgJs!w8)(6 zLTfz%n^eOL#|VYhD442$a2N^dB{enUq~Th*9(K8w4MATy{A}o#Mi(27yIqc>YA)lP z{MMGPg8^j1$b=p;TTA0N8(o5W{5y2A;fm0baYNyKPO$A@Gc>~k>V;LHk_KP|5A`S^ z=8z<0=v)b+Ae;1Wo1I6FzDM+0KC!jb=(tTq>XRM_rQ9KH<9ql(aLy|WaXy+P#;jqJ z-AJAhu>N2a&UMDn--A=NB`^0k2b77ql-*3qvloU0rJ`E>w!&wrn*H~ol;bj8?|nE& z2Q)IT-BSqSa#Fr7iAsed=--qe6(20q=3*;~?z25H0oZB#`+4JwUW#Rn^2P@v`jFrV zY6iEyWdiX+Q^Gb=H|hq5;~u9!GF(8x<{``&x_ihXd)`M5jp(ZAjHT|zgGG%vJm>xG zkn9pSEVN_^zgrcyJni&{n#f&JKF|j)UmBrq!DU|AJ~AL3ctKQ6H_u!vn^?3C;n)~7 zg&wsD6ycd1@KTFmp~p2bvpdHekkjUR(MxEQtO{^<_vUY07C5wJ79z$#SRo#@UHXs9 zU>tED4KUZk=(jB+vJ2$!6)YuXy7jmyZ9vW7$9+cYq8iH!{@45laLHMS-A;EzO;N$FA8bf%nm=q;>efI zv|9$`Si$=#RYX9rE}>zTWaqO1Gcnor*T;V{#f70Uq{i(A^1z-I)Q?j!Pm}MVZIg8q zYe?*_IX)#xhVnz(0GT>7*j{xk4&VaNO;J7dEVg!FHARqiNu&WjnknqDP6*xmj6ff? z+ljs&*;qOnCEyBl+O?ici0ZsTvrhVD;a&vPEg?_sjfbz>l^!IsrB`vY2er9(ymeb} zl+!uUbuHDT$z^y6GaGR+X*AAxO0?vtk>RudM!2=>$|gh7v_yBAAe~fWjl`a>V-^mD z+^bsIt6aZWQ>9mC3aopN>owZF7rQV$ootKtKb%$NqUDEKo87mkZoTM9gL5Ge(US@&%4^BQ{3@=~!|2abUM%uL-FIbWAt_ey$AGPSMJHh}n%bC~;EbE`<91!!K;f z23QE(w^{VKC0euyHwnA%b6=JGoQn*`$0yP~V+;VwOL(n&M03zTOwD%BmJ=fqcTwZ5V>73_lMtTN)midSwa8B0frW3CS~a6p3C1lYeV+kbkeLMLizN2^ z%AvsTf=EUwOJsM&e$e~ml54mxB(?qDx{HV9Sc6K%URzpv z0nC}Ht=VNL=tSs*9bkDl^k|uH>y2pWE8f?np4P;RwTlP13J~P7YchU$Q>JvS{gs%) zVnGK%A^l5p>m*?Un11J1*-ksNjGw>?sX65B?L$kMg&9G~8Ad3vnKw`f_>8*nrVj9n zK$Y;blB7@lxHx|5&CX%qWce~$N30W^(!kUe!bWr9SpC645q=i>-0B|%O)7nV_HoPi zIG~V#d!Dk=U`O{0(m{E=#7p{6&8dcmo+?cnv-mrAf))N8pzb5U6CEuQDSpmj-ry!~ zc;j~p8pgJlAS}GGzb7ieoHsM!GeuE7CRyeg*@*!^C(viz=v>4g2LfmhLp}g`XY2!R zEZ)Fb-ev;qO?k(c1#5b08Wkf&tH*&fL9XmWf^ldtMwi(ilxjdm)}{;vt_-m8@>YY? zReifB>!8FzGFrM;Vi=$STDp#l=o6&^Ms8uc6oqz%+@0lz+P2d`U~-9UYZkc@4W_k@oCLdz0I7N>pvu=Te3kBQ+7`WjiaOHVx%(J;p4jP7)#sXn{XNwoh5jL{(fng9bg108@w;#tu0HBfNQLE=e3N!A+F-fN#h9Y zm*^5;mdDtCM>6VoG;hqNWc?)IP&;X^RnXBhVekj6HRAGY0p27#X>7qpU6YnziB$ELWX@Tn#tUD%D)LyAQEy~*_v5;=bAMul!iauB-}Sb9o(^y2Pd5VyT*9S`_Q%ss4-F549IO2_fa{JA;|{_ zundd^DvPqbQO}6aiLK27-t(^h1wod!BR$j zdKv)rQgLcXcm}w0sVG1Q}KeObSWf{BunTO4)s42JgV+DSa|}}UEvL# zLLXyZFEY}?2AGfNtZGkQe!CtCbsyV&pRRSqI=-#9pURDrvj?TtZ__mKov>$bX!$y7lHTsx#B(-4_ES^)7nszukqc^W zQ$ssUW&W7E&n+eC1V}zl9N#6d7igZ^NXha{AjI_|mz%>dE#TSEy)jXnxEZ@q$#iiO zOlX00W$*mLe6tM(S+B>46~yPWrZwmw_h^`Sy`dNmfy+9}`cF8@X3Y!-Y^koiG?Lz} zuX2IOM`Hzgh%(6(Xgx*vHP;!^b*swdkf@JKhJde}pLsk-FpgrCvV`gjzp4&3 z^O-`;D>MK*FFdwE*Jk*(7wB=_KCe=R4$OcmZOSSEZYrrk=4vtP_ZLXq7@1ym0(vmg zngFtf(E;<^m^KoIjPmY4=VC`&QT!TxEio--fBgdN6CQnw5b|n*w%f#=X?xvzb8(@# z@L3jXE~>_Sjg?g=(oPDTMm8zw2glgq5iW7HhG7Y3q^JE zIrtW@w8;^gXDwJ@u?1A-QbI1_VNnwD$|tgdN7YpZ7yPnG`kAE1K7HAmi58KCP0q3C zrGxi5JQ!BHXGOMh?&deb7qr=nA#GP*m* z`BljB)mFM&v>m-cSH9~{e{ZS>y>>|k7SMnvAm6UU<>VN&8!`LmNh(%rn4AI2=GPG0A0d1}%&Xb1m}KLQJ3u*8FdYv2Zj%hEe< z9i86q=FG*kXJqfR(fKS}*KM@=B~54EVzvvd4sKPnpX>9+Znz-5xaxAr)jlx9CUCZu zX@N{Biw|myL~b|v+Yz2P3VPs1HTs%!YY8gz>l3kiQ@3a_^u_E8$Pfh|65H@LVCLFh zycBlFA*x0ETBg3}ypHWQpg$St(3GHi%ZUKTk&z?#0F8t!8;H|~B+=gVx_+yM(Z?%K z(l4Dt%sIGfH$uLM&&SyPLR2V`<@3T=2FLWu$Ym=qXdn$P3A64KE|4O$@E9>zNg1Wp zB<5N+CGKM{T=TACpd=K%!S0*mG;c>2W`Ij*9a(GGHUglucReuhL&LqGaN4hFO!LC< z6rlF0fXd)A8>Jge)dL$7s=XUwNJ;VaCB|u)y7GK(8H`>^Y|6ePaCcfiRMt*+#AV_7vczBj?!=ZS zI=XiTA#fLJGcZY8-P#(xox5t(kNtO=YH4(I6ql%6BzE4BJfJzlpnq#xPV{7)@m%D{ z?BC^sVHFE*w(hjXbX9K~<=Du&HfB@egozoDp zOfvBYyR3fQVw({6#RM%?1huGlsJfjXmlIc!6+Q+u1zZ^@_DCX@ z&6Xq&MXvCvQx{E>+;L-LLq`D-xS|v{gPDE*1-*UHTZs?~-+Knx ztr{{j*SNzbZg|lw6GKnYfr$Otv1kWIO>}+fZQIo@NF?Fu{ixy+3ZvHq3Jbg9fU!fmt` z{h{OXfcmNGvyavSA|);jg-4qcgQ*rw79g3)^A zigaz0mQ}Akjt75ZnGsGz%YU+M@U8rMY^2*9)TXrkb$)9S$sF$1Sqn5q@lD!*$l&7R zNZY2AfR)Vy=&cK6k|Kx|fEXw+lw<3XJmA>w6yJfcUp=*~^_)U7n>45O`0k4FE<@ z#Rx8{BSLg`^_2eq9}Be>zrVM#^jH>ZlgILMWBf)CA2fMFUZguE&!T&DB& ze;j>$^w%d6Z97u*`@_(@RiRv-j(> z$auTe#+bREL&3id0HP_qbDjFX78U)(+VIy_p@oD6s}hJh-guL;Vd#Dw)zn@!WyRdg zG09YoYWw(_{76oQ9dPawcTN2mf+=65lyhC{+@rfAVYP>%hu4-`kL8kGk7e(Y;gm|&hMs=Ybj-JsWkgso@~6vp9CdJ>%r0izW%k-t4l zW*JAoi0x60ebOY?y{(;pu^;j5bSq|eDS()lrDdhMBiNANU`bEm#U?T)8K* zplaCMGi)ojD{LEo-Z)6yJugG6Li@nRpsZJmz$9K7c| z)wJB5ENHXmQXW)L9gU>~7Wg(2HHX6309_vJC6f3_&h5f3qj{uOl)RNp=3R2LhlCL3 z`%nTP%SHI})3{K$IFW#yR5R!;7s8K(sI$dFCLq)amCbSOa`&6EpNG5V$%SI1k`*t> zwZE%vu7-a|9_ap*d;zs+=ZhzZsWKP`aj7&FzAq3i0LUZKIn7itDDZW}4qDtJ9}>E= z5h31f2W;hJ8kDF@f)^q$W#d({rv>;S7-npy&B(DY`RA9B8cV9SS&J&uXv)vzbsoc$ z2Vw0atdVTyl%%(jV$}yr9f&v#fmC4^@W1k-K&``WHj@5m&gfs33?Kr$s`c{&T+hy0 zfDNm(8X>j>`)XV++IO^G1>WrX%|;6z$1CU;x)_*zXkL(~I&F(y@~MGG!<`FT5SNtW z`p@;n#-&CkhYeV2aF-LythCE`&kB!yCy6~Y3316eox$V(4|VSprQ6nQ3#M(`wr$(C zZQHhO+qse}ZJR4?+q!F?cB|Dn|E~K|FV*UCw)s8Gh|yz=9`TKc?$V{Xv2;SOUPL&C z(Qa1?A<4Bj8R^tVjuh?EqFemOi5t2cNLH}+S9@PW3keH$2Q9paklw(aGYajK%Uz?Z z-a`v!Sf48mPIqAF<0L3iT$twXG^5aln(bS=N%DPZ>aJ?)Tlj%?gM#dJ`#nzq-meBr z^U4)sa8sW5`#Os3G8~e9pex0Ixe+)B#Id>h&RL4PgTIp7M=Uf!m5Ls?1vdrG%h<5D z$9nYAzv$cDuql~bx99T}kg6dkR`2fa&GQ_GCyubxF~#<=^ByYW#`K_jV@c;PR>Ge; zOR)fU4Ia0Ac=e=&fScf-&O45ZCN%qPK!kKAotNNP9V*t>uM@yVsweK6-1bE_g({K0k!Mcxr85vBiVL7eu;t%%(dgn|zZfV23dX$Ko z>~?Zt#73UtDZ|0O;eWX1!ToLKlW4`9-hq=P2`mx?=p8i3Ikm_Y=JBWn-`hJ-HijK+ zC8)GcRl9yJbYhO)Wy5aL*pK6dYsRPm zIYQ3{Kt(iB*@#?+?$-y{(q;dfY}+$-Cxa1p^*hd#vCwKH4)0hnp8%JWc{VmsG#8-A z93eCqz;x=!`Ei*E#ANNCPsBYjh;qZ|+mqt{e5$`Se#t2(y)15nU2Qy*Y2J-IW?@yG z;a|lG_GGiuF)GEjYIkn&;KlT>X5VF}iFs_hF%^0>UZASCQc?5EFf5;*oplPLe~AxH zDtcIR&6)$_?5Ef9kAt%Guh#UeRo9D>&X3HzKJwU%wiV6(2slw4&t5uAHtg*JSPh=%5cZgcVLJFAEVCsLOVW{jYos+=JQ z{uONZGmo=^WHYuucl#yh(bKtIOjRj?bI`=I9^laE!lM_ef!uYH~ofsL-q14Q6RW%XH zmvaKqJg*TeQ(Vila7dZ{5F$pXRqCFkQ%~sb5s{<&tPRhZg<(=DayME2mIwfEJV#?p zV69Y(goD(g;WzG9k}|p*9f=}cI`I2BDY4AI$`oNqFn`>`L>b+3aJ0(4=0FW|YQmcQ=g{aZzPHbAEql$LDeJC3=Vi2s?8D~*@j1l|FraV%=2-1r9h^{RkS9dU zY4Z8AoqNw*h#znl^XWO^bsc<+B}5!Cn}YtmIcskAwc_N+@6FeA6`xwnD?0oa&oQ=K z4T}&L#VVTA1kd6Kx$t81{gK?hR}1m)4K-&m?6eubYGaUjCreUMQq_bnfz6>5PY1-) zBcB&#&7VE~vSIz9EBw(cO~<)Jy}r;tf(#bH%jFrebCCp(C}+d2&&wA^X_qu^hJ zf^ly!@VqnOUt3O?g42g})c}1@0kPB|5`&|T@NiTQI8Okj3gQR~YvMk44(&jd=_|ZaLbXxu8@5gl=!qeKQ9}(2*i38302njTmPJHhvQ=UW}M5! zNhR}#9kdit$QSs<2&X@Pq8rU+5J!b!?W&_PnYBO^a$T82Pv~I3Yw3I71pp~6AN_H0 z-}&CSMoo}coJZ1!t$3ojBF-Rpt1VQ5VE+m<%5yR#Qm*jz-dSeWS&S?H3h&aluOVxir$fh7@$rx?r(tk+XR)Dr0@t z;af5oI3t&=90x0yG^@5)%J6<_4+@|S)3W^y*>6+}MT^ph)6W>@*AwE{25BF|`=AZ= z@^!1VwCN0-o@DMqzbY#N+>F; z^+vTAM0-87iEMBPXl!8tg}^!c7GD2vt_mN4y`B zep&Df#^0UVW?v4WuDQD}J!C?Rz7TwhZ2(ZUB(BREng=Pwnyhhl*c?bUhQpZWxJ-Mi zrTf*WlK>EcvO6_*^2?pw>HX3{Q&Lu|{@Jq-bS8>x1YE6Onmi?|xQL~su5N*@Ci0*% zpg#wtIDUNIsMKn?%cu0?>!*2v?^M;5L3Sl}uDi7DRD^9&XKZ*edMey=BQOu^vb+Up zjbiQAHOusK;K*7>{3>pBbL~gHN=2c`x*5R!Oa-~gc6-vgaMf=*Eg`SU6qFIlo|&%G ze{XRsT5f9%^Ev>?LClp%L-5iWa(vE-VSlI+`a5bk zut2KV=)>g-w0uUh3RfNk6aN%QGh1D|S##i)-%W7-9jo8zqdKgWw>YM77%UPcrl5ux zd?psf+f2>wPn&4uMMaqz%0S9otq{I@ZC+(Erldd3C@$!y39ey}Z&^`AeiAEe97Ad#O5Wf!$v_m~X=j7l?76$PENO)v}bu zQEO@&sI6tQ-z0RKSYXl(<1RFx0$RE%k-v*`bch{Mz%YN-!x^riMfj9fBZ;a*$e!uE z%kh4Y6lxBwRWm<(F%#eiE4z9kpD++0aM5Exl=q_O8N(*;cS2;mMSz(TXbH0Oi-%bZ&C`FBp8zm-@!1~4$7hlq#=>+it>c?}=d$&0b7Rz_{k|pZIu!LAuj1tD zZeL)NZ0wNTJgf1$hG9&eqZ+6EKGV?_Ghp4iw!9Cni_N6n-<3dg9#McdirCw?#$-vb z-xm*f=bAwEuyB+Foq(scXvEtjsFm5Aw&u%&xb_h-$_91W!=Cob|q1L+(M04{D}YMuI%=8h?qK|-Ize1c-VuV(dZslV1o3^6yPU)0HdHXVCjF@*DB*$Xt;&HR_W(L5}8AZ&M z)V|Gw_krbEOg!ag_4pIF))xqm7eyETIsVKNQE`Y*M+P-lR>VjNQpT+IC4*L5(OkIjXV1K0B&HK#xrEgei>QNP(iJD9k)|q(o+_q63?6 zsHRBl0L>4}0qeUrwtFb#T{VwKr=T&@d4x3bXvfD@=kObQzva^f-KR`kFK$XeP1rT? zMo~l1jb&*Bbb7=#WTE%a!E8RrriW*Cz4))#2sq+OJ4ZmPW~n+LSS{J*4Pq}(NG464 z$t$FZDw?phn?`XhQTaUoa{B!NBU%=I5>049X1uJ*K$_@?6mmyD$ z4&1k8+h#^0&QBO%#`3;>O7hblL(KJ#XA%~Iq2qj5#oJmeP(ZgwC_42^9MNX{HheG? z*6sw#p(oI8n|yu{fUHo`Sar0ulMIFq^75{qUwV6yQJL&c!R)>?j(xrsvv><~~mXkA4rE94f*QV}cFATwC zP~eKx8c7JIjVNVO#>{pIP5}RpNmdrxR85C~rwSssbCKTGb3u{#m0D_y`+>|enxE6I zqE}uj<&_wy4eT|vp6vytiN~S2FhmMo2_YG9SS-ZuVKONqn2pY|bfo2~aCpKmIbJZ7 z_xGO!|Ebs?oZ*$l-oM@4<_h_kQAb^jZ09wDv zKHA@}K9}2*XHql3f{g>^Ay$NCGqMECBd4v53xtFE$tn6IbJ*65i+%jZMpc1Kot7*B zh^cg@{CFUY*x4uOyAeoBt$)zvGMP`Nv`3^>C5`9_I8cXN$F|v~K>=hn3h271u@k_&H?4T&*5cLG{ePlJyz@dRFF;$j%5sP!{92E1& zMU$fm_CQnfyUY!P;$TEv;028rvzm0F2ntc@+3%3S9$Rnq^}y-rXn3@&9glWy1}H$d zilLpAX!^=on~l=Ky(j!nXCPx;E-;M;?<$+lK@+Nm0j}C;TV%u625=Ux5Z4nb!8kVh z&+95e2+@VBoB*B*Po)260Rn(%eiY_9J_f#OF`Vo?y@AJ`Er-+$*HF-h#CXJ~NnC`l z@fD68B?GDwt22~Fq1<53x|orWZl@ND^;3?0hQdp~@iy~WYTD;XrWNW)hqA-O%coF} zA3E+N;%OpgXM>qw9m~5b29b7fgmY(O;$IG$;b~jF!>OYT1N4C5}?U zdQR^pc`5l>N>~M)8Y5&5@@a-qFDR+dC2{0u0Th6wuBb5#mlVQeu~J7E(G(0jkd1(q zx36J_^%F)-+GSnMg0k7ML0`!B8;*Mt4`N?TGma;H3%P51%{Q`v1QWTDJ)GU!GaM!Tn*O0+CWYEkw}_x)g_N4taf^H@~rJ5N0=sjj!i^4ZOLLR zae95?6Bre+XH3-3TTwhlJ3sOc4;z!OG>u%pdUr_QrwFI*2qW{D$PNBMrOF4^7rKQ4CMw$bok(uNV3$7NAupr6e8Wg^h~ru*6f=4 zfWtUCa7wUkGle#ed`m%#b)d7cLGHq#I~&40Z;N|V+0w_y=DZ&|VIF%CUz9w|`@G3= zS4tc2s4{+x-8s&iI2~ZiE*i_Nx|1t6x8(+yoOOEr0nn4n$%7gORj?xO8fYvIx2)Ew zcz#y^{zA*>Am1{2&RVn z&lRvZJsV#h)hg(=g&oAD;u*Z?{%Z}R=N|ZPCZHk7*EonM9K;ei^gL-PbH~)87mez^ zl=qmyTe}|bj!MmR%O2TIQP4cL70rM$i<^ANxtjSJsGOFz=5nj_2O>pnj-V~6Vv?1N z$Vhtl@`a&flo_PZ!eBr3QK;*QY* zrERk<8d89>zAbe8UUg&pvF3F6C8;*QAGI6NeV(4>Y1{PA*;Y?-;fhNUENAhNd?TNK zSDifPV)qzkqh^&ig--BPBcaprLb593StnFb2iPD6y1yqXsGcAa9* z=BE`VLJ)pvjl2;sY|rfGhutI86riUX@N-!3 zXwD3`A2*FuC)?uqCB{Go?&yJaRm)vLXsLLD{Gy#nbW$`JkO_tQ=rZT;)yhE%(fu98 zbDgxYGq^3DpVi{7fuNzE$H0zN$tmHS^12hK=FJ>-RQtFf_2EZ3Gg`(q;3~VS_ZUkb z&ZpyaegXW(CO)5hViYR8g{a0o1gv3tfi56irw^bq2zP)Lih0gIkTb)kP27+rbbZ@T z!39gH86+p{pwtaIo_(I~Sy(}7SBg8VM3sVMQZc7{<-`|s8wtOxaB0kFm>2!c7 zCIog+lkLL`;)G-vsJVPyKUZ(uCs8J#xQ&`$*Ob&9!=>o|Ib*aVp=6irdv%odL>?8C zAMGxu+#PY2N9YmLuJqA*TRl0HEvED5x9SWG5yfOHWHaF}b18VU0h9nSjYHS|h;#Eu5oeO#Ql+}5E!#{P`2=LR#&xfVU-Qc}`* z`nbso#;%7Z?ke)Z`&9zW1WoDA_1OOUM<#^Pc{jVDiih8|Jcr4{D2f6ARi0<#@ zq)?;Y=BK>C#axcell2wc39&vwFYzd++b0$nHy@!3v(-Yhl+9gm*j4FgCU30yUI%c$ z3-BN@l#G~dwT@IjMABX<@JclH;t;CTHC-ZlkxM)$T%Fb9=h9YPwq7vOqwOA9a9(V_ z{+62(&AAC&=*ZN{iRnoR5g+8AYc=t?1(*}P+{ox(3_OJA#-G)9-mf?3%P@(wL8`8PMfDv)31}4aEIHek4Z`oi+k<6%dN?HOq^sJ#3$GkrT zSUYFhtr6@D`uqa!7!J`aGHTjlj<{>U_3;<9Mb$et!1&>5eZS5NOjr6J-aKDLLAzXr zYK8V-6?}>q5~FsKUw+LL4xQnmT$wEKC~G@vr83GN=}!dR7*pb}&filjzwP)ZI>PPj z*g{txce6fDa@;<2WsJ-FyrDo+7=ELvlI8t<5+`MTI|BT<1@L?yrP~J!C7(A70Yhs- z&?Mfrs5?EEM+N0eOH52`t2NAarO@h9w&Sx>!b5Y=!LdU(fL-~*A_*YZT;Q!2#TJJT z92Akk=i7G-(GZpYAh;{Z_BAA-c*_ZYtmEK^kmID8%D4djRIgQWk}4hQ&-yRp($q%U zReLp-vK{(9gd~7zT=DVyAvl8Dvxe%3KF*zsuf)`ZIQjh#~Yt z6_>|pxcCzL-oFjZk_YqxA57{D!F#NjA0rJ(@N-_XHtpN4lsta%*ykT2n>m2LNR3PT z6?F>eM4f}@z*&LJ+YcxDN-U=zBFrjyloJ_2I%EW0;MOl-SqAXA{3@es{Cy=uM|&Wf zNLR~xKJ7e|I)OsXrK9L$0%~-^MJvw|ie|smv|>1D_8K1hdXlo*<@ZnP=ynr-$#-s8h0RI<`!j$ zVf_8DJBUsI;tFn%EMzY@It+x9Ie*Ma>5Phh*39-NiGd-E^RYkRN8WVbYB5DL4Q4u? zm}{-;y;Kf>td%L)pt9Bwt`wpp0N$v*n%t>!WVxe?|eaTOp_@yJy2z zl^_w#5r@spubgD={&#O&#Ef&6=<*$C<88R)*czOxgIGVv;<8hGZpcX6s%v`mOUN zdhmX3lcoeJC1g_U?`WscS-_P>!<)X~A*sd0UtMgnj!h&J%tsE!vC)MQFPH?MfQJs$ zBRgY^Qyex#OBM;sRX93p_L(t#%sT0abcnib7s_KhupI3&TSHaSn$d|>PaikpdA^03 zVcitP+=@VohKokSQjjis2Ddnihl0nAp+~?H%!RhpB_dB&)Axt&FR-b zH5o;D_unk8#2X~e{TvN_s%wtqSm0i$}XodB4_1!tNt zhkF~+f~6ZpUHTH)*em~0Y!@;>0qzf4Eu?Tlc-gbjI?=PGayH=-S!a`OcuNf3rYItU ziQVuLz)C!v&P6Ax7n#T5vW@>hQpKt(#{D;?*ojN zY_p`}hSWrJ^=xy*D_$w61rd3C%VepDc{0Ge&o>r(e+fCXUl48eKGb+KQv4vhF|d zAAFsOhf;>8T6luEh@!a9c)gsS6y-4n3I@EQFrCQzzO)cL>We+G)b|diYfZOeSUiqa zf2O8l-ug86&O8d5-YJC<>=p93h{z%p*m#t|rn-Pnah=0N!nU9fGvj*2y`TBsO<0c+ zYoY(6#POeh_Wi$m4n3@@Q&@Pb_60QIn!aCIO&i^**G~IQ%#$Aj=k4b}eY&f0Sq*~$ z;dCQAYkgDkL_gM*+YV)?JC*|HsmWEq2V%j56k>m+=K@1EX{ue{Q;mqU@>mSE?H#k<0^-w@*?#tDHEbchkG~cK4tG`!Jq4Y^MklLVwX^ok0%#O?!Qi zq<5UxPGbP(yrtn^_7IE~5V}yJtfv|OP^1q^kEu<_tRk3{R?f~)pb}KO?k$}`*oYm$ zJMvcP+Cy&dj0J`Azah6D&PSb!k9D-93ut!1o!<8e+OSjtsI-uR`PT(s#_OmZ{em%l zUBk^8o3YyLK-(1J+!1t~iyMyFtpbS@OB4eL_?7v*ol~-r@SAqNUeQ71s4>7R2;_(o z!d1sS{`+4a2?|!HZrJKzi-kpq7ES>AmD!+VUp|ukz{3k#yWSMD_~;rG7<(w|&$B-n z#lylYY6@$Y`C7>&7jz@Mo-Y;5M=LPJ*`xUb1%V!9jP5~*@4=0l z))veX1l*RC&ncJE7H=pyK?j6KvN{`PAU2|+;643NcjgZ$JKdoa%#SYkI$p=KE`U{# z<$=Lq7jCHO-vxED>*ahU_Ay<)f(XBWhWVGpAVppwl%|?D-gfIkmXf%%Kt%F9Y0o8= zSfhd<9*u>}P-p}cvTBt<8T5V9Pysie5t5dB^MTi>?8hEn(Av#*ETz=}82VWgt2-Rnp0zb5h{0EU(&RV#*kpo}5hBXEd(3bhh%^bAv zGV1s>SUoYZx8m|pmK_XyUk(bEL#~h)p1oMxx?U$}WX=s2)lnNZ0s!0{w5I}N*gxkN z6lnnyL!x}p3`0n$py$%QB{Q|o8{l(p!8mxAZm8+i`iGareom1}zLf}MMF{U8;i4*3mG_r`XULY9)av_M4i zq?-rmDE?$>c&}HdB4nt>0K5^|5U@FfZ0G}hG`ss`k-H#TebzpoZCoyNPrb!*GUel5 z(w7m2Gi3g=I$wk%+@RsaStunvQE&oi?AhOOuR=`cdjaq#_gNDrDi#NSZ9KJq-+@v* z2kncDI>~FzoK%J`l{gCOc7vq06f8$9HfiomWG?T&dBqk=rnv$u1k%KgESBKTMb%qj z6U>mE&AG{CjYCGJW&%ibgn10m;a`@6!}C3wsQapyVx|FL+<@e^E~gIwcZN~u!4m?| z%CHZQn0yN;^4@7*)+uB=nLbvSM~HbsQ{kfvwMu9?Zf5oNp1tN0w%TFyGt-Km*y1J6 zbQGsE{eu=j6fFmbe1Hd;ac}(delklct>_UYN&Gkl`~zMHKQ<0algn=Cf{>Ut7^o-- z9(*J6+19GT4~8_1%Iw%+xW9{+*11yn+vbk?sK3!Ql5PTVU~Y%R^Wv8A=1{Zy?Yx34 z)+;)QTvO5COjF-rn~WWUd0aL@JVuYhWT)e68LbW))0#$H-<*}wXSh%dJ>Xx4)65h1 zG@IoY*Py`I6Is8Vpy?o%9IxR zZ7{69$s=2|@2pn}iIw3BI{*b&4T3VS3bX;5%>j`9tw>^G4>-2F$+iXO4lK~1PtyAu zI27KpAp->K_FHAl9X=Ba1DD>G5RK|kugo$vRowHHL``ynw)T+26xQ!za z9oCWB}b?KCA(I-FS{WQ97 zsw2S7(--;RMiy|^3Nd#$))LOpfXF>fyM1y*Eutv=)`79nJ;Ukrj(*t;a|AC?@@+R` zcpE}|8_x3^O^zBinXN`46r9)>Dl0oPxAq<$%uyY*A5GMmd!%%exHPS9Q*1oQfp7EC zZaUp4Zp-^j`j{4SYWnBNHAPy$)DVv*bxC0igt&SI-yc-X^^F^?dQ%E02$U9q6qGa> z!e9q(N&fXh4T#?p$-o3ko!>Nvs?=JN{y||obF|Rf7S{o6I@8r#i12-2@LvlKNP|}h zrK#qAR>8|^miqeSmT@^9*u>}KxhOMvTBt<8T2jEKmqp;5t5dNi-C8j z>{}jQ(8}dzETz>h82WKj>&rxX&9h;z+v#>KN;_9>lBG7F4w%#un@>Iw0{^6n{Oi70 z&PuqrkwdQshBXEd(1!Wphm`TnnL1OT{eX)gpOu%GwN3DN?lMnw6bDMpY`L9e78OXg~w=fFqYf>H2)Hudw> zH*SiZoFbKcD-p;hR{@{D0#2k5I|Bb{J0QoA7X##A1^cE=3md z|Lzr`WSVoZLLg1-$YKc|T~xg#w*Cy+>72`4HaKKtYNmih$C!J7{|ANM!P(!Ks5`1> zVx|FL-2LRXuBNvE*M(8&!D9l@%CL8infwVT@;+)G)G1_tGJUBq_Yw1iCc=m3YL(D( z+>YyS-u=iWY_-E?rzRCWH^oaH>MV|?^8TWwPZTW&hrEwxkx6g#y+JZdDy`@)B}x1s z2K;qa2tPIsOOu-(=#-F{b`Yp22_Aec^5M#=;d_cSjLPi)K9TLUd8FPPY;=vJn?f8~ z*vIj_K4HAy(CqoVsvwK?igqJcRP@)=)YsS}V@F`_l}!*2(Bm-Kul-#`tAj?gCJ|TH zr=|26Efhm{|8vCwpjjktYSzn7FF=8@$FjaXhtpAPp6@5!F{D{x^PO=^Upz8t^17?( zsG4C8NYMX6HltFF%9IxRB`~ak=}lX-x2y*WiM7!RI{*b&4TAEo`f5Wo+if6&yOG4$ zHgIgW)74|nwOF7*FQiX3a45WGBL)c8H4n;&`)no_1}^;-AsW@5UYTWTs<>BciJIgX z?KL4MDXf3R_bt;Qk!deh1M+ zote8zx3M$R>Rg`AoFzjRHJ<}fwHqe)#+m;fQppTc+g zRdfC1hO3?z0ty19MIZ$wO$IR72V0T9xt0Usw?#5Afl_DJ&7mr_7NkFy*vlMGwKm0d z0GrKp_2we{8XEfkWwSJRg;1Jm-pjA66ta}Wg*hUUhjDu=vBVk|1o3DrWQIZ`ppa#& z49cKSkcJAlpRtg%JX{RCJ!L=h@PgJZwgV}xcEHfLnp)rc(hJ@U`>js)YEe44a+55z zK6SvPR@i*3_DX!RR6bI?x7u;Y7w_379Sh|6tRb~5nI zDkxZvxI$iA_Fe7KYMrBzIX7Hqdu`be0B~2*b_h&h?{{5OqyK2p{7^sx7-B#2}LUTMk0_+t^z&~3nrux``o`wm*Z57+WRMv3laa6 zcD#P-#%U+8RKe%Zs?MA>li>JqJ6kkwKW{aKEF^Jhfr#XJ5BAY%eEUr4VLweo$ViO< zcq6hQU~>rB$T#|UcFp)QcS5xKJik5Iq@3!ZdW+?B$oG<@FCq+P$l_0QJPJp+LBqMT zP)d5D;1tlro4?>;g_zD>5#Yb=m?n%>%=drAWa{9N1EqNO+bh9;&8NOX*O z0?_|uIDo^$jhLwWvX^3}0bty%?=YR|+GWE+{j zRG3GIc|ud+oeQ-}XgO|2^~ZO9o(n%P4oj1p?CXS(m~`l?C<*R=Ci3~vs^M>jG>pn@Ut{=Z z@vLjDuvcc0dUUYSHIgn1acE)h#q)ZB@xDc~XY;CpELJPpiCk0BpG{MrVfT$4gLzWc zK|F>J!el@4w-l{*8`GMGT%Vnl(xeCCder9a&+3ChVr{g-c0s{a zgP_c-0&R$_JlWV!~ns%;z1d6ACASsz@Q%*P?O1YxHZCW4CCnj4tTt(21;wtq8<)+!wA8e_ctpp9}fX{#_Rh^M!GPBxBns8)n`H8j8^Dh`p{SyN4q6t>Kx3xg$%A(vVbW1-wl52nWZ6SLKfn?Yc0o74uQePn!lxA` zUF5zM?)G@SfJgRRLZ4#;9q>;{7C;J!tix!2UJy?U3JAKWhgx@PDtvUImV$qr>kEbK zxm9@A_Z=Ai$?N`i1_Mp*Bjj)?aV|zv#QR@)o$i6o{G@JivKVzC{=B1HCQ8;vSMeku zXv6rpVND)A_7dOudC~eEPLjvlhWbEKBfLs@!>xsPQ!GEdH*M&^1P%4dd=vmRb+$V$ z-K@=kd^20U>(6WsjW+rtD!R@LDmSF>VLY@JaO@`v2tC*Zp4I}g+37<&%h}W=S7>mN zw}Iu-75BNUleU^4{`;_hz`wjFGShWQxYuFYB{V`YG8_-}6Nfm@k>0bW&f14ujg;CP zLd(G+AK+PL@;m-EK3uBE3VlR1vSt*4HEg9{5%Br{KO65>>pBy6#n08mBGh8>k&dTF znAARM(snAR-Woctu2)`XCgEX35!9h=Fzr= zDKqa67IKWpX{^-WA&S*NiYe)lW>1H^;SY^^2tohpT%f>-7B$Jg8L;?Poh`xOD>wo)@#b&8T_UFQ zw*>f^`Jf3C6^nzvG@01F<3K6?FFrrcYr~vWhAx#j4C-Nvq_z+&M=UmO;ZkHFPxsq7 z8kuv=b$Qs9EtE`i304TCi5*!i!K0JvcZF>*Lv}XjI+qO&8JU_XAkhKlAwXv~T)RD! z@P>?8+D1B!HR82r-W00iA=mrgRAtKMC;^x#K?BH>gt#X|;bEPa(`e};y|JaRZ-&4F z=nggkWG!2TY7d>@HL{-|Co<;ZO?ami0s`Kp-`uqndt!^&e=|Og!Rq!uoeO|M^Yru& z*>Rsm^cUDO(}t{oaX$CYI}9q;@tick?d#-X}@BG0i*6_R+k|HjYw zG>`5dTrv4i2v=6P8!f28B*K9r%`nP1z3`fwFt!c9=LSQ#sc2Gd70&G0{IXb)Yvokfm_9`pge3t zrS?-p?eRt@msdqmD&H&DjW1YZK(0ngZ7KNw2jsiPEdgnt?>MP+u|Y;fk{6P6LlcUb z7C=fB*{g{Ki^*08*=7_-Fi*@yNH>dhs(U-l+88EXIf;UQKmq&0;u;H7R0XrN19=}o zII*Y!bf0iwB1QDU--w688pi|6kCBDfwG;Yxqoc{j}c+4U$<m7ycp;dS* zj~w{F$n5{7ZB6b&W(rwmhoYoCa7NbtYFLac%M9KQDPM!t?ZJ3-i ztnvN3-@?~*RkZnt@O5w z`TTfKR;0T7TQ}0Yk*+Oc8{ClYHiKtd)6D=kPhV6lnXbmFW@$~bOfCJts6yBo8*A<9?YNyVX|I@;3|B*l zQTcUsJ(Pc;2qc#r(%b8Tt@4?%ZTqaKQSfPNcZTW%%olM({-X(9RV_hl(P`2xG)6Ht z8V~gchj?V6Wrr#Z)fH!2m4*(!<_Gb6jz@%AB`L$$JXXKFgP-%OtMW~YMY=WbVTfc^a> z=_R`;JI-`;G(Vvr(EW_j-3amBctQZ$21K*H`o=z#Ygn$fHiVVC(+uG&6|G;;tnCEb zxFu5bQcJQvKjzD1;aMtB;AM0BP5pjLc9=CbT0@^N0RX7a>silbH(&}Dg)HX;>@K;g zYMcQij^5-SkYSh>IG^8wgriee~Nh4C{R1_b%_Wxt2jzExs@$HU`U_O-A)5N!Hev6 zj8}p>$X$5{Ty68VCrmp}Kx%JiE45bu>^9K^L)(NArwC~SWA=FJtR{3Whnyjs9iCRb zPfvo#{bQ%OIp>J>-|+(o(p;lgPj8HK_r4RzZM38Q^9^^t^XjnLixigg{!Ue!1rAn; z)o4a<9ae=?CW+qi0;g^6%%`B|7k~7O=!)6xneXQ4+rG0m@d*e1frfVj4oA$-nW9H` zss*xMWi%>Y-R-lpUSk&0BFeYAmiR%%5w{!?UJA;ubp4=;G%8r`rHapOH}iql`P;v! zSV_Mt;rA}d2xjvIKlcR^DcgWI_itqD8zB;a^Njc&ZWw9B6*f91fceInQa=N-AH>kg z(>aMHjxb6uOF}raUi*6c9z)~k3xa@=mY#x6jbSDk<-kEChTco0Q-SX1l1I45zVI0D zJ^+B}h&-m0$W>T#qH>dvNjarL?jYH{?2HR+WXI}`Dd5t->lHCa5 zc5rT8VQmz07w0OKz0><9OV@GnkHhiDvwa)h`a#GUUH5@)>g>$vIK6D zqAv6nm}qWLE&}}I9?HUV8BWt`GoAP{oladHeUb~)w=5>TD}&7K7NmZeeAf@pbQz!-LjtKlNpwHp1IP?VCyGZJp_EEsx)t(t%AE^sAe6oM^jI(kNQ_fe$9D? zfD}QCH;@^^DGL}9HEb7!I}UA7yl9e>&CJ;|A+NVSX+t#otaU0bdZN%$Q8ZV2?LI-z z3ze^u;970Pj2LitqY5L{QgjeWx1P(+LT}|nslV5)h2R}>tupB=HPQ+J69NF`wR#Om z_Vg4Y0k0k(kzN0Ur*es7&9l_|%)1H-u&|`O(MquW2wMUBRkALx>w}y|{C)w>aIAJl z7VD|H>ifawk8Q)^z~vKTuHFxI`5yo@!Q$H&xCBUvb{QvZ86XX{eUL%(%5w#o5!Nr` zchhpilhhF|nX6Y3{>P$RH08s zGblrb)D2K7?1HF*lXG6=?;YvQzgOB3e&?~()By!~qgV;JLoYc^Lf}~NX2eaZ1setP zenZH%mXo2Jzt!~x+&IGk+Kzc2a%L`5^vJftFKoIq5nuUA`j~_+Sg-vKh>cHd`kLD` z0dBSlmvk3ML_M4Zt!qzAveW=^XJSZ~rVT-xKu=VG*4- z+yjoe9{dm;UY4lcI*-03+QQ{53jbw*oQ6b5yyl(QPWpF0Z;!&=h9SW-yu^AI=5UEp z+Lb{?opgVgSokAP(q4qv**OrzJZXfkDLnyRB>A@{+$_2(blr1Yd>&*ltT>doc3)CK81U} zhiS8X7x)CBGJ5cyU4iGzV+vW9W^nKl74T5luo%ED`L%UDsShj{v%&>$PUnd^<(Cp* z0Ois#*nKDgdK8bH1nK1E*NvHwh6m?jJ8C(Z7U)aa1e5O!J*Jw@j=iH=K+GNz`KA<1 z>SA-Fv#KsjuEE%>O6BwhL9_%dd4-k)RX&EmZ~^hyO{330?gcfNLhP|5*>~e@orw;~ z*oz~B-6i2pbm@&bqN*nN=NEsaR!6W$wC1LyV5NZQVRHzBphK^DF8}KdDEQooFuW4Z z#jZPH*n~Y3Q)v@IriO6SaG(I@>?tpFAJNt*vVOlB1B0&=A}dtDklS7~Xxq;f-X#Uz zoj_PVlhAE6xAXvA!(8GUI1|F2Qo2O-V(k_Cnx6VgeccCu)aiIWVwD2M{j8mub#UN| z@q6-S-;I^-GNAr|DBmV~TEW}9!7LftQ&=bL|03%hg9K}WZPB)E+qTVV+qP}n?w+=7 z+wN)Gwr%&DbKi@1<9zdH$BzADN7ky9nN^jQne`bKqAjxcEYr0;rR{X1MQEM7ha30!xKJnpf-rR58G zfxBX~aUb_gu7?&Yzd9_Eurr@jeYSvqA&%!>>HSI_^xw#zWiP!!SrHhLK#Ls=tjCb? zC7iDk7`Pi#Oh8MHZ=tVIflvbs6~=h;PnvH|;rILuR`kS>V&|pwj?aIhdsE6G@Hg0_ z&pNb`f23kmo0G=RD;ri~Ptkk1{>J|#W|!WV-w5q)FEJt$$v|OHH;2fIG9U*T7nv$y z>tM?YQv8e#1iaKKxN1vzSZtpjb%F|9Fne!IKr3XMbH-UyA;X$BW;MjI!>f+B9$qq_ zLEBRRsuN@R{C!mEw8HHe(HAO6&%*M>((6VVsW{uhZqlZXafqYYh3`};JS^M)98h(F z*S^}Bpc@Jf3D!pH zcf>(fP~t76kSX7ADVam$+u;m~>VSo_3H527VZ zq4&oBx9cx1=IIe=o}k)+ECE!YE^l{-zFI-GOVjcmc*xg)<`TiI74Dd~9TCRaU*0f% zmF!<<+@S+%TBuBSEmRdjc26uqVF^#jw%uz!+ZX>`mz8ecW8p?qTJk^N8N#k43ZZ&` z$-Nc)$

{2*eu3P3UqbX6FH}!xR3ch$Y+$nETN!yA~y$@PM)Jn8jvvo3(QI(8Th) z)msL~OQIdnwt#}g#+5kTGl#Ht_A+sBO$bL_ba5IpXhkirVS)IC;}3^W;1T;!8_2EX z!f5)fp;V+_4qqqUuEgqb4qFo!#O0-gi)Cgq~dC2L%wbJ^z z9_Ds&10b$gFmc-GYMK@=+7qJ`Y^P2NRw-CG^)ks3BbH>X7G*pLvu*ACHvpX&lxLcIhhjT{AGNjTOY)5d%iuiOOPYdBYLnGF}43JT!Vm&rv6x&UI zCU;erEYuTOu#~yJH&JyCKxNU?WX@$91&H%xtQKv?euc`&hOMI^g@ewAL&4^t&G{aC zI7C1&>sAf3Ekt4eHAEAD{=NRm1sZ5P7=`u#WPo5UhvW(?R~iJ3`59vx%SLiWn6b0| zoO}7zJptlov#A&fl}^DKjOzZ20O_Q{Lp9Cyf!zZ)R{v1c3f zDFT`!OddXcHE)}X4sCr>FsnV7WNt3!qTA@MXuygkms|hv;_M zfS*lOmxb+ZBeeFt(WX?*WUFkbN$z81vo8IVe9a`yXGc-c(VG8C#jZer@Th{&jT!2ed;v|B2Fq(Rmu z*_ZgNxBqQ?nmV2!WQ=bay>8z3f1LXNee~eV%tut#6eD>Mm~0$pX5r;zo3UH%9is#Y zKxv!)0bnW1S9Y=c#Hd_q1^~*(J`m)GSbtM^WbV^z001Q2i5!h`n0g;G+|aO*@k5fz zYBWJ^I{yG3!+VX{oUL>&JV+`&Kgbh4K9k@@TUtBsckNqqa2DmbQxi6;7|m;SXfEPJ z`KbiT7azaiUNf(De!w0L8{fFYm}pZ_3#MpAax8JGslbJ+nULsi!z*9+H(@*VvQm-AQ&pwxOSE&!CS8b1iW}R#QSTYo;h(hm$KFxLuOcX*zg7 zqV0k9WUjV$iGl>G%%ef+36vdP>Bdy*;M~b{sotY}1osy7%i`0w_D-!n@YgJC@esArUOp!FT{e3hT@)XGjt!fDb85 z2x+>NDr*(*%83T@E6ca&EZ=TbA6@j9Wk?hUBLE$7bsd2&>ivSJfuT8yN892En^FJ{ zouU*<2h0l7d;C@7kYm2HjAG1GR>;0V0=ZswKW@ZgnA}wkK=|d6{#%~F1D%jyM`^ZU zfMxL<2g%)&rui*x);=h4XSK2M`p_{&tq`PF#gU^3VX zv-74xAkkCQN?>j7$7IAAwl+8TvxaP=VH`6QxH?ie{(ccNaIyi}w1;#Gn{Yid8%)kC zciD6y=kWbh1v+x--bnOO@BHSk)lxY zjVSlQ=+Oa6XtGN?G|G)-zqfYZLukT8E*xGKFu*yh$BRyoa6CLmg0D&YsZOVbGc9cs z1luQeugYCJVp>3eI)uFc^$%8~(qI5LQ#3$FAHF53*D1aGba?3EAr&c}g^bTSXxj&A zsael+0T;!K8?u#zLx?c&g(i4oqAxvG-1-u~p$=aZ4||_STe@Ys4-pZKkbdV3vp%~L<6_Ss--f_EXHUGOHh z7aE%FaK-=p?N*fnLL8U`Q%BTtlP7S>7&|1Xa;;e%nVi`$%pXWEmF$^C*+>?J6(ha22Hm z2j#1zNP4(JX_7oe%?C!|c?90y13fW-R>ci;Zx-28ll)eSp$|D zjCO??5k#$iz_Df~Dk{Nj=QM8tYk8~&3cgVt8HKny?8(DRD+P7So?d?DP%qp3Ej}}G zb7U3N#aXh(jcy9NnjZ2*hzlRDrnfvNcQUFNq=j^FMJvM!P5Pt}g9f6w?h0~#khI|D zv7G8nNUkSzIeq1eSJsvIJ`Adj>H8hyoh7e)I}^lG3A1n zTZ9L=U^n+q81O8`JrlfNf7OO03Gqx^^6N(uGF|#G3+)MPRT~IZ#p!veHh+F^%B|TI z_xIJqE<*12mcn0{2&06R;D8L_1dhwV0WR=!0A8IBI=PVd=uEk%S?j1}T8E{}kKR0N zWC||BM$G`}PR)<9V1N2S@n za<@qj{}%rjxh9R~N33O^@EnKdO zt3L-RS~!>nmv|38Dk*)aUor~ZK}D{L&d&v8PniRb-`7JO%W4-5K_^|qqpIpj>c8D8 zyq9KYC3e2k#l>GkL`VbD3)%+^Sv-0+IKGJ@+hyq;x1}KOdfQ~%T~V#WdI=Aq2A;jW zIu0;^lY22bCB{BQ^wzjTa26A~Z&16E)||21eww<5@d{I}5V1-dE%GH&@e)z3|a=L=eTJ8@wFkw*qM4$wz~ybjU;7_?rN@sCz5@h?#eE z`wO`kLNw#kC2`c($D1-JK5qLCBy`0d<}JWzmg8#vNL>A8+Qp&2L|knjSjSdzn$NcV zN)_Qgi^|ZaD=1JS`8W!6Gls0k^32XTKzN;o;FCP1S-7TRBje-7?5DsjZkV%JBmzLaQW>+ z!WznEtNtq=;T(IGCBB=0_CrO0B?=^m^mt6~oY<7pc0~D>2)(T@ORQr@T`y#0KgX@;t5}xH1XDJ}cjLq(P zzqvmi%9`}`tl3i9ZNxOALm!nhIxm(chVeJjY`K>llb@;Nir^_zn$QJK4$)QcHK2;Z zLC932bH_0mFhHQH*L3LyZ2uN*`V=5}67ce!I|O)tkaEHa7*OzM6-MGGeW>8x@?3Fx zNk|A$yH$Ru^zY0lgW=K0J@IxA)M5u7ZdbwNSh~ih@GY#V7AK`87OpI(ZRX?(q&zqS zGe0yYp-IlF-B89XhdC{W?q&U_CE1RFh*->QTYvMWczkjsy~rT&&nwx;pXjm8 zBbGGR(ciZf-N*JnkP$}LgzC_W7K373%`DP5WKtr@qtsF>_85cnmlOxYs%kRK)jzqP zfO(Y@iU_7Nmv^|J3NfeERwT1U1Zl{ZcS(gW)T0SMW>}Cf) z#wph-VcI6!|K7HSRdB63!2Fc4Jrl3k1#!={vYB}_YRK1g@(3~^xrBeq&2rDg^x}R#f7PB z-&F$R-Ip4aWa=^Me-wO9eT8X+9>S}W`#rvT>CYOLh#f}dK04aI&E51a1|64kO=BH2GbvpR3_{ z_=nxLkojw59|_97qR82E!3eE@y5)44rMJ_ecD+KP?@nS0EirVZ)4>yJM%rT}SSVud0KkD#?;&WB~ruP%r*R|tW`X;O9}*CETt^reO4 z)fV0)+nQwhQM6Z3dq2_rWo^BEVpe^>e*Y~CvkxcfN0Q2EI!>+!T`YuH4QsQ1di&dn z5}}R_kt<9qY&vep*=K5uTD^Ai7pS@6An1ye1=ZhT^N$U$Lvit@nE-Di2*E?>oHheH zTD;Ti7a!;#EiSuxZRzVyj0rPcu+B1c*=w#$%H`3Y3s?6)7btuK>*g#CtNS;WoH|Qv=qe8b%~Pn)G~X$+@vhC zCA{=y=708Z|CRw1)%WtBJGMq*oTJLxpj4sHWOVX$B z*F52a`Ew|uHcT27*Gd2mj5DdErus}1rFj9dNrKl}Eb?KaI692pi(@zu0Rae_IRMZ) z=sradfD=OY^ZX{iPj*y3k(dYp5h4|_6+{jkXO!KRg_ew{Wa*bn%Ti3e?pl}@EV4P^ zPA_a1SOwJ(EWnxMZWT5`nfZHMH0#g*iX)s#klSwb8=2onkehDx&t;x=of<`f5AH*t znz$?IpD!*MPC%OTXYYKi#g;cQuj{vo{LZbOCZ&5Mb3h?enY`U2j5lGTLE#K+$}Zk| zwcqlEwCA8Bs+;V8f|tH}z*!&fB%>;Ixgx6xU5Vv9Gq&d+@n(vU*&v0S?xZ27#>u%1 z31A#0Akm~mNpDH!{XVZE&wU_<#-zTD>rA4}F(_p`EOaBSI8iw}s6V=AYMyTx6~d6q z86_0DXcT3vQ55&=k=}+xTtsusM@QF86P4a^i-YPviL#JW>)Q8|2qJqbKN#EWo0UUIUruf|+(A1X=wssyx?u>}GwiU~3PM$O^X zd?H*N1TS$qT2Ws&CJwrp>$AG&pvMV8=eDKj`!zB2vqZIF-x;s`kI5DQ3S;`W9yrL4CZ zIP16hpc)bG7Q)yRi7S2khgRqcP(fchrmhCVGLrXN2^OiwN65S2p8E?bv~RxPC(bQQ zjrkme?-m?pl%&es$5}K5S*=NDqOV09CDvKODR;kM_3Vj=scyU1>!<9U%Zg*qz$@12S^nLvX`Ms%~(F62#8Fv%^KBU)N)sQMQ~qbJO}WJt%%5NLY6JiL~t$#SWB!qF~&1K%H-0y4|} zDH5jjDBxcGd+CPUMlgKplZ65RTS8HyAPA0PKu$=AsaTx5I_wR?JT^T#H9^;j zLh!~#I+c2?Ip9Gc4rknT_)l0UrXZ=hGa;85sck(@@~pUV;PT6b$uY7JK%V8yU=#f{k* z9Tc`>W^-2!;RqJ|_m;mZ7llL+coc`~Bksj_H_?V?TNWTcz`<{6V{vP1816hA3@&Ea zS>z;<_BlMJv*#w3V*)DeX0)BecJc*wPLWkZM~cgCf@GaeO>W_PH8B55lCvO2=&@y( zm;spO>hn+>b_16qqh0c5W)#U09W7(^9_iyZVPWj{c0{-bo#CEHHtBc7;@7D(pqJYC zcdzXA>u{BnNg1J^;EGf%)n{;`<%b`zUxsPIUp*;p)eT5y5*PKnhrRk8^(E+<#}sAMUYYxHbEfS0dL+b@ z%0$Q)=%y`WK!ZZ7jLM<}FJ+;kAhREJS}O{GY8W~WT6fcU*yVl_~mxE>FJMiwEe`=UkKAhPG>|3Uke?l2qDcH-f=f4&5mtutNCEL=IGHuZ^( zpo6lgwcU|y1WAxMDxTA_t~%n)qa+Lv3=#UR7)~>qO&5dEo4MWH&^$gvY@;l1k@Xjv zuazH`bIc`hrlmv};enl@m`as%1n@;nKCuQ&rMv;PLrN`vXV!sQqyR^C2A61!Grk)O zF}5g@YjNMe!ov>MOF8B}k4ZL@Daji#sv?d;jK@?{B0srA#X%Fp*5&GaQ@mDhxf@Y8 zT4FcAMvo0~oRSdVOfFm$j&~wpNVf#;mX1@G&VCFucfu!EM3^4>?=I+zL2X@*Yk$Y) z^7ss%*gx+pKN?9z3O@;)Y_c-`!Hw-vP<0X%rlY-0x-;~`z_c^qKxkAYnUQGI9;0kK z$0JVu(u8`GPg7Q!{f*Pq5F<^GtvJ5*hiE>1u54#aWqiZ4$!wx7fEK=sW3DCHu~Pr8 z7jqdKug~mrkgEhnGNie#lXN8@N-v~g_(F6?WBeg;KQi^lav}^_`^mfgs2zFxt?P~i z_HRHC(S z*6*$-&p5rZKW!Y&-nqVHWe^36fi4$R&MCrHzpkjfZmFwxX< z(J|?6lO3`|f-BuEpcx%40zO#Zh)NP2NiAc8UPR?lX1E043sLu*sPqttw+NL3GgpnD z!9rRsEPkkA8wQ zR*4jwbp#X5Bfxd@y3Q8OOxN(dp!B9JA&MEC+zpY#F_L7ajc|-1qc{2vmx16QdT{-9 zhU8hx40lP1Lwg(S@<}oDHg7akDbsu9m~6VAhe0kJP9(N7%a)ZKrH?z%mKTJN;+=Ul zL%}bYDWrNMJdo5OoF{#G@Kppwe1=gnHeq!LXKV8bUzw(JkS4pfcr4D2`J^{2htRP- z#ZAZ36(t=1O|4@Fp1L{KhOX;MW)l9~P39O6E&1i9^Q2ydih=oS%*5t&yZwi8HKKbs zHfT8V7Cq5zIec7z_VBPJ+5~Cu?>40RhevSUNW?vV=GLdg_+?5dGq8q9W8yy$VLjXr zAx}@iE3;p;gM+K8MSq*!%L}-3Y;hf($^L9iSamp;jjYMWBwg(`xf1zb+(pV`rsajJ zGYduJyU3yV&6mh1#9U7Zm>Ms3Smdp&G1@>n`iMP1CIj>U{s|-a?v}Rs1#XfqCcc?O zA=H1oMs%8QcxDZUHp_poB*?JA)WxdFtdda@x!j4@SOXAw5*m&9A$u)dG{%RU^wS&Z zobuICneppaEIe@!*BLK2f{_f4NN3^Efa`zECIHbO#a-;e z%()#R33j5tHwZf6F!gR zi~yx%b=BwV+kHzUrX!&nd2aIhSqXivh>3va_BuOzD~SG53s>9RHQndl4)>2a7v-D zhIcj*f;0@g3Trw`)biHLk}Fo3E)W-21*ENRh{taH*_~EX5XlCaA4^1O`P0Mnd}vD* zC$cj?Tb-&kN>%1!@sr-s)xT9NYU^ENx*b(}>>F(7X2z0#_F`~z3}Y5xmxduA{)A_i z&k_Vddney_lZi;jw*nj?Kkyyn^g>5bRQOaTo&535*C3&G-{&D$CF%KEo;a^NE9@ZC zvmTNq9$KY@HJY4`XinNS9366TAmjed{)5n>u-KX}pe(Ey@)6gG%g}rnNU6ia`S@d! zpZDW&|NAnbRo#iB)S4$d|KS0 zRR6`EURGSklN}-BgbwC)p5Q#+aTLyWSHvt9D`lr^-F+=h>oY&{$|+)gMqLM@Qp_oD zBc{!$YMJDyN6Mkg@waK*FgziS{xk&AJKUyK65&8w=E|!8;o?^3fY=Pz zu(O~3C&-K-Dal*8 zIxmt5MS!}lw0%yRroCaMV6zrDfc3+7|8s!}E#`gKb=hcDGPnjFoyAh8iuju8%6(ZxhSaRJD zoLaCuFYyyRi2WGt`gl_@UVbm52l}9Bkg}UF=;0>A0n^Pq1%VA5%8k)%o=034WpU4_ zzy@Wo+w|@6M2MJG91fk&pTv?Jr>djF(HmcOW=aW|jhv`8ZjZNhNK#UKd6+qNNIs1Q z?#3c?T?vt%aFNj&m$oB(%OXR_j7YQBqHy=(t!T8Vy6`Px?ux;^5n$&8R; zAaKwe>qt-O0pO<#bqW>!!@nq+d<&#bnsXV2t<@Oa@ImbI-4pD_==z!ic(LpcXw^un zXb`HCSWDESw~IvwY{NadRA<|}5`Ab(%xjtqi`IZ%KoZuO9nItGz%>}lUuzmj+IYgs z0XM_tOHm*jx7Z%Q=SM~0-+)o6ebFTuivDPo+j?1$n3p(sLyI*0-$)q%?@7L3G4?=+mbT)5%lvAh?s@Dt>|MwH;>Tyg0rZgRJ>rQz^T9jtIql#@59+43n~if&bvGY*nh1y#v6aa z*aCgiBx>8E%uwXtWgZ_K^}u+@7Bw?vKb(4^aOfj)^enpZC(qI!CsXDrvo-uILfOQ9 zzh+#wk+XP4H_9Dg_Oq?6b$wa!x8r!ewCA2s0=tZ1+Lr+UAbQR=XyuUK%9|XZEj_g} z>RFBmS5p6eGH7*oyxS^rwnEn@0Y|~+(j!=uY!jui>Wa_TS!)!Wi5(}n+dBq;S2Ki! zuuzNH^*fH*Orx`IXl9V)4M{xM`^^i8koHR9wY(Ys2VAopv|)2fNxcT>GoRsA&HpS7 zE*L25{6oR;jO4YQM*jC$6YK~R2+U*PgZ&+!g0`W3!fw@}=r@lIaJwnVd7_TKfzS*0 z1&9QE^-_g}{j6qpwf}#8D*%A|YuW-WpBZ`bBI*J3NU~vRQBz<}e_*{J$=4T^pUqC= z(Qs`qfY^hD62t_AEQIwlAa|{mym{r&(~*$hjI-D#j`FeroK9UDEv9*`3V6Fq;M>lY zwoM|qg4|1)@Zs=PvS0YfSKi0S2fAyXAeb1u{vZ*&sVZ(klg&@dd#*IPq;sm9AtGhu zOe^lU6(4Idy#Lg{`SJjOkoS{---9+1$JFCe8&9vcI(Od5jpcxAa66)#0MK_Y1HT$L ziR^GI;S>}K4WGe3!2n@E8tJTSL(3h>&|CQRzQGmULO+`YDo+3_qqmWon9%0x*Ji|l zuw9_@^^8fV7*LE_Nh}i;S-aU9<~GQ+g52F|jUHq>hed}2MNCC&s9lxE*Hh_$l)~(U zO=&~yNHZh2@r;S{6^lj6=E{a3ce~?tNBiZ}#6?3v`Ac_a)?KfIr0Gp$^&$u-VnGLY zX|^(vW}*1Z`uhHv11wZr+vKuup4)=dl;?h$m7Q}HNS-X#ei&@BGo&k?B{LQFFl(AXon=hWb09R1 zD<3!`;}*aJYF6_9-h=`;0C&^md!s69bzrn=MXn;^xe38PgTVMBU%5t{8=t$h&on5B zOQ2-+9i##p1np8Vx~Gn5mUe?1kHUvNFL}xIzpvH*k94XC(a>Qz73)Xrs8@Kt))8yr zTxg9R6#hr^C)fq2?7xC`bp61Ix9HIyVt$-1d+>2v_!xeAa)Bgoq_133-9~Qi7bMF@ zW+oGIeuH9)GKw3pGXLN%zD9iiQ%@4t(S7oS<6%9?F{E4R)pqk;vX8FIL698&|4`4#@il zO$eOw!)D%Bayw*b%6plT{EeRb$J$N9oSRLAc%ma4`-3KMc5l}iCo+{{a?MYdA=7mx zTM(#I%>2Jwj*{V!D6uvAd?(&{4tyCL=JIM@&An|qLr%JB&Ygg$& z(s*W4#v3(r&B`>gl%>Ak#yl{2#uGE6{-}OUE$A4~@ju2qIXD|zl)d3F$^@2v(*-@!wF#-by#f5__k7G1ZNxlav>cWS zArgX0WfFy)d_an@me8cKpW34wuEfSpq?p!a!=w9ak%2LDHP~P%yEML<@aeAt&%48e zem4Vqyw#<$o#0YmCQ>1JCrz2w!vgz=dr6xJhtuSIi~zCj-+o|40TCS)D$57`BZ3y-7-2kIQ?7#~XUk%&7gKO@V=JYt1;nF6) z3Yzu^@}O{$b;RpN$z*S3M{I_*k@%+334eQK7(+y64v3>lIlN%ZHP|T{s`c#5f=P3!XBM+0A@@ z6vi=+&r~IZ;Z!Gs?1UOH*>Q@MP=FQJ{M>)}Kbz$C?;7cVK;c#I8uFJvPD0|4`(kjW#nGvZ}eZN=JchH21(E-6955@AX;i-`4_0WuXN1%dNSkdOf=-3I@yh^TfXsRxtls4?Czs^$L2pj;Y=s@1f`u( zQWI{~p-dM!YAE}N6X4*r;28f7#z8O1IT^y?6r9CFMFUwaj|2K?o_{j)aj;@#b@Wic z=1-13lIADb0jcQpg2yL-XNn)!1!oY$5(a#{24}gB;OH&qCin-K@}IasXltKl6f50b zSdEpB9Px@H`$vXef;cPMX_yE=pK<%XMD*`gTgyaJO=ZH&KvfQw9#!fEd8Ijbu46Ly z;^%@t{gs{&!f&e}l=I5U#`WoiiVkA7G9gseoM9$TEhqwqq{JkDk4UN}=Ef$;b0>hD zLecN~y`H8ZMmYLI2WW-YmmXi$?=uGF%mo#{$Iv+pS=ptibHdsbdP>Oz(9S+E4Dz?# zc}hbz50+f^8x>>D3ZN|!Rh|KQavHn?A{1xWFGA4I7hA$I}Z8U7Y z;dswLD_|VUtL0YE0IU0_N6{kh-=vd_T*5iHB_2cV&_)#5cTTNwzy5Y|`Ue;Q7F0L0 z8e?4BFjHI;0jnSa|Sc zWd==XUbRkPb)y!<%T8YTHm@HW`7*e)X<0d7x;8qd(++on!X}*yBCPmURp?P1o?imb z&oB~sR%zt;6Mz$3If1r@2UMfCZY0HkvU@u0DWABuZ{B^2gRJ_1fyH9-7&XSD$wy)7 zRuk6f#flI(D&H4CU#tTpnm)j5K>d?yGT3C~Qr<}p$bhW2tRHN6QsC*_X{AAOct4)` zMI2vlZ7XASK2wtLvQ|w579RTeux6y#f>?8Qrf%!GJc?f=D5h+f|DXY`0DV)|mQ_zZ z)0t%WS#(WCrR@;fW0DgXpMP{o-$~bVCL9fUFm-_rd%?oR*}+=&&IMyi%c0&Nyu%V= z=`MvNnyPLm#>gwZKoG9|BFPC+i;8MyPJBn8uCAt~9W&D_$a^x~yWuQ~wy!~#!Ezi= z3qOqFDT4+7a(^w)oSBtoUu!6C&9;rutAq4??|S-XxmiqUo zZ>%z>)S3A8#t*yOP#}7o@$R3!6Tkvf zPEEwCd;2tFTzIYhWpH9q+Yh>^=9oF?O>@#`{?6GoaoVcf^H4l_%XwvL(s``-^e$L{ z4%UqRXzj+8iGBC_)AD_fI|fonXbExI46yK_VQb?AnJyyyIbQJ0v5NIiGFg`(Ce$yw z6*(L5CCXL)^Z6@;oG;KHZS>7q6$B95Y&#~Wmdcdvd3X(qau02DyRrO*IB+CIa_~S7 z2_dR9*jvg*H+);>C!dt4TTMxTC|d)>a<;@-6~*k#ZB8+bf*M;BP`xY^L{VJVd)%L34eRAaF1L=aO(TRB0v%CXKUhX#vE*Z zXEaI9o*3GEgksnOp|)aqaY{PVN_$N*+8wwhD<=MNz9F$*QASSWtVsVy%3rSg%lqZk z|CpqMf!ZXTr=l6cL^Bl3lO>(aM82Qx&8DYx3P%vLSZtE3Q8i?@ng&SatRCRzX1Y1( z7c3FMFF@+c#%d}`n9w$$;mg4p@+iE9GCuNKTb`Uy!^D*N@_3EnT#J` zOYAZXGmv|_AZ|mh^G>07_m$ySm@$r!PrcIKAL&RVJSCNGD;ux-d@x{Q76Vp#!uEfl z0CJeR)Bgno@6$qa6~v?l-K{r8#B2=A@szESvKAnCHdE~5?^^mvJ-qU^{49#%v>%wQ zN>wi+BM#)c7$IUnUW<%Ug#^#|lTP?)*OrGd*{)ItE&ewz_;$D-m4c0kB)}8cdAOFB z@`lfqA1eIG1F7vW!b3%IH&?)_NrP)I1hM9qe-G&{D-bV@?-PgD5diKLxESa2xit<- z9n0f4kptx4=%LWo!kA3XuMYoJJpmZ|`QbAiuB9`wLt6c2F`lr{2B`To_sRGUrNzpn z(#qY^O%B3qc5ln_H6GVcVw0N+me?5)KZ$ z>+fyrUoPyq?fA}5I(8gY2Ep<|o<(Mgd?h5*_$rS^6W=@E5KA$_Sq6t@S)oxDPz^xq z{6Z|Ia!kvo>aGKezvwkSgOYwj4s;4oY$F$FHe#*w;X6a`$XyjlAh+27)?lk=>Qt!(V6sJV-tYY}hqHZ&`zixs zxGnYP`M({LI^)&kXBy=7Z%O+@X@C zm3ORr&m|@mTOds{tyUFb6f~^aqc2uN-)P~Cn<}}T53Lg11LmDN-aPDzLkA6932tx} zXSN6sLB7H;LoDXU7PV~w;No$gMFI1i(L!Oi`JHcIzpj_SlTQ4jCmL)riuGSs0V<9H zz>z|4jiqX@b)pvpg}HDDa~}1my)1j^0(@!Dpphcda~Y~GXi%1TB0DRaOd-p2AAerp z-V<FPD5X{xS6Y8moDVQ9wXZT^f| za+K7$`|i=&VR7fokw|SsfVEK;Bi4!h3}CKVFwyI;Pr(1I2@t}VPNJ%g>yV-cyg24o z=&~+(G&lEVx3ELAoq@G&VUR=c$vP))yHVW>wfB{-T%09hDX3bI<$n>P^@38Nt+hmx z3zQTNk*fgF2}XgaE4xsL6okLj|V*p?7I2GwL znuG?-Xnb4xW%6$pEEmThQy3D~6nr}cs~NEq?omOu@23twBI+T`xMo@XuN5OvfwaD zrO@C&v+=RHcV3zmYO~u=TrVG)4XV>ovSz1SX48$;A=1k5UbNw+nmy*IYP@n3HIih@ z{r?dhd|yM=6HxhyAxwNWx%-@!VEpT4HFO)c*jcu0>P!HQi-~)9Wu+Uu*!cjsXE+08 zCES|?UwtV968*eYDt@K&qDEmek{qIcw50!vQ7W|~3CMrVSWdPl=@?hms@CfHrl?}= zhf2mhpf-MoPxa4?hn(Nh>>WJeIuI4LzFr7Wi)y|qvL4W8eVw;jC!9FH-}{}JI-<>4 z$v5#@U^CW}JeMOUzld4N2X+$TsLVu( z9p|HXLy}!xe{%2#Qrj`ktUG#G(MIg$YA0dfPYy}kG00Y%6&^RwV)JK@dc?YE@gOe( zCkTV~+{zXCUuF*L->vDqtc|LeiN;|89moaKN)wT$yA#GXE2M|UH$|i({Mv>q_5*@C z^=a1E?IBCGyv#~y+=pPcliS8E1FoWqPjEsAD4hD&o08?6qv|3yiB$`|T$KB{0b_c? z&+<)xMav~AnAF>RY~+qP}nwr$&<*0eco+vYS+|L2brJI=T3 zqN1)Us#ZOjPv)x3m4|Q_eD@lYA06pQQ=IrT=`6TKHM^bFeD~zQUK_LjH_kv|3%@r< zT|4?|ylJM6rqGyHi-J>p;5mAwTdf~_nK}KvxgVB)A09LoG=jzkIJ^Amgr^+$Laoh%Fn9H%ODVbzd2l6Y^v0(Yz zEX0zBLe3mVXn~8+-QMNZW-vzpW2=1v6t21&D7T<80{)J-JC4i~n$6;@TZO-KnuT&u zK(NkS&MV-t$3-~yy>-`qsxgp8P3gh~$>*=0aw&bL@xT82R_9{CNMlILn83aTaC4Aa zIG$P#F$|Dh9!k*B3VWbg@L7!uD8p{NrJ(^*<{x6aGP28atae0QI?)9VhkqcT6J%wg zA5_+g*(%iZW|-YsG^l(;;XqF=i=v<)AWOpUDXkn3ZWiy2!g3B+KRgw)LGa&7NBWja zeVQDld8pm^5;!dmd4exyUgOjM^tY5sA583UMAEkp7@YO5)VfJ04m%ugX-(IGprHTl z00a<=eHLD;XX|mI7hY4ecfV~NBioDXyd1c!~G#FK`}(ic@J4t;16KZpK7R`s;4^2MTRyzzxz|a%+q%39qtc14)#$lOQqeRGgKp zL-0QsK~bsNBn^(*Qtu3v^58)5#>M-Z@097HJc%+jVTL462ch1g(B<%7As+AyR#@X} z(+8{4Q#!_+$R;v33k-c7>ZX7QpQ{9x-87WCpN)#Y&l-7fsPlM3kR8j}`lj{vny&Vk zbq}o`h72C$PaQn{t1>pV{$EnF=$DA%bKfdo{?$_{nZ`)|mY0Gx9$q!b8&J3EP&AR@ z6NKy{gI3fo5MBrmfVvLTs+nXs)K83X@U6|#n_BGo6!`)S<8rHU+q06x)*4R6U|)WO zuVGyeyHg2SkS5}+<%Y(HJ>rNppUzaa`W{k z3crE#?Hvpj%T-M=_KcPCvh~D}@MEY~u*W9~O#fZN1eTA<5l4s#&9b z&Vo2|XzWO~vF54k)iX_faUoUxV0f z5--v<>;T*MuP4Uzs$O$~Pu4&&`3f=a9gJ4J`6RXUS zQC)-`V)04g@=VmhC-d8M=Jc<=%>4VJd%Jk#>CHuUY>*-HIVS42XF16C{BWoO2&MW^ z$Dzei;TIvK z51s-YRXITnP0#fXsQoE?7=Dal*BEhZB;A!Stp?rV9xu3-ckbzpV_g=TVD`{x z?y1qLz^j37%%CLB))qEg*{*B7x~C7^ohKIt*hFS=&E{kmL}$({F2Kf6wb;uTsprYw z+F&(&=l+!0?X&^JV#95kfgSM-(bVPVG_2kpO5_pv!LK{!1C-IU$5N3U;OYO%OR?oz za$&&;OG;d#WeNSkJ-WQ!C3r^Y$#&V;96t)tZ4VUTckO4ah&TWVZ35c?H>%(rd6nh5z}WPRr@AT*08*SqA_5^ z5~geabZt^MH&>0@w2W|4bpDQVYsK`B{8g7lECzX`^GO%DA)-V|@E(qmoq zDTy!iMO0z}RHZ*gC9!-vEVqTwLP)(Uz!?~QdH;mDKNjGqQdQ9q``81f#Ar-y|vc4J`6ag@yxR=ZIle=E@P$LglZ=q*gi!p=uxqy~5$yg~(M1vLbk+DO!7GE~3s?8&*BM5{=W`$^!#Bb!F*=z-N$`gu>J-|50@=4Q z7gp`%{dih6vIKgTMLJ)l_+Ky}$avTi{$==%lkLt0T^Y#TvlfkJO#h&C7*#(h(JcKJ zUquJkF=PAb03H(Rn_D1Y*iM{F(G8|rB0&PRV-U&VH>GWIl7!^cY!A@YS80CA4m)SScMPOf!|vMaNOx-ssh!!tWL0TrL%7EsVt zEsQ-qUfKkS2jB?efLqc0bVNZgB7XK$QsYPLA#~;sieY_8!pin~F}X?Mv{;k8RkThy zSt%EjY_+X-dXAY)2O9fy_0Fr#Vq98HfoKmVG!7jKI%;oY`8vfHW!MN&g%IzGbb?3` zqW^qVvf-h0G8Tg9P_X)g6>WNxq}zd&Per3ItdclcQljPQT#Lh(oC2~xy|szcXq#er zdtO(}D?)buZxuFQE6>DLgxy%CtYl>}=?OIYnBSD_+O7O~dvT-qT#D)Nq0(gE3htBi zvFkL^V&i=U_RGsBc7It;C4xe1@txXkx1ArRRS;pdjaj{(F}&a*p_I8@i#DH%CKZ=n z?taJZE9TT)D{E2yJh8=at@3AI`68wmdk6w&JD6Jsln?Ozrox4el+}~IPhly`#+9ax z+q1RW0eKEj{KhGX4f&us$85BZaU>l9F&V3yKJB*}+CugXKa`V!pSuvNqoC)n+)w=q zA}*(}e-i1w3S<6+)CDh8(=wN@laDJ>`k4G-2RrjbR3qKg(wzaUC%OKH_xX=Oo091) zso-HK9$jEFf7Vs%*Z6m-7;U1L*zWh~{&qfQH1khl0wYu|9PDn47>|-)M=T?*nP>qz zPtOS>pWA@e<@ij>wM*u?>}nE4(Apl=?)cB^$d~dqj$XxaYfYR!I-AiRRMhT+faO zA0bgt-Z_re+@F6me391?Y*I^SZx%V3>6|$EtEe0L$ggJOY^Sog$%!^Nw#@|N5oye2 zb7BH?FR1rR$MZr{zFcBIVC_x^+hP@S}F5U0%1Dd4smAlyrsMzrrGP;F_f0-w2&p-L z74cXzjJ%6I6*5EI1t_Ay+CC^FH#{<s7zLJ*(iv{F)gSb#OWk=O>c9sU3}W%PE{RPMyzN@Ly2MK6 zauMff8*R5KWtr{yWy`N~7%Cl8Kxi=?IvDH)06$w97CxaH5U{7#(k)9u$`KW^Wq4(a z0K!4JC_^#>y1{n$xGd_x)H>h-D?1wh=a9)nT+Z}_-?EP zx0P;Lv;Sq$B#^5oscb_}Bq?-X!SO;z!s&*{@hz}t=ORavyHn)Um;fh}BSz(xke}w7 zrVpA^VvRe)S2WAzK1N%Hs%h8_2EK^$-S6-z;6GqvZ}PtG->?6;Wdb=oBVk}TY*ww!F z<~%4gqeo}C!;eZfiqh3ciOTAb|gvX z50?~M?}6K$ai-_2sJ&C)zPw$Z>%nR(hW|Ur%!y95Yy)97Ro?Z^625p?E=sU*f>3Wo|7Kem?hQ+|kA7tcR zDTC8r`&j{?Oj8R`NG5Y0|NaL)E0eUvD`$-AlKd*3N_0+@N$uhGZP-@PidRr5;Uq(j zl9_4mzjPfEK3_(`U39}$hexibRa3m6FI%^WmW(fNb#ow(Nz z@4r`D9dBknjY`-LCwMOJh0g15$f0N^;0{GE0U%Qio*Pt}Rn{+Q2g6wE-ypjhWbT4w zj2)96z?iDS6vQ$!sGQ>0!k`_)4gl*1iR61t3YdQ{#EzmW(IL7iR~zKPUa0NBrf6o# zx;&U-a(iVy*^H!uVfaiAUD(T-k3H}A+Io4M_ zEkjd1eUKqP5vOsXGNT_DU&7sg>%&mWmg0+IimHRPSoZ>Q#UW1VfcA8paN(izXy9zxD1SUsu3Q9k(N&k|%B@ytK7?&1ykQv5*UZuoWIU>zPX4~9!@eD##npIOTy8hx7mxE{n4jWt{ zz|0}6CFiV$zqH5k`4i*^1-I>_=EpX5YYGH|3IqgL2=NhKjxY^29A=M@1B*Whm}F9p z?R^;U?|oLbQ-<9s^bN<@N|43fL?~HlUJqqLdiB1J!B`SMLD5D?w)F(^AMC&1%Nfy1 z)yG*DyyKGdycPo9&pNrATH|vTGe0iZy54S zq)q+BVweE_WS-0KYX9JiVl8X$5@7J3)d(CyVnq{@J726D7ydoi{1*|WY1?lQ`4Y^9~<-B zMO~ElLp2-FsVTuF5|4);Za^A5#krIdqUt!bUX^k!G21x@lz29KMr^oA&>>(@;^yx} zLc^=HR7uu>GWyYUUul|%?(Sp@C6m9@q-+GNzKK}m!On8ZbQ&Iq@6*4tQC@?PwtILd z&;Pq%Ot^6^SrC}JqB-IZ2g0;o}b8M*A3K{#9QHOYzbc_-8Oz%cT{+XDtiini`7 z|5S4=6|Hwoa*Zr6x}Bf)LMFBq=zkEzt{OzkqQ)_SdWbq(;4rFzN-{`onb4Ai{SD!) zr;ZN5^Wl=Q&bT^9+=3hrFA`ZBTaJHytp#OB)u@oGTR+y}2b>s%2<-pfQh#-FQivNNGgzM~c>-sk!u-#;k|h8vIkO7@0KU!v2nS!(|}HF|v<;Xiy}u#NoZ0seW^9;eGfNN<2HR;Yi8uoIEkWMMw2TDTov=FAQ&W zsVI$t?-jOYI8vQ?jPLM^E>~#}?vCFr2&U~nNP;MgvShRN;}hp9t7qav&8ZPXOklTe z8r6#CHx~-675={j0Q&bLYDlwhGM4o=rJhsZ!EI|>+p_KU&9K|DZgi<8k*K>a|I4dA zw$8CI%=TQi6c^NBBj$idk8+N$uezqGG_gV}Y?(c6;NSq(u@u$uk(fLD@4edOjx+LY zgp*>5#AODq4VR4K3z;cfzh0)+YQfQpRrm?K0(Yw#X%-+9w@e(wJ-e+YZAeU>&s8Jq zNz{h%2)(NxUR<_M33pN@V2UG_=xeJNRAAIprIM~g3U?*=tCgUiOFtW?b3j%(0`Hc* z_lxIs3(6FBkScK7MJ^M6yzlLS${D}lpN`!$My zlii_9M^NN(`*#+q>JlcJ7DxmUTGTS2!#BM(TQ>P=Q?4&gul_i;tvg< zXLWOIl8;zj<&IRl>_L7d?9Ln~yTVo*)^oSaiPEX44EA%Kqs$c5JwsYBk#iFLXT33c z?f^E1pD^%I8)pOU5fEp6Z~ukjxx42Iv*nyxK@ewYE(T2ag7gnQi0rbSTJ?YWedq9O z>`QOaZj7fa9pj8%{}%SZ(dMhNFfxW`eZl$D+3?P%k0F;*n)h^=Oiu#D;rJ0wkTYRS z&EGk4zsI~4BH=mD@w>Xn)eGLVzgfdbmD^>`TE-S$SHEB!^^{4aVgeL>Dsup!y{Um( zvEY;_Bet zcWC7Ooo-YRs~14A#JvbG2aOWqMsQwxI7|_Dt8?+-EP62~COz05 z=pIqE>_cvp2ov&(C@oTmBmN?z=>`0q!!4utJd^i)sDIu<7VAipDU0PQffbo#KRS;S zVYpC4EcxkxS)$iEL7ZuI(_`h6;!ZhvPeS2Ehsmd5ZM{8#&E7>;Qvnatp0_hvQjfaL z1_J_iHhxIKb8<&Wo(J8jsU53Z1P!%mQwCe+W@!ar_1zETx?neOdLC7CYB))YvF+iod`%karcs&P)9{z*54jRsnA za`(Pe8r6M-B?Pnm**mde2z+f!Aq|=Z$Qr~bGWKxf2R`&6KJqGiCV+s*x~ONkv;=H_ z58tmfCfzDzfodPr(b7+V824XdL-((ES_Iqegy}yku*zoj&V?;T8;pS`yMZ}Ha=C~) ztjZSw%R|`hBi)S_$?{cbQ)jVdfKsj&0+#&6mSdi?#E z65D+^>n?jY=I2&UFgII!Dk26#IQYj}4z#)#axM-d@O$rAuLU4Sj<@xhe8HP4{a#4| z>OLE6M+cHVA(Hd5kz)KPC&rIcaK8z5F5I@Yz+`OL z;u<5Sv7lD;Ku$GK^`k2zxY`VXH^@+=wVhrQ1og5dn|t3D&d*(-HhCf;VYvqci>URCyQNcQyaG!o-*Exg7-{42UZ@zJ$5XqBo(nc{?lsZE+ z*{s1<8xmwDJ~sE}eZ69}&@L%+iREmi+YO=CZ7~=ZL-C#Gsp!@yxojATm`av2erDiw zilC&=iGM!DCE z4Z?5VF2U@O3fl7%bjhHTDVnB|Tooc!AfTaBN~?cD>{{W4$jbs~3n} z*8au5h|B=2b+9w`;`6f_lBN%vSuK?=;QupqC<3W}R)`Vv8728f$k6zyQ+yq%0?~ZP zy|;4>T%$5+CG-qI?X&H2>{w;gqUb8we2+J zjL#2YJtGCT$7D#sNA8KoH=q&ee~%sO)w=yxe(-qA+z5{b2*?=Fb=Y)$b8i0YU@`q? zdZ}N@uiAUK)|4x}t0+VR(wt=}h9a*oVPY20lHuny*rmzIQLe>k`oW&dzi~QY& zA+Xnz0kz+kgxFGlwjgi5^)Oqg#HQh2-~9HiMA4~|KZPrY>8`;1$Y7?dbqA+9rZ)9T za;5FFeZk0Z92Qc8ST_bSpZ$$WqltisJ`z@6a?vc@?q^}d4?9^k*0=6sT`sxByXi<2^-zwGoLFEcfp{ z8W2yj4m0Y##i@sF4Lw-v zf>e_WSEUp50eIGUy00z&U1)1?^RpClLISQqk3tr$L(HqHZ8_31%rPU2)6#{5>p%ZC zQlQ6SEIcfJBaref%aUfrl(#EXGW^Gq;gtA)R9jH$ z#6|h04^Rs-gmnZkkdcl~Ch^r_y(H;#y0{NR$~Iw|j)Ip2c@|f=0Su#YIl2f%jAO%< zn7)mpy5*TV4p5{wS_*)`QU8bT%rK>SRwF5Ks&*GG0-_$AA^)E8VdkFT#J!@}H3#m< z0s`WH%LIU8?&tvl!4`H^$7j0cjW_0k;`a##IE`bDcd1iy0jdv4%*j-3+~;edfWSE% zx8vSz9u>LwZ>fJWYEmmWd_TN|U(C6=+E0y`Mg{Mlgti<4*_F4>Y_r%712W@~7xmL{ zbCL|ofz2kQ7rAI@hRrH(mCGKk42D4e$APP!>Yj_ET>IMjtd{-zmWe9E4Um=dlhtyF zZNlcWcp(*bk-U&AIuq4uo%oT&dO|>PV-|IVOm+%%uGV2Se|gzf?MIBby-|!-HFzR} zT0KLvDxw?^AH}XlIVSIS^y(}?NT|pRq5Cw>dE2Q8hXX&Ur{h>D&1{%MZ9A5xu2Cgtgky52{@q1s z0YvH?e+?X)?6>ue_CL}y+Qt|ho3BRhWy1F4+%B`)#oNr%EN>y=tyjFO+qjL1pGvH& zZtT4{EL$Ts=_V?gAN{X|QFdKHu~KqejSZK%A}q$a5u zc+*AkI=+Js21j(vo6oeMPY-v*YA8)cGix##1T8EP6hB%O=477wf+ZLc8wO^(D_Iim zGZvqMy_u<#px`Ai%z*Il?zOa)?!gWrWwi4FsV6yA_i)QWW!4~%3tSvCR0{mWsG4Cj z?c}LK=(PFk#?#@yo*bd3xAFW4cnO6I_qt=Xdj}(P6F2S%D&DC%rtdTZ(f~wU+y8N+ zP2Vfym^lx-X0j4>0dp-axAjAU5$PEU^(aw`K3|%)y#O%`m!Pvx!Cz*dU^us)KS1-K}(7*FC?@tz)<31m}|$VPx?1)I`N@?sAHOW{b1_c$3P<1olxw-K6K@l z8dFfW~^ryFbv5$f8hU`4kwBy6v)ho>!*B5%j-&W84G^=A`D~fx}BQnhUVyPvB2ymD?o&xn1;g)_?7~80y?d%(AcPchcHAy#j^OEr6wy zTEZsAv=Gd2i_Kit^yPnBik*pBfbM(KmKVs=4Org_uRlWAqAZ_%I)^Sj9Nw0MoN%p5 z&@-?D#7GxqpYKSi=pCxHZcwCrQkmm;K87~1B6%uTbBJs+kG;vcM{!a);5W8POR?Us zdi#Px=T2WX|8Z31V@E3Y&6+#-NfCKKP@oW9TXt1EF?;v!DMub3T~3?}UcJ_ZS1_+n z5kI-`p~=XjO|8g=l%L}m$EvC*_fz%DLc7g||!JOP3 zM7vOua7U55HW)xnvgi?VMFG-X7@K$?&?mFTYQodHqJnUnh;*dnz5^95_N%y(7yEg_ z_j;o3Jcy9LqY&m~Q2WH}{UsjN2wItm2(_(?Qk1xp zMCv0kk9TT_ZbnnX+wjSp^vFqBsZ*tQmt1!X7O=@YO5ZI(M?p3(auk?W|FN?P>doUI8Hy z|~zEB*Mf zLdc}Wi^ijo6;Dy=xoi2709*$2w$5YZ{#4JOcxuAYt*}BAYy)=Xp-wE+gw+e$Sw1;u z{!yv`{yjgwU0-zP+rm9!QM)9WI=h~YY;38?!d|jcpGHPxU?|SGiyMt%_2VfddK3`c z7X3D>CNhJPaU^sYoq?x9XkNqpC}jp7R>2PwWy>JC&Eg&X`bKkeZ&XMK5p1OEK3#f6 z5UlTm_e%fmwgc81_;IPsoRqrWDfk^Ve(i(k@D;#|L`aRKD&-l01)5vn_EVZ?GZ?I)_fut=waF0+#YVt>{J#x)y+T8pwFS*)t0!1!z)gP)y4e0b zJzyCXyGup7T5o;DHo=!<8GjOaz64Yms9V&a}Eie^eLICW!% zw2v)0-heMe4LxzG%}Q;z)WEH=WB#e!w&J9f&R?TUGBTZ}A4LYgogc*z7S_P40 z@l#pgZAb_+Q>rBYm5eeWB~|ik#wovG9ML~8sM5<7Xr6z-rjN9e8fV+Dhe1C4J27Va zKO4}1TTpzsr~j*v9Usaxfy2olwKuAKY9pg~M0Vqt5r<~6Ncpiq!qCG{p;okAfK#c# zhw=q4@nL_xUr+1O)fM@Vg}6T)W=yUyNfo<_7g^o3%U>ezwO>Kw~h_|rL zec*5DraU-#HnIZ@qah256|PK4gxSyo#1?0b<@ebntC8df#WLb7{;Ag(h&DiP9>a zfqWjlUl;5GjQ*2?#Fm2$hx2YW4?WWNC@4$H37MK=cH%%>4wfiW@?Im^=r+Ql1{*eS z&kMWt{Ywp zoM<{=#>lrtf%jK&9du)>z9VPSmbQaWTOSOQ(^k|_&VcZ03R&D67PSMu2i!%a^ zRAh4u{lwHAURdLV83oEUy>ELR2bh%i>FwOXebLOau5 zoeD+N-SF7BfB52?$Hs7CHMPkOGc?oWhq4tR3b$dTrr?mJ?ySN_klWev4&_Pz?%7f% z2Ez}5dc{2s*jX<#cE4x;;?UMq>${V6%xM^kZY9wgZ`#Lmf#StBRM~aE;3^;Q%%>2v z&!{b2^sy+o?4<6Q9K#dcDK@XX&ah-1HKmH8X2Us{lGgjP7h@`_mT{oFO7( zT5g4`eUuiO%R0i*Ie-S$(!RodyL)Gx*w+uY7k>BvWeo20f-9%D_1w!(KFct2nW2n>bNf#(S*7%VeKvvh2 zk3Dl~BwZndb&4aEJy13>biHIdwBhxL>q~aS%-{)$MHUWQl*kj~o4MrW;E?kTyFMkb zF-4#Ji3l8ek|~iwrYq`WMWb*~AqY)nWWG*&zmM8$Y_!8_WdTUY3MKugJuB~aBCZ<& zb~k_+4WOIcu+w5#0VITLyr&AJ;KrB`9TVwlsoFKM+M0z$AjX=YkS&V4WpePHhaDx{ z@&QlYOLMs;^_tzn=`fG#0b%~LNT-WHAHT!-=g_Rp=;GmJe0ozx*d3i;aZW$cA7vZWg`Gi2fs91nS6qW%_~OE3c##(0jopft05wkALi978 zOB|aAJjkI2eq$^W^$Dbb{a-lw{(n__@l zD{^-S>R`zoZrhZ3a}8gLto`eQQ~X#vmFD0U z@oJW&Ywhik{?7m|mP3tJ)5jtC8+eejkb9^v@qmGzPE#q3pYBUBOIa zYK3bTB}XItF-ZSW92wwyh=>N_dd#D+Z{So#4RC2H-zr&4tdm}?q`#s#MMO}S&wRbV z1YgU93{m8hHZN^`a`p9CU=+z3p za{w+xGjl#9(Y`UnlJp;x!|YUY*t#R8-8KwsJr4<%{?P^p2#EJuh7p!9HpA=NcAh|>*6d2nGW_^ z(i*+dXN1*67HY0#EUbz}4Zjf7J;Q!J&}d>0xc|ro#$*U#4ylv3)mZE1HAGl4cW0=1bKd$7@(66sTv>>iUIW*2AT7Dle4Za*HDTo_Fwbar0LF z^Ln|cn>B>)soSu#hZpOg-9v-OYOLk)ZA&C4!NqyNgvSje9^s?Z=bc`6S|T%fhD0+E z7#MKY&9ii43mlqUC?w6(s>R5E99(!P$=xwSf0q(pi8h^t>$i^l?Uiv~ToY`=ceS}6 zl=jl%AycZ+p~jxyZJ71j5o|e87ig$FIVo-0N_n;LfankHd1@sAXk0N~QB9VyHimOR zE|5aUWoQYMF#}tD%^d%Efa6ed0_0|^0jH$j$>9o_?<>d&iiok%v;SgK^OQC%#CViC zFlH#(xvKT#_XoDfGWCI>8KtbkH#U;ka}W`eOG=)WKBF45mX*1zZx*l^VdIHWv6v6Dw;5 z6M1CQHW64m8bxt4#wA(Rn-33WEfT|?>kVpe9qLMQvpqNQ)Ca4HNu3CB`Pi&^{_Kmz zPRyg0^0Cu}zH*XLn3&YA^M(lOvT-%!OYJmz;EMt(CjTdC)g*z{t(% z%0}oHu{e;u>9A#qab#8R3p*bKFJW638+!e$M4%v62#C3`j@YDmNTImxF}NJxi|Z4P zNXv!VE9e%yKy-K|1RUjM44#4?E#TCQENZ`1w~Xl zRYi4JPdVbFs-EcI9;x#lj4vs_UBPr41@@H8)PM6hGeGcUT3Z-u5MhWs2(_Z2CO44! z7tL1V@C}_Aaw+Xf-VZB>Cn1smFX@?BnOzg8cOyfr4gB{Q z*66cKvO{nFR8D8Fqsb&&TN8{&`f7E6BqA)^PpQ&ls6gLStsO?xM=-~bUn6S6PGV`U z?mItqpV#HKe6P<8N%+RGgj2SaEe*^E0?DjT;bF_*uI%h`p=2MZ6RAh_sN3leUEO~>wCEo^(94QtRqH0Un zPnxS-haPsSHn)1atX6evcPGc@r*3WL*us#Xny!^$oj9?IDnivj@gO#Ob3##f-Fef& z3{sMcB;}x`h5!&>lWS-S0N&MrcSKAZ(97KxGIzFcF-`(aH4DGOon=M=s;T@F50s;_{z z8FQ8LR56mv7{Mj^#|pM<3D28^RN^)L_j%w2#$i&9V*$>o740vnjtPRn9}#6_Z1Y_8 z{-?ld-hzd?%4tm@v$>jTOvEu0twR6aH=8&R!eGtt>Kgny-n@}Ihk-?tUyZplo2XS= zLD!X#k*%8LM#(?b#H0G-2pjn!=^`LT&a7$4K+HtC1*-(UXo`5{+7@W31MpNjZE#ww zn4cjNPxdTUut;&;&(a2(t|xRTUb%6;^MB6`Yn}Y!7OD!mQwINrZ!1Ww(M=LMvL!N& zP&FHHu5P1XVB#LeYHQ_fS&kIBn}LzVsKKFEoC*Tox*Q}JB>yKLgF~TcFaGc^PykA@ zc8b*@j%17MIiqGV74K)yz95jnHWXI{o7UAK$n^(j7Y^9gTe;dUH_#q4SA}75@`OR> zMzTL$rj)rWAJ<|*v9$F_tO@%>Uc`AY_}^Ub=WKl+qahlSQbr1@hf=SH{bCb9lLRQa zIVdW%mUcvSLhZf@jD_2J17dzrQHt9v_DVi8D3PEJUUQHSO0%0QnbdFXi74EP$%P|tTu9Dp+Fj7>pG{>y=7SmTX-{RDs$T3egyu6EQ z++bPcqzb`iQT1G;F*M6%?Z)kYx~=&ULEFQ~;iSJ}02r~hp{@f4Ap+d+{thU~5zQe$2(c`DiE$>)2^xOa3cqSYI3wCttW?$Rk7Kura0hC= zWhw>Uhc4kaD7qFl5dNhBYZLQHTD4hyC|hpzsB490K-SsWXsVW=O~X%w9L>c}JLKCk zD9ltHw*-c%?h}_zKB?KSe6aiU>E;TquP?YtdDc0 zB>c_!Cj7`hd|160C(SXd^c=Ql=H}&;w^;_I8!ynI<9fY3C{{kggkq0H-P}w0X;&^M zqy^p_ZMO03SCC5{+cDLn_^8O!FsQff{aqSdb=3)A&2QV6FKM7b=~1NHBzaLzSYDvP~qn#L=5-R z>=S9^@U9O!_2wl&ClS7bE_>XD&A%-f-p<@*>33Tw>?<0nH}fatpA(auCnrOi$Km}k z0K#HnMlO~#t&`wbHsp8EwL8@jbY1Ub$q(^pCzhj~0F|k6LXVeVG(;fYUqIKgqDq&~ zIX5kF51D?AQm2i!*?+&$P<>PFix>Ik-y&_a7}_KDorT+>6u$}^`f4nYC~pdmxGWGk zg=?tfu}84$hp8EF`<0-IqypkDVov6pj{wSaV`z|z?$1oXHvE-Y{N>CI zjWmk1o7f*S241r54<)GWmG{< zh`p075g)IlK5L_Yk$Q)W$!(G@AT|vu>uYqO456b>cCqUsY=;-<#P1HXL^_~yWdJo1 z4dM{I$yu4Ii)##AglC1Gm6c$%4%Ncndu|qSs1sf=nZXSg5dr`vkie+?hhI5aLQtTj zr3^jP92&NBeqh{|A_l1YD$1AdcVcvs5}~*tMyG)og7SDTHTivy#yw>?0+_;F^BC&M z-SXjjhVIV*0yTa%7ME8a#L>^3?N-QYVGi_mz&8ozZ+y$yL7Fjg&5K+&&^;PzU6amd zAjg$I=EF=D)TJN;E^=2pUFQS%eebYG3uUb_12czcSY@8@lr0!X0Hp8zr2LIf?Q4IEp7_2k*V znO>^vc`C8L>QdYq;E2$~__(hsUL}Bg*Q4*Af14T5PZJr_KgfFLIoecNWSu*aq;H z94eMNf-2`m9Ma9x6cgbkhRvp)qEvU^oqye8LcyN*4IcoV9Cwz%ems`k5^R)sg9Hs1C`zchhJQ#K^OYI#<5`U1bH$VGxypFgk3hPuel3nW(k;WeITNhMWSTd_^D^@=WvurQ6~F+b}+g5;MltuJu_G0JuT~fVW>TJaK1F@t3`tC(v09&ZF|)1iC9EZhv?qEG-`&u>GCB#0mgTj&><%I%=!r z!Abl~C(Eh1Bdx-TL~$U6*q2jhkNhT^&ER)VmHtkV<`u9XPb6>F(imbM+YDv(+G8{| zGD z5Ac0a%nTYPI#HqA2p`cUq*k5t{@I10V1L~grd8rQz5fK}J<^LPJ`ojm#eAZ`+DJ?D1pHCnLFJm%nY zimKY%#Y4btI3RQau}maju6c1FaX*PS1ogp$jan?OfMTkR8$nBCK!DlBaZy|W+VikU zBlUsqJ~AGgmoRU_)9^1;;E?4pi~2sRj88vz=sqqITsznV_BBACc$64=cSdFsCF2on z;9_x17Xqw^&Xi|fyR6=*DboG30Ou%4JUt#0ol8Ex34hlajnz#RSu-qn2CKw7{1~tNP9dhsGE=3N*DUCn z+J2wzKe`bYGs(c>TlltokXv+Qcd7@JBY%}eQi}_ahHt0Gd~e6u(1JNk zQ@*smP^9hr*+PBMULvWQA9|SitMj(dXwTq07bw=G=>6S#cT#vrze2M=HI%>(_sIu% zxRGx_1eJOGS<)>7lL1|-@;1wQ5w(GKm7oKe@(iuB3HrN7qWo|i4iq0<0Ly7NBoDO2 zl?^FE-bVgH<4fcaZ3>yOSO+ekgfg931dn*j_6i#S8yY~zuj{mAJ~8Pt(PiYpECz8i z!FZHA)3u$emniFXa@<5^A%Ypo?m~MscOQcs50E5^O{-q@D$Edso1NQ}L}nezkS zta!y=Lku_^xS}UHTXknF2HH~?@@0WoXYU(9a2638pXGoum-Y5vr%NLG6FMH_$8>h- z1EW&p8}s^*I@FPkYGqB}CWHONWyJ!a7Rv;+60D7~Q){+-#SW~9*J<>1gU0cNjeeIwz z_ZX-ISArDZXK9?W*T{zj!T4H&GFw0RsH!^{scv%fLu;a0WDp~VHXPww5Ku_}2~NaN zS(T91xC>uifHD(m06Lf8G8@1a+rQ0a4~j=Z!kUb=Ta?RxpA-S+*ISlPUHMkgq4xND z(1vE*65NMgGvRc8gY+gMF&Uk}YVPzu$U1F*QL=GY0^P5qe;S?a36UR#R)`;6);Kd; z)caVxLHh*o+3`r+Io?>OmWCRquS~2_!pJAs-fyq`#KzSKQ(wtm{T`EOu0v?0pVrcb z{Y_zg<9;SgsKXB;cmx`KDN>YKHXBXSNf;B{8+g)1P>Uj7IWIcz zp1je%!lTtzl^MDWMmmLnLr zRq9&R(b_gmCJ_UCoO*(N|B4D8`fLDPNNYACp8PS+^CkM>`CONI4So^dy-~7|#ku7^*IewS(wlTZIQX^42j1$j>)T zWJ#9cfa`v=iI{^NNJ)={tUxFBDI1iB!Aoj!oNX11-}r3MB8k#pTt<3Nxqzis?O$#!k|}jpeu% zVFT+Nh>mV|c3bmqH&4himR1gSD8*&>0_KIWKJjZXPF+HjYd!ruTD=CxU3bC+LqE%r z{OlZ^7%c4}byPHKI6ENcCVz&ZO>34RdXp8R%&d4`wzEy_62)Zyh>81Igv$6ELTt9P z7Zqn*ycihO)k%yTuQrDf*e?s_%D~fx`i-?@2FNS+A7L@fKkodX8x(^(?#6CeiIX($ z8Qf>@?%B~Qn6un~a2c#lejT?Z{w$sZy}4`rwzOWrr1Q9rV+lBMS-L5zx(k?=b{Wro z0a$K6Vxz%pA2u2mJPPq6vEo&7A#qh}tcH|f<2!`GFAhV_P0E8DEX~uBSQ7XX?pdX` zuHDum9xqXjYD9L|=tp6J-cuxQ+v_`Xio4deny!%++91@`A=}PELkqvHW$9+CTDbvyEsDdXB0K9)U9Yr8{3-J$9{4s#0Zo#g zgm2^F1UXO)2)K!X?%nmfi{2VLW~(*#tH{^E{wQC4YMMz`L8(@xy;49})olpxAkZyq zwJ{+tDf_7zic)^?qx8FsGQr4D0_f(U0Q9L83Wp|?-2yXk*fu(ek{4(e413fi|U{>N7l@5WrBNzfs9JWs$OaQ%a7&-*g~sDfQ__wHT6 zwNSM*?sc$iU(E=?R3@OpRti zv`whp)LxQC?_JM%Z4c)mDh5KvJ^VQ=R=IW74p^giSuOIVQ5-Lza+PwB+M51zKrC>_ zU7&dCK3R{ML2RiAv33p@x81y7$1ElIk~E@x6uddV(5H)n=q6(7Z|q}+1p&Z2&(AV6 zMZnbgJ&%lS%DlE@ljm8urIB}eDbISh#OZmQI1?1z(|D87rtxY`0{py6Wt zpN1H#2N_0C4O4}0#-=LOBhret(%bKJ^pnnZH!$XS2^6Bi230Mu?KH1v zXgOS?=^&6^UWM*FGJwYQ?RFLbKQE@-%&X$Og)5(RZ^a)iF+1o;au~4SiOCjcfJaOY zfVT}@(t&9#)OwhJ&d1r*DS01MclR2G#c!7m4NJ!RsdF)SsOzYcHGz1Xnv`fWHsmL2 za8Eod%NEJI8AjHyntLt#2<;rdmnjs0tZvZRI|B0xE4o@qiRn&FgBR{CXctta%~<$5 zp4oTVVQakOq}s-T<9&*-4xxU3-{JI<*sWmcy3l<_V~Vik(B<|g4!(Bm;sh)@s{ zY_!WyqDD93#0xG2E*JFn62_iY4W0J!B}}nV;s;Jx3Jsa2XTbV30JuJk?+s0nb32t& zmRt2B$d0b$Zn6Aqhi++nj5D%(u&FT&Cjs$%&I}K)L>^*;dQ4=WliIAvg=**@rmK$k zXs!&25EwpTmHZw#yw1vFK~VC838BBxf!v9cuis|Tpsj}^TAU=Pm>!3VZ&YpTb9^PT zh6ZZC#K9n#qNh}~K1j$;l?9%N0k~C;QGuhCPf-3Xc6xAA=?+<(3zMP@G$II#^Li%H zRTz+OPSlM?lBawFd$qqd#2F9SZG{5Wb#2_&yh|eOgnsb!P}6weP)!0u@%IO4t!|%@ z;0w}QD6}WN4aEhW$X`SI2E*E~oVko{_v&0VT)IxJ;#q78VQ61K`-;-LH3@ z_{^zcIx@UOW&T`4eH($yI3=ePJ&-*wXZIH^UxS6agK;MC*ca=*;7~SuyUfI7q4o)t zqbU02!`%gK-IlJZ^b;%Zx8H-dz0m_(g11d$2hPD`mzvlbS58#LCWN8j?#{UDw&WHv z8lgJ;1%L*4+zk+q2muo{(PW&yE)HOJuH4uC2@>X>%jC<8qB0thT7WvFYs31FD+M$B zWCfU4feuC~4b~=AkEw5!P6lc9isj)!|0yu@WJeXuD0;D7gt(&_z8nW&5ElN;66*Q} z{ZdJ7T#)I~NXGqZ>Jx~HLNDc4A9kS{s;ci5_vYeZ`Jv;MtO8@vg7ly<+_nx;>!%ct zJ$0ZQIL)n|Dn?fQf#xsylouW_zBYqwO+Ky&x=if0#FcTEt&qD!O)WNx(fmR-TAANf zmQaj(zdA2_6pmxW)EIc|Z`&sq$0K z9K08_tx;WLq_TQvT!hflu=T4SDD?*E4;Jmz%NCgoM2wn@?byB~f!AtZp%+w@I_+6z z@`kd%N^*u@eXD3Dt@B8WH!Zs=5EdQPx2?r)znAUNyA|lcqjki_oj-r7;A-GrVu=(@ zoKLb$0(U{|s>Jw0(6d>fl`3LoDOMqMfFU|W%_dcgufYf6+@Z}08!Y*#(S#rGnRxkM zn>IH0G`e0?8)Pt|OoM}#K85ruJpSt{sE>(xA($#0Sf*WptzL?>3=qSQ9Of_cG)CK*v%rzX1;6oHmEjsJ!)&u# z5;z0_87zCT$l7?m1I{6 zhR(Ne%nXmd-xtB$z*XI zh#@U>h<-9Ir=X?b{rE9;OaKtw0NAh>@|t7`d&zy6DR2D1f=I2~S_aZiw=AS(X56>VSCM1sr;(&QjS#w;)v#Lmw^v|=Ymp-fdV~de47@hMQ zve|X8JRnzGewOJ`J$D&yogAZXBtZar6V z^Whj%8V;B?Oydxf2MA zP{sKLAiNIY&QLQiZ^*!BRi@=q0%E~DF}|J9j*F<%L#n-$IQSU+BsCrYcHaH``GIBW zR25o+uq>a$&hOG7uMIAAeKUnoYs)Xmm|}*YxU) zto!6NMRcH=x`EgcA0IC%Gf3dmwE{qOC`OUtchjp&yNV+p?C_*v=C^QGuOccap;w*Gvk|7pji6Rz zNY->*oT8}qG3kxy6h^0ti^cu%>@HaQM|%>@k``Vqf(67)T*6W$JXskHL=>InhVeBeydnPr)K;DZzX68va^TK$?UkFUvG zvuv>TWYopC&VNniVaP7Kb3{VtxT(AR1Ucc<091n}N!*Zig|{#j|>uH-CJ5K@iyw`?sHbAi9~gjVfqGo(0W<&;=EKqroZm24)k)z`?uujIEW|j z0c|9S_K*p{&e>4baL~NtB$X<8xgi0%4aCMLYEh{WtGXw8ax~QV_^dTOk(mVej%(h} zW~Fghgt-a&E(DU*^`3)jehEFK`=(~)NNyR{@3D>%x?&WD4|QnXK;0-=Xf~UM{qGN= zsLjI7Cm0&S!?p>#H+gVZmo7SpiE0$}D#eKD2JUXhSPa;%)^M@n=PZ_eQ&KQZaFA>_ z3DOBu*#K_&WS^^=em}=ZNvw^L!g4uXAM&k5(aPQNj`?S|#vn)Rmi7X-2(`n7-}Z)2 z5NbyjAnqUVrl|8YkxTC{apnS<6ZA0z!~MH+pdEn}huJXVLAtW*zAeaic}+AcVTsw0 zVmm7@9hpC)jY-1_g{x|UK#J>FA6yHqJi^U0@`7NOv8WK9za?0Qzb$4IjQ&n#1pvSg z7Ri)or9=B_*pJ1Dv_%BlCFl$5A|O=&%YNqgal3peSwakC5mxd2z-s~6*d6bhN0NMY z>PuwDD%LiBLchU12vfF`b7k&NtOYcFIh3iigF0Qswpr!!e1MKIL3FCLjlU0p(U>!V z+>zcPX!vm|$>-(nBs1q1tT)PEMrU!EtNX+RkS`_7n`~=`Bbm-y03$S<%O4tX8j`^R zRVS-_#H0!f-fmts2QdN&+A|BmsskHfmCjCefgyKDy($L1cNDPzID?JZ)-`#!r+Mw| zR8o1ViaM)ytI_%7*8&uFRLGzs4!jwF(1_nv@eHI7>ZHHu40qSGTw|Ukp*hQWg2?Ew zVXC~B&Rf=#nIdBI4A1@R`>Tn>h^SM$O{IJVL#m*I(@b&~M#UNAf$^?~Jj;0tWv~P2 z2*3iE(p$$R1aMByrjB`Kp&-FzEb^CgeecH9-byp38Y=+u56{RW!Z9OS)#8B8?pYA} zhM{hxY6ytN3Z&9nVn@E?-vv?>E|p669MEx${ZejgQ!Wg-R@$k#C3|5bE}~nY5w50Q zc(x&;Hy#*#AsN?nEyZo$#|>rKPfysB$*lclg7L8+g%OOVxrn8^_vMlYyUlsHlt`7Z z0axjJ6k{G3=V->@5qtJ(h2FO{&8jh$zWJCIekfYDTIuK7SM$SFWgZTEhG{6UwhF^* zgv@>kuZ{?cGDdhloL7Qin9izf0fbZ?>V^Y%uI1x4u3y_{MByun82OF16Yab>@)XoY z#nW?1#CRh7E?V6ruA``CeGI?41V?Wd#w1T3qWfOI0Iw2=!X6|iTE3TqNoYTHZk4Vz zmg`#Df|X&JZyu}Y!bWWoVz!`Vo>amxmDJZnT;vFT;>W0@5EG+BwDfp`E)1t!WPCAU zpeDXxk6NBq-6*`OGh&T9$o|DDhiNrGthO!sAY26?hW3lNh1|3a!%Fhz(%E=&L}=h6 z@HUz!iiIUBxm-Vk9~rjQ4YnZx%3$4>N3$Rxh@Zu-4f?e?wlhF0v{nFF>+{{o?!^3X zC)$-q;p(NkSwq`EO3}YCiBFyfl%;K|ai{*oq}|ss)~cK-`?SK_oI@1gVezO{F#v{@ zX~ji;m)9qP7C|wf^Hq)zHuEau?gohpBBW70wJPr8{S=XIyn1l&;6U47O_yfy#jc~= zq1r2QHL$9{57f(N*$YAK)^*G`E2cfo%=fHy1{F?dw?S=(Z2W~n68t>;%X zMwc}i)6lPL&Bn%eOi=tlxICmF`s>m7E}-m(7ljr$nJ*GEwYI|SS5YbPqcO&D@gF{M z-RG$!Xwgh%*-&Zw1eu3YKXs2wPc2+D1Y(UKk`S{4Xu8=HY$ePB3l8xxnE;|Jv7I+= z0GEP;W=c(o4K2MK-6FdWq4`cqfwThy%cu-R&8Mk?YXPOB<|OuqA6Gp`-Aj?%e8BFa zX%iqeoArZ`7c;)A!!k81n7x^UYV|kYQo%fki}9mM5u%A|e9NC1o=D!bn)=0vkEvzKEOa@a&ss6{n#X zbVBWPcbyR-4_t3eRn(p+?qEeZP`E|TCeHW@Vx-F*EyJlr^U(-#k{I)ik?&(RkjKeI43HJtim2L;?=_!snYKtbi*4`GDiYi?!Rz%RGuE z8x*?Ejq-(*WeYIbjo0PHW%nkW3-@W*9IqkFTq(+5%#Y|6z=Cw~fcnVf>E>ax@vbwd zA8~w)qRV*skH64G_#ODz4yx^?U)c+MStRwx+UyE6_v(zafz}}j{L8tR>Qm(MrcJtK zgN~$J`mfG;6LvIhi#-DFQKfRuU@p2G0FiAjC-_t>OgeqBk=NjVjvAPMSSwGLcY}?@ zD~Uk5njf^{#&$}A!vh-xXYRg>MXeQ*6nerk5LBRJd)l7t}j}BiDux5Pwf*VEyhPvWKe)lG|?CAYMy?X#oxu z@;dIOZcY&>b7n}r`Z6b4*zdE7QFYQ;Ol1S$pCm*q{PNUmzB2&~%-{uuQrac7un8c2 zVJL9BdBHWEox3|m@s8jE&{=aO)AAUZHG%{2p8`=Er3o2LWt-}&y<{cp#wx#i>2hJP8r4O`jvMBfa1)U zpwkd-sujWsTb@Y_pYeg-ch6_ZsjhV+l~~5;;CRbvl(zzZl`8G3 zP41jfe)%9_$0aE43)cs?qM#Kp_~$)yH7DI_K2RO-ZLbDo+lSpgTVH=Z_kv>e5O5rs z*iV(TggTi-Kr%RfGJGwi)x(EFA!}X}fHTo8zG#!#Py;lZGeEp1?u?au}5?a)U_- zH)#ReT0#ft^DEE3M!NgdCtTe^r~7)7FN+vE5!dqdEoBc@;!X$XH0{cylg4 zGXu0|Rj)r|7V2CpP907yp!rsI0a$MzO>@k&594IzU8AoaROt}hoh>x@Ad5{<(EJ^l zAiOL=Oauo(>lxCsZol~c^`eqCiZ)euJG7q>3D!(wZ)|FxKWcsQqXzXEM@FZUn4zqq zgVV4KH)Q^Lva#kkF;O*zQKoe-9wjj;HuN17KFNq5P?0jmimsQ>uQ&|;jSbvM9I23* z37yC1xZjXs!;5TmIr4((`aTW6ActrCU2ji#z0^abbR!V9ffe3*lQGSQ5zs}t2v;V{ zDCs8(!%`52`Xa z#&ri@^*+*GllG9FzINFmayl%rRA49=;tM=%U8ca`Z*_stxFM){qkz3V&ssc5Bs{h< z`toY&&zy|T6`@3adR2);5)6Gil@wrmXhd#(5N?k)?mCsVd0_g>+;nD!K}s2pV>zxV zL>cQGboh!$n2-T#YRX&T-gBk19d|9Dj!vqWo?d4sT1noC}4;RJ-H|-wz zIL0{!$Bins{k`sW=*Q|cCYL8RO2;l}W~-V$DE&zF+2(mmqCNF%63{#*#VywV4f`}; z>=K!zHuqyC-Sc+$G8EnA3NkwJD+7{ErU8WaQ6C@MwKIEl;w;ZOKptQA_qR4JmJ(~! z)B@k%t&1b6wmHMO0@*?2B`QuheDaJeGXyw>Wx#8(Jbe!b5(Z%W%Z_GsrRy#FD8z7> zExSUbxG&ne!&sx*8R6wPoKHtd4kCDL1CtbDW%LzIrj8(}>~U71?oVa3dnv`Y^*m1U z2804!k~cS^LLFu^^q5oGIP0X5E)Bj|v~9dx&W)|oyYAC@@rOpPJNYntBnjQL>t^bl zQT;&0W_aT%b*p35@@*mG);c$*817wZ`*qG{I0JOyI;LPP)H2W#tr^f3>VkEe{aHs> zL1qu0>aX}`iW+;L{dY4*&O)F*A9=CsemWJ>4Y1cVjzHp6pa^;$^pv~&;&0wj!SfXj z@u-fxilO)phyYK5Zz?h0qm>1a60nh~&)-jGzjkeh=2vyN6vI8W@@!Y)#|n+fe&3w= zjrk%!x*K1VbTwytp3zh1Txv5rDw+4YGxepgM-`m{6O0xt815Tq&nX6dHxk1wJTIvHK)p!TBw!-`2OwY9!1u@h14$s59K?O>Uwd`J= z*kriCxP3K4ZCiKDT*~11wkf0W}QqaaPF;R|( z^NZ$BA0F7(hUBBajr>F1krHDWXf^fXyLz$84M_M#74)+!~js{@;G zq9Gs}=$0FpoDG+Joxqb*n`ZQ_TGJvdePg6(sDB@T$|)4s0^-^iz&%4=8(4!WtwT36 zkR}{cT0O0n7RZ1a&eBDV;F@G$tEW%x@24)z6K?N%>M*6wrds5$=ys=Br@;KH3RI7G zxx*!Es2yozl3wDNGZ8HKoE9V^$0`s;1=nhBQt7iv`!sr-Q&+e~T%yl0TbV~C7KngM z=1NjL3Jk;eeTj4tkT^1hu}sx|Nu5eFW*pGc4*8+>^(Q71jH=)1^rou}fzumcuwo%Z z;7G9Iy^=C2C{s~fJIHW+b??IGUCYiX(ht8hND#22eXc$_k_=fICNpk;1o?R0U(?WI-U}P6*wcMS_vU(X zXut7;+2NlmigVMo&W=F4xi|9XNZfSuuVZ*QW?0^)ZMPam;^!O1z26ZIj}ZSZq~;aD zQ_R#VR;N2+`z>RIl2M+(ycR!|@;pYra*S}O6y4q6TGcB3`zR+@Cs+plC3jQX6zHIOo8R9@$OBj?-41z<2A)z z4xBuW)z&bSpJV!{Kh9nyblzP@1{Sx%Lh|%T&oPO7DWH8RRNF+e{SaI6^#bIpaV3%H4uV>XH=J^1l*;ysMr_Ew zSA+6LtF+)BaLZ$t(Yh~Q`t`k^>M(76J6v_>g@8%`A59$mTo#)L=rIM?38ye4!pvej zSmED;=HU39%3_n{#RhQ9-WJU3#5=SQiY6EV{QFW%Ga~gt;~I_p}Xtsw}HElID{KE1Evcx?t+$2Vutb91@l|KB;W?=HB@I3l}G!f)y= zwv#vl$-Ue~L7xXdvR)?1^-k_jy73+HUb7u1-%D2^rl@Bls+;98c%IY#AB+{b*^;M- zyn}*NQL!t|WMVU?2#Ru2#d})^{U1K z*vD+B-WDU&!>5b`VxD4(AoMT6O^v^KP>xuDt8vY$`$q7Bh!{_#8X-`PB6NMFrH*9Nae9PzVsF`);bo zQBqE#UJOrf;IpEdw!ruu<2JILR{-R8n=UWVUxX%DUX1VTIuCy2%pNB+h_q*!eYh(h z_r_}iXdjYYdkK{&q!T3sNp~erCotu&MQW85{wYm zA%5pjFE4J7i-zI=#|+wxli;8boWRa0IV9DPsMw#jnz3&F1&!;OeR4OE`*SJBq!UPl z=wnX$NP8^9Q#D!Mib{She9pQ;-#naFCDy|_IIC!y07M(`s^|3Va#dhf$eA0LPPCOu z&FfvjabexRyL2*{&D(3j|1S=qhWd);Q)zCz*Q3=IpY!y0v`1`-62LRbV!m2vSJU{m zDR&jQa;EwELQZMcz#ewL!z|n9GI=m=CM((|`JEJWw70%13Umcepcrv;6~xpR?m2Jh zgM5uFsfNF}KxJUrceR8BB@@In!e$gRBqe9pp;{*CDK&wrGeQW{dGSKnpL8^be@?HU znjJq8>zYKR`Cb;mW=+RdYB|Lw>`HKVqa(h;D6w>Lk zO;DV>0B^d5=i~XsL4w$Yt6?LWuH2fbLBUE z9I~KIvfaPvO#maCeicyHCQUa&h^HqQoMm5&SL|8=6tCdfi z`1XDcK}#-kuHy7zpDwPwwnsbs$Mje$TV zq>85I5Cufvp)}lU^8{ssMk9kD)!<3GhMCWI^s5-z!r>Lg7)!{Lu0&SPTrpq}16^f# zW7hGsX#;R80#xf-0v=6cy7+9Z%OjLw0$=c%LQ;Kbo;MvP{U44$3LxpvNhlIbO!Q}j zb!Wl7w3=WC2xXU~``yx1dE4RMpJ;Vm`*LfIXk-f<@^ELZzI-+{=rg)U!-0r42amZ~ z!W*M4i+me5efBl`pO7bVXI7g8f1v+Jzy}vU=LQ4lP#H$DJLIA_n{f#eaMWJATvV$L zt)wyA%Z%sbkCOLpZkD)AE|C5FrXwi7!f1kBxy)PvJb|A9LJM!@KN1YE_kf~z|6u-+ zfYqiPlFL{aUYLk!whs6~p%nX{OfQqxDI#w6C=MfPs2HOx`Hkv|cOPJhf zR|w5->v)^!c)OTzihCW(kxg`cJ^sP|M;Q~Oal?ORpDL;>8`~Oyk`pmwCqXmIw29s| z-L%}C^{2lUcYS~VzJSRdj&y@`hT{l|0bjc?|4_b^HPvytDjG)ux2sJTq4)WhqNCX*6lO&TJP|) zLRuSIPE4{E&tMiNdO2$X6MJGGb}sg4FL}Q6p|r%`eJNxVreeg>toos+?3o=RFZ;E! zLGh0Cmo@;}$w6O= z-jK9!2cw?M7=v>F&$^lZ*!mv{(T8kh!s&^VqRx>StaYcs+xc$Hw%*|JJjsc^r5qr# z{@eAKY^>T?76#eZ!LPCML{pGlH{sS&a>R|bZ9EvCZr*VYkrUN0;YF^%(WF_xofKEs zO)xSt?$rH<QMkG!S&;OY&p}!>Js6M28lZdN?#ohoViOb zU#Nj2^L^8fUig}`a=8!KP@IrG{&zhn^(0G-EgwDVHnBsPmWQFzkven!lt1YIk${Z` zonju7ts%TGK9yCSWP8P-B8&;oz3Z*I9#d1aLCpL-QtAZ^IjQF*Cbz1)SqPAF*#9J;u{*!WE zy7_#SH2n#Qy^i`X5|F#`+OBswVX3!v-ys=T7v^XJ9DSYwzu;I58g>GOVX)tw!b>;X z%@V1bp}q7HY7=L3jpXMq<+w5R%BT%+Gg}=5Vw(?M80dW50PMy;$~ehK#hnz8>Fjsr;xLA0)Pb z;PuXvRw&PTyO!@Q`_`m{@AWBQ)?ss=%Xa-ScTo?F8=Ah};pX;;TdcXiYAqz9%CIc? zFA@MYrOc&FLvxOk;<(Pi%wfY^5RWITR(YoEdJ_q%``|;%&7s49xh7luP+)>lQVc_@ z-=~_({{0jY^-|OoiA$P5mV#4up=KgO6<}CNPT(Z3JVa)Tj&|;)|DPkfU~2ZVQ3_`M zqiA`zTQP>XUn&pqgT_aiP_z6(Ojw)jeg2X+RcFAf?W$@*-c<%0oi~hA$qjf2x%718b zjyX#^23SmYrQ)R(;3(zt9UDJPX3J%BNX%2Ly*wxt;aJk?0Q zvpQt27keGbhND!}VAB(l^c+6MY1!O`mBVpO*_6hUX1C>Fi^TWPPl&s@KzwrAXMWwx zYZ66+N=wL&UH={KYHxqn$Hzqz43ygyL=H z7oY4ZoEi1eJMz}9I#uR_}yrg5`)AV~2@Ryp*4|k`XkVo3Q)RC>Usc{C!ph6wg~$@$Evx<+ilRPs*WoyV92T`R=BX z9ogG@YAHPyWXD1O)-#vN`Hi?=CfZLtpn+txxoqX=GuDdF&kLR5V(>g>UVk1=k22%@ zqlRgK{@-i&!dsHM$;&F5ciZ>hmI0*fAR8zrjh1C*T-xqU`k7j;4p3Q;-5i||!_4Vw z^clJA_}UZFdd;UvaZL=s{7zNY&!&#Ic2PH_Zjr{1zgzIvU-4bzDRj8HRDFRbn!>ehal}14eiV>+ zawc{1(mqv1YAw)scx1%2b~gthz|_6Z)wO++XZ@)IixD8;H}=m)>z{c75li{<xbr7**ea;~roY_6jFk_g&09Whyld zJXoI(9;?ndVhaWFL|xKdNrdrrkRXE!*3wlN44#YlgtmZMsrInK957XO*q&PZiVFJ! z{2z&aeRBrHHz@PHhF^uoT8?(xbV%9et>sAn-b>g%42QGSbT*S+=Zzrumm_(VtRlC} zaP_YE+6PF?s~sXdo|Sel{s;8GrcODw2r)K#b;zYYY@z}}tc2OmWR_NI_di7cqXE)4 zL6T>1QKe*V0*$@MejvrT=9khC?WO&(c#ahP3X&Ik%d$}nUc{NGdn0Q8%8n?ao$+tQH_ zKKDcUS3-F9qz0dU+XODvE+3f`Q>y-~f}$nTCKo@?3kyiSdgVlvT_5fVp%uTn=xZoQ z;0T=h@{Pr@7*Qju#h%M;APaTM{vuJ>uJEb)5Iq)GU;pu*z@rO5&qz?F|AtA{ZE-pJ zHb*SgTa}?o_VU^(kA)>6AvcVdb92yy*xPu(y#*s(2rt<^4kpxJU2kr*?9!7v!@&&i zyAR^2euU9iz(Nd^o%I(Vjz|1UF5y9#8$&dNRbH@g|8;`t#4!D@1*VM&UuzBe$?`1a@@z^G&7I(kdAo6BHo%^*#?x-L?9|SwIVL@&!=D9A!i3A5`%>EF$?)%^0yI&=U ziQl`_`$Z_A<0)D-STDqXs6q?pllrA_DiRuk5kP6hb87q$$13Y$Rzjvz&E&Hz{!VuP zEko!>$gsavM~^Z!g>mhzaVa_P3YUbfH*@J$hHokK`ypEZ%lb4ZXg4HuU!CfoK>)!0 z^M30-4ps|vo4FuKKptqkP;#tuG@-AN+sqy;GPcP4gz)_Oxx= z#{Amup0YbR5BQTN|rx6ALmq2o;SIWAC>mgn#yg-Q|}XMV|_w}0bOy|$~wG_mYzK171j_` z(9mX&6@m+pk^ffpF9GjQvn&_i==JI55W+fQ@ws#)>ioA0c$mVoYm7 zJNG2l-%y~!96YUSiaJI?Q)|#AnKC2d|Cj22xBLC)DtQ-cX6K=pAxTOZ8OZF#dm%6Q zyJSYU6MZMaHo0kaNKY_FDq7o_%zTC!!+#06DXm?jGisI8{t}(@5!n1>zC4bZSqv@( zt^V~7^}sw^+X}5`;-`V8{Yjd@BlgiiPiHSZf;)zTRUGxuGjguq%oe_D)amUZ)~P>T zyTlaVF$HmuvTGDNZ)>zXR=Yh1>>-t0;8pb#cm93L{}xt5IUenAwi}|Y*Qf4eY^#Hl zH7^lR6v*`P#yP%6ds#nbWmTcdf?Sbc;BeYyF$lBSt8Qkg9*F^qws$3aq5Nxr6~003 zLDgQuX>gAEB-Iac{rhDG>5jxRp%L`pf5ZGs0EstJpHYh`9VCm16p-S(W}lLSG?fr{ zNkL}#ua~}M);fUfshyq07PyIsuo=Kb=?{Eu{SkIt*NqDizqiVtjc)ECDoZREcCm4Y zR^R}8#c7%}3e~#*RlZXs@cp z=={mHb#d!UUr^!0X=Rrno#}?W8}B+1Qa^2OX|;XhTwq`}~N?V=ic{uj{ykbo1Y zyMVvKTQ`R?*GQ%|4%p|aDO+@{oqsz z=!npCykfbdQm0HJjl*<<#Rg55gK!#j)r%f+1zM>+Y;C-<=T&mRo6bkX84(MjwK6bK zK#|3np=flPM_X}&abKP|VctMzOs#i|`ae*BX$DO&`w5m2tI$yG*|L!5o;{VF)>#OR0e|7u*)1LTV zg8^}T{Ur9hsv}$IR_(rprbz#R_G#@Bi9rOANGS>4DbP{cXQU0RqeMbaoN}s`G*lSES#p`)Ecex-o_~N)>;KmdnW0ds+7oWMb(D-Gsh&Hgu+Pb|jCSNK2*l_9Px=F@IN~`MNB$hAYqvuleXxMC06@RY-X; zOuu~pxpIRDf?!8-M*;CCPt4#L8Qx0x>>M~q2B16s*COO-)98t$TW>`!=-Z-=Ot?{j z+p)HX^kT$vL$G5~2f!m1|0PyA@0WuV2B{^{+sJ8s%kKA&`$upzZhk;GGQy&8SyzQ? z&m;Sd5o*o@P=72zeiOq0eGEHqIb6PivGh2xv9saK2dFEubyej-_{@DNYccvXD9q=XCD#AItJ6=7EJoODO1agdM5b6v#?5g?;#h;8 zm-|luAe*W~IzVkpNX7}b$ywWJbQxE|R+h#?>Zf4`Ihl|A*XqibZ_8kWLO^VFI*;TK zSml-<+*}_Jo4%Kvfg})6p@4h;+Rh@!7dRE$cJ{nRP43rHA+h&r&p&{!<9Tq+-tu;` zb`#uCYi-uOCgo#WBS4Fe)Z_(d!ld=F?*RgVnlG7yo2KP6@?qqe%2Gyls0R2`-5%7& z)x5vOEpt;L=aZnU)br2eNj2kJ} zm)ZG;N%b@MK_^LPbF##7uzNWu4#%R`*-3Fh(nBnm=L~Gc&BPYbhZBt=y0l*jUkd}% zB0bQ3F2R11FwwnO9%+O((+ZJCX;}d(!$TTeb~lTcZUkW~K!l0{!R53*BLAG^62K2; zPD=Ubt%7O-F7htUmbacN$5E}qNyuajKoqqjx6D8IJp?t_BH0wmXB^$z%rD`Hnjai2 z{%-qyF0$ObMshNo$4_u9j%K9Bmwo_g2)D4ikvZ>CSc;8_7&sLjIJf-6Kxt&xHaOb8 zOBv~IFdw$=5GNU_I!j5kgBIBYmuraZG3AOdFf8anyPkZqFY+V-%@IQe2NnA&VKLolk zS)kY%tciLZ-j&D2H&7$xVS>Z!m`&^92;W1d(sII>#sK+Mll#&SF+bX9QKDo(rY&tRU{` z^G%4M2(+ddX=kx6(&=9raO+W;iF&2+^Etfc*`|u}Kkk3t&&KeKeUD08fAzj&r_O(6 zvE!vk{Vf!~Qq%N1+#^mJx@GdrOYX3x@<4tynjY#OKtKX!y3hNWlWJ}%NxjRRd;nit zZf_kTcN0D(OAa(76ule5Vtb9{z@EFLfQ_;JZr(+={-eBkby)xMiu|n;OXsk*BaqJmq|so7EWoG);VgF+ zNa^Ez@mYAkH2}oQEjO{`G5;YyFD4=v&5Q7UnGIj#BS*!}7Ly8G*Km2CqEdF1vRAGg z6nQMO=Px4YQ|b2xBkWF(qWu564dralE(+jqCc`j#{AoIW zxU5e7&4^pn(>~38gK^kMokX>Nv9gd7gU^|f?B!Z8s9~x}*BWax%iW!-kXHapg+BTEcJz2$?nO^wIsSH- zp8+|YJZD`+&Do8rVx^8-pajcXjwcX_b~0s#S@>_->QnLWe)iSw5#0Y!H=>lZ^Ya{YNSPzUhD^EPl{5`+~qY>RFhc8}|>6oQ5oZFRH&OZw#W(v<&qJ%Um@x z(05jq#p0VylKfO=pWqv}eN$v7L!w63$ZG{z{=1J2oz>*9;a}s(eGRr?cm|&^M(vtUgzjs%G@A(8$-$p> z!ytpk332xL0jcI74W)FS0;hRC(evDL-9CXUJq2>RPDQ903(@Zv(I(k9iVcFW?yZ zF435x17nQ;l}k6L5Vsdc=&bmQ=_@H5%gL8UEUW`Chi3zX}#uK z5Vb2yi!Fkurk%Uvn1?358rUf*hgMbnpr_ik)3ik$&zjuCt?)Hxj-{*rAw3DO8DY~A zFutX;dOoz+_em?)V>#?Mn0Ni<9gQ+7w=sKDVB=@TrvP~~FHsUDv;I3mq(ep!Fjb~_ zO}AXo;_yLzad8bI86Zgjq-sgz?~}9%X%seLC9-kPu+5Oh4`hunjYa;!5Wm_RG~v|q25ua zW2}7}^D(vzkFHnVhY-dmSaw*#@)h-4tN8}ghOYV|Fp6;^YTDd5Pg=+CKn=^8SDH~- z8WDjXOaD@H#`4KJ;}IYZ1P=2#cZ*^Q%(owBT4le#7H9903lD|+^AtO-k`U8>gjv%n z(umILpWX|EEW&!jfY<7K?f1qf1Ii19843gI*x_0pT~gF#cC?>7YGIiFYD>nBh#K z2;FzX$d4R{c{s|6&(*yGqpK$ZN&3uwT~NtTp9i*=x$_&EkT|aOPYzl+y;T+O z((0~3t`?@06Zb)1ymjDb`vlXYcN6~2yw23`+wg|z#H^ZY5aY$t8p z^be_>ADIkagqZ*qhA&_KaaBqs42p_^Vr|bie*Es_uqxyK2uI91pYk#Dij6bJ5VLl` znWHTZ_h-ysq)Oa99$EROTH|-u%N6G4PIz9{#K|qB76x;>8a?EA18Dx<75NTtL)N!x zRAJ#(#hv4iQ%H(n?R;|S^Qv!VPgg5|BI)D#%caZSFLsG_8vpt$F`$Ph&K=70Qsgv` z`Mes~L*IisIy-cOw#5&;AKu8jk=%?AOD_O8ql!W6w+owl{<5YYNy-UP zJaNWeE%=sIFlj!QkP6|Q1Q_~@(?Uy@)0rn06~wW&d$7+IyjoNyW(RZkE(eB1T;;8JSd+pUkGTJ5}X19Spbf>Q@r(AJJ#suhFuRUE&ArKNb)Vo_d z)t{iAB1$U5*d49WkxA>eLOaXnS=k{8;A#>M?Wi}V`|@UFywez?Z>R&$1_JT?f@-8z zC>!&dE~qDY+n!C`gU^x#7P0p-51RFGT_I1_?g!Nmg6P5M%O9X33sgWB-D16%4;E$zjsfuLYu6n71bE^dBa$wMZl#FnVlV%Q?W4OOc{Tr_G+W4 zEGPbd#Gk)}_n)E$_KMS}!sTankBo*nmk$p`2^^f?0l{g{IT*}=Iz=M(sRqR#3WO9V zJAnpdDqb_EwhA#o{u=A0hNdq*S8o0%F@}EW4+5?8)WL#TZ@`c<+9Q1l zoVDmmFB{MdF0`3no#K1|XD`g0;5aFTxN_qVfJzActuw_F87f#O{2SR1LdOkQvbjvB zi#fJ@S5@h_jP^znJnfp?fovnSOvs(sNNh6kaefhYaqha|*2++jSPS9j?pd*z|2XMS zT1UmYXuF_z5=6QCL-1W$^(9Q_5qj8SHAKL{Z~nXvYrA@AAeDOo zY^YZ5qg6ex7&dyV&}8tre`L?CL^%*$mNf_=NUEvLuRiaVeHZVaH75H34GffNnYey- z>qt0aMgH7!1W{b~G=#@#c`ll!DW}{0$a9AibO=p1F>2 zOG%Gft)qIF=EQ<1JsvSLSLDv~|B*JmTBW;AO4Ti)QS|y-LH&akF{S)XXm66_dY-fTITm&7TocEk)kSQ`5JfsmVIiLQQBrX8~JPocL&E*1CA?plan1 zoOmNV(SpL$k+`+!9=uBucGbmT#FZ|S%@*G=9gh$@UvT6*ehGBml}_+W;Uvty7Uc-t zd}?n9>H>gD95f)Nld&03jlIZdZ*7cE!+RB}Yxr0@b3thhgKwQd<9Wh(uNB3(s43@0&07?;Am*qM4g3O%_g=)m`S^M6Bs6LmnW5p{E~L0{_<=oO+)^y z@m-)O6r@=p#aIK$^kFEwfFe#jOCM3;OK*6uwO-mIs_PzQjZAJfqD-d2`)LZ7Ge}Ri zA7vC?MQM8e#8XezwkNPQ=VXK?DO64IxK&-2<_5u?SdZDNdZa0H{F;*QHvyayshH(d z!n>*GZ;3~BI!fMMCmK+VwcX=kEZH(!RL@>HE+~(wna|b>1$kg`-T*d(1ab}%%z|Z( zhq$uWp5uff8|pMl#LF^S&(_1UJ)sV#dy1Vky0bVz$!OapE|RKYq+Ju6&U6o($7uUg z>unjn6zqQEe$@dQS$930b0QoU3~;VzRqNqI*vSd%eIp!dLZ{=dcEehaNa1!|N*)gC zEAZS#pK)OM66_zu(avW@rn$nLGD0KXe`}?)u<2YYhksbFRy8&bsh<)Z+(o0{=dkK1 z9}0TWkx}C(TJ!xUZOT5@TU@~fbV|5g*=X)(oyfM1*=M`vk>=*;H;eu4?LFdxYX+(NZV=WY@hAAGe5KA^NUNBCRPXt0$> z`jN8;NsY4u`6M>I{4-zAL%3dvn-2uL*xd9lIn*&sWdITMuk$Ls4nXaRdCw;H84q%I zgAZJl!t#xyyf0Uc#F)Jvpr6z6JG{)?Nqo@fu<2FI0$e+Ksum}*CpW!o_i?#bI_CEh zpjp+JjhXhBsf)8X0Ly3^+v)MM7VX_8nO}qxdMgejj99rzUqBfcuI8h~2@^AF^jMwC zF_d1uxc3Hs9B(s2Z-z=xB+}9pK`pdxE0YOX!!EmT#Cx90?Kv$gT*ajsza~k5~$J7eCW? z<}BcA`uv=e;-2FtoNOqJF$mcdKm=IlKvA}||*RDO0xM5DH=`NK#c78&g$diN;> z0(cwTPIsPr{#P*UQ|^h>ths6aVaZwkv1Z=*+jjm5p%!d(TP@Z|i)v)Pqo*EM2-0In za23_^7==;@RhE9@A7*0i`W8@rWsxR8-?LQMcR56kA!ce)h3fT$&cM36^6HYbRFrHy zGV<@%4F!)|#WK~FvOtnCzWs3}AM{zRrVE)ro(#W>f^&CEE$K0FF#|-Jacl+cx24Ir zG?3feHw8K0ga!5!)E0Sb(eiASGzfkgCVU;-n`$s8>Y}P3>I2( z*J{f)tvu~qZ>fsY>TALql&=w<;Aqo14Sd$Do6LHWi?5Z#RHw9KIv)Pq5-Piwz$+p7 z5d`hvAk8O#(B|{g4Q?*A-SG2A%=9`BjO;dIADFpkBpq1}5?_z3gseErpCmJHEe^wV zThM;bgVlS@@h$Qq%6!Pf-wn(Y)B4=RFSrI&4xC-fL6qC#vYflIqHhna@G6ww{3K-pGrG69KGx^~5IQL5XD6Fq2XN>E^Zpy6Y8cJa=cyQ`AvaMwpTu1QY| zn3$@Z@4Dy$PP3Sa;#7kwJJWmoXk71z7o(wXmzrPWURDu>s)E%(ij2C5Pfw?V6e#yT zYhmZ(i~FBZa&$jisLqwk!U%{z6BuDfmF*4@9p+vo=9I>9n(%gusZSXtxCZQ!#(hG~ z;8cJeA3qQ>f7~*4iNo+##O`M6{#ju9G@W zfE-X#-WZYo&DRvt1w9bIUv1bN$T)kPR4I|uWYA$589y&X2hcO7ozO*mvlJMHDaq#J z=bFnp68GQnLVuz7OeW_`9UOFTK8XuoKKSW#s3hXO7N)e7^+p1ekT5Q{>q3eIg>R82 zLb?o@B$b4XIwiQG!4EP>=`U8-IO>7^K%qFGDG$%k#Hr+{CI7lXCaL%=ltohf34fj3 z?L!R%>j1Fn#(+rBQC=izZ*8rU^D=(DR2^V+UHZX|Wv}~51<&v-Yr<0d0z*S*Tz3_jEI^+QEZ2ekus%70WxsBSH!Xt}!VYzR4{JP3&_Cpj z7B!f9r^h_ zTL>ESZn}_yh5jc+i%%qHbDXKwJJRN~TD#FO2XDcq(cav)A` zi?^$a9h?d0GN#Vir#(VJ}!0DR{pkd*VmRy}y~t2x*yQe!|w6 z@4Rs1`)ikFE&>OmIhk5=d2`>Lph7eX@YzEzJd>Qpj|z+`-p&)d#>yrz#*M44*h9`I zqW3+&KVE-=)&v$O*abR~K|PbcVk5DuhPk?mIY=Mj2TJj;>~hd9ZW{0M`e?f9_UkYY zWcqB^Z%)P4=7*WjGG(d3Q|VWhR|x^$Y<#WV&MPL5xDbv!r-ArQ!QIO#Gw0fR{}EY$ zNJCbFXn1q|qMeYB@U@QeNN?0R;(TRtu{!dCfj3T>HNIxfV1?m)Da@I3!3VTdCUa;T zRivNlvgKGK?a|Z%hp6`s#}g0zjYvysy}zk`6gMVaaFIWWj0B3dRu`~;HK2i-;i&#C zmT^>DANh#5C*G0(gF}v+Mua{#o`iB1C}-mEZfq!FNhE|G+I(LK<%a^ryh7ym$ZF>-i3ED?P zFonOcfTV1HDE4rHu^5)z5&+b2eD!SEM5WEWYW;zLfDCI1?(8#Uq`p+ONZ+qu5F=91 zQ&GfWBh6-ckK<6Yk%+*~%rVc3D6(xPe?-wX&T5{!#0<=P*<#S=t3JzGgpW3Gxn=Yd zGEh+S;f!LUqSzxyRDd(`=kMLo@TC@Bx$j|5M=M_DWp*|o=J)(py~J}RCj;H5c;%)1 zBq(rltH9kP*cfhcp!X%sM{?r_d(yv^Cpl~>Zj zttKwFglUsvL3h=0i7f9v^UnTQ3%>Kx{$)2~X?F%Y(QB%NJ$ngFh%&I@y_Hjq-0*&0 z2i^XDg+Of~#eeR{Tv%PQ=qYi~e>Puhqaf|U;C(t10K!{*?kBIOol3z5oO5$aa{`i< z`EI5)GO#;f7uK{p0?XWa+U$qF7}*L<)olyUD*5S!1Z7rvl1Zx~B`9$76UXw-Uo3WP z7eWgazD|GVrkXVsNE%$1I}C*ydlsA<(1r7)ESm8I2lpcLw{UaxuvJmfJO?Q7aSz^SvG}&#c(mnuzZ4{S4;KF(@lNib zv-7s+`@Y^I5LE3+KI{xGNVMa?BPv~qU(aVcSyI(1cx$zwg!~D6>BlI~n0v_Cqh^%P z5DTl!TMLEA{94b}XW~(`8k1q29>W^ZTZ-R23kF8_&;71wr;AgZWl>?g6DIND=5bAiG@U`MEv_1`7M~m{EJyUpfmIQu=O8Pl&x`DD z5q=SSBpk^6ou*>Z5=jnkx5**KCyK^#YgZTJFH5ghAkDTN5-_b=FNyRQolts7nc%^E}exOSvrMODJE;ur%Hw+*eGEcTJ2}pD?@a#88&(}aU*tAE2-!(s?&`M z)y~X+I0z6(?MCFo=eonIkD<^tN{gQ?{iH%#v@7!}uZEtJUJet5-f+35jv<(L=l83z z>yR||^r7_|j1qC*d2CpzbW#nX+(!3m{UhUjk7otIX+iq>gJL0HoRu88kbETOTU>7z z-;8FpU4Mswz#Uw>>%KO4QOnsjytO+aUrL~> z)l0@XJ%X#Z6jvBx%vaFPnpIKB!j7^ic0zJ{XX1m8axj;U#WHB7w20cF{zB5`w831f zx^P==^`Rv(NrGAst&B8^_Uw;9cn{+To&ZEfv9&Dl6V%N^`^$%#>H)!rWi1zWEP;O9 zw`nc6fP4W^A_cNr(vG4=gt;iG*l>GQya8Yv$ zMC}K{V?_3m=q5P@_xBe@OsG1ewfzjm5tLke6oqNIWOCj5U{=H!%=s$KIQZ*`TzX>? zNOB^%=j-3C^~q^W_M=h&+o#a0HC|0(`Q1xr&Ptjk+|X%GjGQ2})2D58xdTU^D_7WW za8_Y_3|Ajvqk%6*O%zD_q6D;C)sA&Y9M5hvRc2%UHT+yP_0}fxyNk05!k^P8IH|0Q zcTm*%#!2Ynz}ScUGt3P5Usw@X-QusJ4{G8O+hD(LuQbPjP7{&~v1Hs~)hSDb!kSIb zB4a@7$m?6ghH1_|iW$003|n_PqwI%)7jclw#ij3m4B*1>|Hp%t4m&JzWGFtPHw;2z zd{qnF%2e?O^sM@VPh2bOvWk!_2jeUzc9FYWO~MZMP!OK}ZFB|^y4Vq1bH*T8uTcS< z(=mT1J;8}LY&6wj|M3-$U*8=$hm2LJ+K}Cv6na4BQu`%VG)t1AZQZt3knreX+7vUTmLgD5^wXuuMEzSSx!U8$im+GJeAjikG zGW|Je*M_9aup_Um@7Lk$@}PJz!wWWrM(d@YpHQId#CZy-=C5|k0E)pb%LjPcC;r6b z1O_go6p?iDOUUteVD7*HCst2ESYx!Rk!IG<%soA{32M~>{w&6@&wnos!IslkJnl)@k1*AwJd<>%$cvN?A;@t*<*q7q-nU25e z4wLmE`MFmI|KRxO67!b()jXfzDCtK5?2)Fb%D#D=lZ*Wcsiz1{_2<@^4E??O_`nyx z`V%2@6>5iQ!!k_4_6>J){L#%F@MVKUw5m>gwP1oi{f+islr-4e?7eERA@OsrI-5Sd zb@he!3v4nm7s(u=c1A++<7niF8sUx}3Yf#y^6I&S5yN}{06#uU)1NTDq$|arkLsNs z@2&genHTKgd;~QF=R}I_X;t3m<<|wCcW(O-mO&Q;Q_4bAvLlcRzSb=h>)dfx(pZ!tt%;^X->h6cX7}OZ5-JG-56@ zRrR1#61|+G&M5qLIM@UbIT8my-q|#x^EYh=T57|c$ z6$hPmrEFl%`lNZTK%s6vD&Le43rNS4t=^$;1&#&vY=e4iTT-&@wl52{d~1tb@j5yy zJ@s+pv+?@T^4v%mU+F0O-Tvw?Ly=B5_;^67p?Y_qplGicT{IB#IGhjwc@2663m485 zgwzo@{B+Z~xLI+VYN0b^#rokV8$9N3adBkFXk2p{ifQb6XRG~-(BB<)%&d@sO;Gl9 zl!|qs>*q@#%vUZ56Z5;anPS|DWo$vup;rZ9{=u+l*5^~D924Nu-h2M&Gf%&uG%CASP6ER(kQu$?f?nZLX+RbCsRL%BJ`DaWb>yA7nXvR1DzLO zU3UBWm4AWv?21D1zs7hGe^&?{fSMR*+?|X&TeIGbF6Ah-U~#2|NxIS~9v;1_bBjjw z?pHE2S~@K9Ez_ziD>yx0f}1lTyY?#<8;Kkxnp~VI+*-F?AwH82x|NOttTnN$h0bMp zSSzLn4>dPrfV=ST1(XoxZj#^nV zKq|qG-gD!HJ8cPl5CvEqA$!6)q$Pr{w@DkX()r=F2Q2~L9im5+r);LrWm>X8!E!!u zG&$)!;?(&or>UQu{ib62nI**+gt6sD{@2W#=Ct+=<5PyQVjnW}Ub8|@zhx>1g(D{4{%dtyspVuE%nRG=m9cI;wTz;ZV2=)eI+V7nh%>Pq`RaO zGTfJ8kdG@T1!3^R_7CnwULBWX(1h@j0+W)=Ys74C0l|rMNAZKy$`^xY>A}K7eYH>I zW+sq~?qz8t#&&Es4iHwtZtaCkFSrX^nnADUCLd1GKj4A~r_okKU}ySuw0+(y@%Kz- zYOsTY^j92B+-mODc~vHxm=b$@FsOfIsTYUM5N}?WNN#T&i%V`n+HPSe5I<}XYX4N0 zt0|-+Nnf|G;sZ_4+hb*Ug7)@iH{9rMm*XvPQV(KJ@Up@3%V#$=T#cS>+<6*rOy33U zO-R9W3M<3r$g8d9fdaN-Q|oOs8uD%$r`kR6k%|W#xV%DKOQ{mo(V0-EdAhnmo>7KAmS=~ zCT^n7p2fZ~T*3MhBm^oZNewm*)w~^BO|~wAk>i_WK_0!7D$ovdS1y~(P5;ABLMG*{ zgK~u6NT%qfyhtrazfmOtTAib98@mOYg-?h;1VI0?fBm|WO`|w`p1ZZkKb{%7lxvVS zlegERm5guQTgeR^6^_V5LP8BIXqXz1ulw3V?!L+1&4kg400B&a_0jzFQ`T#m8#ityNc#wxqdf zv2`HlWg7f&}o6>UZR%u_!aD3A)`U&vFTE`_focT2#Q1F7EM z1#O+GuK*oJ_0Clmc9y`D6lB)!hUCIr+0~*8ZR%A$m>D`cTiAv%@Rf!SQloYa)p8F<`7oZ&*3p-dCe(`V zyDFE^((7I~%YxYYPQnRaq^IBE?AQy2EVP5Uk%iyEmcn^|lj+!UyWNRZ+Bm0F40jX) zBb%=GXO@OUP*G@?))4>up#}tc`&G_bY#j9D>YjtyoTcTa0T+A2Boj}4u61o?GrUYl zrqPfWAW0vfRNbT7ujd7dlPbE1K!z>bqFqGV(j!VvMTtLuW+x34SSitjZ~ax)$8nd% zl)V$qVhd82D0Px+&rhy_zNJsL4WC_K?;6sI_F7ELVi2=&A1SL_E>sN2%h3qO3CSMc zPCH0J%=vR}Cn6{nwFbTzb4Od>i74q5MK=7)l+jm?|H>;m52*l% zAL^e`D^=DmedB|z)E$<=#y3I35P@yAzr7LD(XAuvfnjTlgM9q9XosQl^9&SI|K{w| z`*byt^&7okr$pEOC3t7~QNih+dK>50RP0xv#UFw!Au1WNn!+kp=7>oaU7vxdqT_Op zdNau;917Xkm>)11s;bA4?_1WnJ4GQh5DPlREK*^1=({?9GqgmQ?q5YMzZfAkd%K_~A@CC|U4k?%LgNEAQ?(2%R~ z=hmd$t3U9g{nC4(U3Uu!ZvBazR^M*Bnx>2Yd#vEqM?C>AtIcXmU!nYpMjK~DkhBj- zm~g{O4%(mB&<`9$u)r63*;I51{ZyGdKCqi_0HcnP+e`#B&{It?VtfS$J z?OB0x&RL*lA};o2=c&4pG4MvRKZU1%G`3q*KgV4a5fzP;xz?Pknd5g0XS7~JqZ`_d zR}9u;dLZ}V_NTB$q2ZUu*<&hDPq1TUu5h^e{&3Wd&0?|-r+J}|%uEVgvTwzeRC7|$ zG(n3G?Q?_;XiXt&D*892y@5LA!UH%Je@14*IM^Y*Rkhd)wo%RabF^qr zc!@OKBiOe3I1gRoq64!2;1g-cr#r-5aQXp>+z|HeRJ4oJ1wypc;krB_xuk=}J6}pe z6<&Ffq#Sb0!OLEbrT5`nexApq%_!w9ccu8_mIn!H=ExsilE<{NqMjj|R?N>IzVG#$`oK2tbE8I$KwPc?-@#6z2Ld9BG2AlxLRLwKf-< z^}xibP2Y_%xDbsbUFU-@RymfXx%cLbaw;#3Zo>UKgy z&(49y?OPorsvJ#7BC6z7`I|5VIz8!!)37yp?t1F zj@oAm!PO6R3XLR7JcbmsWqZ>dx&gfv57O>^8qfJ89bvA${}D`p5Xmn8Sc2tCCym%z z#fAuLPd6B}9!#`M(0RD5`z=H=$un{!UHLqxwdZ%tB5x?!ABXui^hB}hQ&-od$5w? zw!{OF)SiA#08Ybilr3E?t+T>;_u|{K2d7M(J)6R|R(drVwSfJ;h2s8ia5Q z)?O7G1wUBT_%b>>gEu)O(3Wc^TC~@9u~U#6O_-k@dDC`bREHVygy9#aMn|X6J<3ED zY=A#P{Wi6E6B}B-L3nZm?(a~d$d72B==1K^8a*}cFg|jtbxH?T|EcqPg)~R99Vl3I z&n@MZ;|hmqC*`Jq(-)bmUTRzzCEOhbdVGZ?z-xXV8}-|q*11(I2q}CasDpvo$Z}KV zR+#^o*pU}0vw#cU!CUA3&O;T-FV~>pw=cMM0S70$np^ykvJY|cb%idj>pE|-SX%z} z?(woeNJ449Hz_;Y+oYiFy4xeGpB9mg>p^0qrW+pdjiM_|p`2*d+h~$PPh#>NHD9Hd z0&n?IU*V-T#=TP;#QvSf`?kf@w=Fnq$Neh>o#Mx*`OpMCc7e#*Y{kZ^TG_s6miFeY zJfoCk3djH@t3bK>pKg6uSc+VW7~+V&U+(#N%Czc>$b(6hp;HN{C_K^`To^A6TH(-C zSq^NDwH2K-v9*s}>AKYF?n?I?^uTLIKN?dM&%nj&sQraKlTGDTj(;dv05>njCZGq% zn0ThiACtkbStlCTK$MhLud*1#^{{`$78tP1>uM#TCg?2aK*7_RM8^hoS!%3)uo6{&zQj=vY)DyqF zE}(k7TMv|Py+QBBA+i{x1pt9}(I3>y9^i%gP&)a9eRFD~8A&*v)UkNxQL=h~v(4}T zpK@b!JYlV_(oDJRV)ab@6m5MUr<|L*8Rmp5u}Me%{+QvN3`IbVV`&GldhAb(-p5gM zX02PY35RECj+et9V4rjDJZ=*>XN8c9t?`9>?_8FBxu8i=sJOo!PYg?%t+-G3wYmml z5(W%|E&PF8rpNRDFYZ+|g9T4tpb5@*UfKY@m?EB=44l3BR9^eA~KO8?Ucv@|EHc43EBx=KNyX84hhcV4)llNcW26k zGe$MrwO^+$xN+)=7a)0SzmXhu{pDjDV)5@c<{fMQ&Uqa?TcLE91jYvit?Ed8^c1r&xQq1P+3^5lv^)!v?!q6 zFAwkJH%M*xN4yfAcF?OBA`c8Qyzc3q5{x?;M?MuMr&kpP^g02B4kR*@_693TV$;6m z3Gl~2lAY@YhnX6o_;`Q}|AG@}n<9*LU^Z>Q#;FaV{mR=x3wE{#kQTS*tTukwr#K2wwxzN`;Ow2zsqmK-}rm|{Z9kG|Ihr#<|oBm+WAMyJK)97k{1h* z^d;W}c*8H?=LU5A?0*8Dz(0}z2%q8a_N%kGyQjUo{&lZ)-^xGwU%l&jf&3Hxt$#9|HjYm>+?Du0GdE^Bdk?5nO)<08;&p0afpS`-IQXJKyiD zAA;-NzR@drfc@5O0K$)7KEWH;^hfXa>mtBC&+}*hhva+p<(4Fm{RiPw{A%`9f89Qj z;DP(=%l?he9KiHh_la<~`0Tcq1KV5I^pZFjA-+JeLU;(T@g8<>r-4A*n0O04k*Q2|* z*Ong;ZA-8|EVx{k_Q0MtdXE_npq99N?`RtXAg6aS{@#H2R1|`3o)-rz7cl}+!!S!P zu&5X&W}n6UnW2WS@#$@f3a-+pzdFdjSe^XjDCcT<_^$=8s|lxREQo^T&ZAa2vaX}h zc*D;wLtD5KiG1=ZW5kjbJCzSl*qei`mTFz;O$}lGrMqyo9{vA((Tk&k ztM&1BwhErsyT3UaFy?{~rCtI=*wYsH*4;9t+C@AMrc87uz}#&iZC7J|HYAh?;P3 z>(^5g;VVwa2C!Ni8Mj`gvMGGd$@u^X#&>fM#Sbw}mV(DGTR3`NF$4+om@mQ+8fXjQ z0C2g00Ne+<0o?630_c=G1XTCJMvS5k(3RuUmKq@PfWWw>`<~OQ@Lk$uOmu5-n1G}v z*C!F}|1Q;wqg3Eoq4(-|4#uV(QR?lgmS-aB{DuK+6@*tep@jbw?rI1QoTEHF2#+w2 zkdawXqM&^ReBdZl;hf9Ro^V0br0eKmuSl`Vd=Co85EGs79kqNA@s!O0xSF%^ChgH=mv~JZ(fj&mW)cy?f~+@0q4oO^ z)^I3vR9|kTJKVnVA1r9o7>RyCkKD23=+BHNxQt!}A6#WKVTo|I<}I<)Z$MrxNsIDm zxGn4dbOvfUv9ic(T@n|4>y|LxZe4IJKIV17TGThGh{c=&d9Cvm_yIDZ?WKbb`Cy4+6RU%mVh`9ue zX3weEQ^iLL8SEUyQ`9}&64&`l{Nn-x(pvM!x&se(Ka2V|DA&U=tV+Kh>Af!(u1J~@ z=-u&rHJfmCtpp4Dw0}Hf)5Mi1(SWdoo)Zaqnst_zv*{eaTa7MOX+v zhn+RMuuW;eXYT-hngpg2r6LNe5U``ApGV@e7_0HfXw_)X7;;Usf`Y7#6;zsQSrPfQ zYBX2XV8LiAkPeOz;`PKo6w_duRKXbE1TrI2eot^51;6%J>KTRY!8(@^Rj95kr~g8* z96M6B1sq)$PM5^9`g%R>lVg;~>rP!G?rlv&;rve`(PEzoh9LV7tYEJbxxEnr4-v?* zJI?E8bWA3^>6B7M3DEThRaF_8D}&@Q2M%D|k30;xkOd5E@d_42UW3K#+T={9OxLa{XLwgIbPFAspMk~xJU zk|}|fniWw0l&8d_nyQeo>txjumfM;h7u!jY<8gvs6?8`9_f!Q_N<;q*4Ov3IeXN^8 zdV-)A7&W_+W*F|@4tV}bYT^H^^4ojlWN@{XoXkD=l-T%cYJN41OL8{;HxV1G!Vd%~9G_4MUQV!hI~mPml<3&{g{`s?wjvtAL-xc1c5wdQWwjQ_-{vWBVZKRK91 zEEAzy4$gi3e_}=v(i5`3CKxjBr)v4PMpfzytkqp6rWf76f)8DRgBKNACPIGYiHJ7* z<3&(3TTtaHeKwH{#7+em_YMC4Wy9UcleYC=ctRGa_7`Sc$!*jAjDc*slJe1ilI%%x zCQJEJCEE;LlP>;WkPKH6ME|2(M>0idp`dpFJN86l0Iv-)|T{u zO4Xl3eo^huMlP5d3`KCwr=_xvU-WlTt^d~{{{d0mYVJ9C>>+vs^^>a`eibwq@F(q> zS^~=RR?w2fEdvMZe>1NdvrvKhJPO!Mms$6BwM7OCDlJR)6*9xxPx7VN-ztGd2w+*< zJYNE)mS+BbXsumst^dPMu96bWB2=Ro#VAHG%Ap%`(GTK(rTCLUW1jX4K>;w*Qi$}A zgZQp_(+|jOy+)INbyjh?7x@@O3yh&i|z=B0M9eQZI17W^0EYHD6Oa-$# z@Xdj*0y(hj@v2dZaLaJkv6jrcY46=DfE@Hgl*8=r#_xW;;DE1w5)Y?gZQ%#7lMot0cc60hex_81rqg9>Z=FS))C?Px9Rhw)4+JSd_F_R!35LUGr zU>bnsHaD|K6io{N0ILSgX?it!qu{R1G5vGdK#3H%KQ_j9?7L8ZMDpG29gJ(-w z+Ve@<46yzUR0nr{y0R-VvcChOtD)3TMY>uGIsV0IJ`k##K^U0(Mdy0Vq@q8+)2uQ* z0_fO*qPz6bljIS7k_g^MVH~_pBgOjE6-+2$VKxJ z^|5M8skhOpFE7~BSc`c!lxffuatGT#Gy(7pVF}C7QKPb-KB_%e;q?nxWw3sK9PXeM z@F!Pf?*Re9ju0H9K6l-of)w~S6R%M1_!tXi&e%aT=soSGhoPUS=GNQA5{+==CF!PY zvVJ|3PVjg&6%U$dh{8Ly-Sl3sE}zS#6K8rf5B4A2fAQ)js)~W(KQ{S%-kbIeD437D z)*Y@+8V$AGeJK>{&bJS|RH`Vw+{>3l{254>>dGom(Y(=_CnY5BmOxd%) zgiRW=CzB(w#(1URz@nYsRvQ@fH@6`_J5ee9Vk&b~^`T}!y5;wowx%9by5!dix64Lso}yxp8TedDzU!z$qpahAR``~>!kY`d z@$R8ptM3=GXf1=G2GoZT7(xCi>XK72qGyI=rS*O(IT%Q&qbha)8L|P4KAlNG>^-O- zTx0zPJ5Rx%W;%i~K~Q0)NicXrtW!>eZ%h*DONJM9hMucucO}qH3#6V0dCp8fiHCM1 zEDw&;CzHS8{P1Cg!qUqS0viY#2@W7!kNT^qw)8#;i+^EM=bA?UbZ)G#D#FZZ!4g9C z`Fh3YvBO8ALTcDQD0CnTS#WBWy{sJfxnd=h6Hfnmpd3md*+%9qp8E70qXa_quPIz)J8#C8d_aal1eKRnw48yP1RRc88&twH+ z*k5r$ahB5!_bUO5dO}LTWh@;8M=Vc%zz9m<1ybpwiK>~hJ9mp!Pq)C7vMXwIe!U>k z6DXig?hfF@82HY9;MIf~@IC-xw)2+sVqYEL>U#{)rci?R&c{ytAmgbiNyG!euLcF` z?OHt z>e;pJf>u?iE`i5q9iEmmBfG!#iHw6WQNJRC74wzTnE0H;4aBSOW{=W;DPyqeJ1-4e z3tHTz4u74^R6{at@Y@3y!`;p_p;~4SjHbDj9|26%59EpSF^Chq4dHjl(_K9-i%`d^ zvalzxp`r;+lO`0+t)-q3hM3ORgLG?T3ZVc6{RBFw2q0qEn1AfY$t*elu0)qk@`!agW0jB|tCyVOR- zweNHXUuYK-I?YPB2sU!R6}a3gveSWImJe%u5AFBlR<4J*Eb_!;TnrB9F#bH6NM0*) z?bNx$mxU*OpnL{WARlaSI4bcvCbyE25Csp7v+l-KFz-nb>K~-W;XihHtMQkDNOxlw zh~G8x;8lM~kKQdYUTb+17Ag#TB+e^Wd^iWbuiS;!P#s{Qls}&d8HAfWJVG9#g*>J_ zDl!iW-Ki~4vkqDqx~C_RAV8;u_gl*EP-yClz|0fv@$)l5+NhG zS9;l1OA>}t-H1ZW6pP1EH|LjWw2JDp@Ip6}^he?$HJ0z^<0#cB3Q~owa3x{H95+7cP1q*?{vw2_Lcc$_Z%6?4$GxW{~ZBXwv@=b0cPBJZu*%F>ySU_in(1w^ocPV~S^A`GH`{bI0oVvq=w9H9T3vSU+Ts)% zKpc(4DWG%Zf68bhwCfiS;90>kp3nat&Vr$Oze9-6J_5_8OVFcy$2FH;;vBwL-!oag zi`b6As~8Z$j_{o%qG6g<<0yr5HCHEPm4) z`3v4u}6;nV>;g`6gmdr(ne4Uoby8Z%r@z(Vo zoHLd|0u%iK+RK)GwKnd7cl!P77oItEk+o5s_h4~xuM~i%I&f}ktSl}>D`jf|1&p;= z?80vNl2w~UD1QqRS0A3jcYXKs*Es2-skLh$HRHmwdaE-NgUz2RnW!m0y}g#4;~(Hw zT?L$D46lmXh-V?36R#)jLNs&7Ha-FC_kxvv>7Hjf!|{id zl;%OmF(4oyxVZrcusUUtOw&~Ke)Ycnp5liF#|!i_7x~%{@HhZ$R{$LgLMb;4iKd$c zjl9LhPoLP+i{Vg|0}OGJ7x|}EszxzBtF?TJ;NHNk!om%>jJ|5O|LgvY`#Xb2jCrra zh0GaH5!EiXy&`odI10a5nE7;IaC=j>@ygeT9y!II&62B&z`JLoGGJ4IawF^MV_SGi zG4U!>47$*D5Ls4nUejTx*g4eI*Ca2*9F@xHvoW|sY^itWH~jz=!CUtitvT?5Y{$cGo0^!Rk{*f+3JL$p6;fzm|7s`7IYb>i*pO zGNKZW_sypy+5c;ys{QexZd3IW7>Xs48X@XDXvU`_acTY8IL2;WbiyDvd*wzKbP(9P zCC%h`=5N^kz$qaq`IbJ{M^mhJpY>k$b`}T~xzoB;X=5v0gGRlC?H+~wol<`FYKJLO zzCa93YI8IAC5ZI|H?It`QLUb}a942!iQDV2B z@?{!ZHG{d`Yz-54v*h8cq{LCkXMX?lPN=0!A1GnbS6%JyXrV7{#i_t z^#Wx&Ijk;ySyru{?1e@Y-d6g!ae=@&Uve);l~Lp78Aw&^T57ApTNF+y zQ0|&e(i_x0kKMmPJQ~jq?={%lIYu`LvABWKQq2>zxWLYVF2~a6e6$EZRqFjyV`gAj z$$F!NsiGfc&(&G6tErL7x)Ybhz7KYPk*H`%8C+U?P;5tLy5N+t2#1|$Xl)qaP@pTa z+{aEb@dU@STWxx31is}#j+MRc8#hZJ+yr5p#21Z`Au=wu_zp1B24M4tMv6&XpwT=F z00G6O1#J0S4ZJR>rfY#Z@-=5&Shg&7u9tgU^=71u%^>%5JIC}9ko+i)EL-Fr*4f%r z4-QpbiVWrd-lix11b+xna!x?T!y`3(@at0ppI~ z^}$dVI0s9_i9$digN%`Q9Oy${AR`?1(5I+J#Q&A()v!L)N>VdHNNOI z7(HBcm%;eIt;dJBXL!oDNi9{7%vVoh`-aw{3r{c_V%Wj!)W1Je13CEc>6<4kD?QfZG!tWbX15wVfx(_fcSFR1S9xZ zv+%cm>fH}qyg4c&!_IS@=I;#@Lrw6~O-d~M$V%$67s)FTM?aLIl~k5%rtt;! za`;hxJYJkoPqupl)rK(Kv6-i%v5~hgp2v#nZsIGuhP>_d^d|^upj`E|K?s~45ILb@ z;0n|e3k|**%DKw|vKK*V=;MKD03yu}*M7Yq)1UGRXxjJwY-3jBal$~GOx-H8bDnb| z%v=^2F34tFM_scH3{i~8qRG|~rNZT@Z^(I}h$XmE<5x|ZKiz*T%2?zb!9+et4pS8c~25||EeP0y#GQQ7A1IWJ2l`1>IjS&t+Px2;OZ-&oBvAir2RTQDXwjVRtS^i zFeF?-D9;XQtY5|D1gQjeUE10bxMqk#XFc(BaHPSR42qd9PTE`<2m$a1kb}6KfTda@ zfijjEkzjp^!Fxn7H;^G3vmep7J^z3^;w+y>E^mZ-<(MNf^?_dvnEz{a1X?$TE= zd$6*_KOxeEuXhJzHg4ES=X@5z&9$dqYJ$btM~^ zmQ^60;mP#ApDYl2Cv%<7297(<;MZJAQFHL15nJboPZb+q%(`UYoXh@(N-dIoTS!^^ zjcd5CRpMgpNh`LJ7N~1>Bopc_wi%VU@kj^+ONvGsg)lgSOlm1F;K_zUU$Dg*dNWj-^K$0#1x^0k8oSwS-JU^A^78sc>i!|0XplH_%($A44W6gr1s zDojVma9Pap4sZM}T4NP6(c{fa-DPU8rx*KzrnBEi1b#sdaukdW%WjGZdlA{x$hzm= zY2%v8Fz7-WBab!PXVvBV&C>-&wQ4E1I9L6%MDV)`J!cw^31%8ueAg2?ok|rnHiww8 zS4z>*RBpVH!^hoG_CyA8UyV^gL~~T6rS)tgD}e?9_=|dX{<4O5Cb_bB5y}#q6w1Kw z5wK#~SC7Q?Z<8M38K_i>UH^ zH5NnoYV^0nN5zQcehMa_3y#6AhzLx^ISN|1+n3E+XF#-w#mC7SJB*6htw(g?R1CbS zhez7XjUM2;Vc=6+xkTh$VXgr|{Vew&3?YVJtC1KB6og>r0CmV~w+hB%9sm)Xe2T%5 zo-z8SSzxmAgyvlvEtE;E0E|rX$r6u z&54gB7WGjfz$vHBZSU=EezzO+HiY5+ELCtoCZ&9^0Jk&>vC9^fA3msRT})+V!_S7i`IDi=vM?;#3jn143}jlrp%)ZF+&1GXlGja&4QfV;F9P9XVBW)<(Ci(V9OYUA=WDK_Y4s-e zn3a)7{nFar>)f;;TAp&+q640f0tFV#l@`fjx5KVBT6WEOHl06z6SK< zEK1`Y?b8SX{HECO!-A_oV9*1Bq?K{XguI0w9(iRFV1^lr0ymat80MpqdpPH@PmdFR zgE|-wsh(m;!>Et+C-gdU4}L`)Jqk#>NYvuvNHyr`jp5V68;4%$R@w(oIo2@#4c0q@ z2Of|mm9=TbO513xwkl_bYX)SHf(@;564QW3l)66v*?K?WOZBhQQCjOL4un{S*FL8^ zYpbq8?Owm5=T}J8+mnZ>3pB3mEmg^-06F3!lFORBo3!^|!&guY3QVFU!i=-pKplOa z?XG2t(#*tHRLl|%frBJ1a%}WKz+ZNXV05fI4XSvi+KHq0qnX<^t9gpmNJI~g4~6zV zHWNbNEMLDw`cH=&t`9ts6^V%@aY54+QALh;^g+{k>>sRoV!_0JhNlkf4ZoJTX9qJsB1DT6ZrGpxQWLb+4n9r+~n524Mb`{A-)%Ip^(DiG( zvsE0h}_v+G7`@;&C|G_acAiZA^z5)<=dp8O3~Yug1Ov^vmtMQbitT@(!CsuLgx z^%O{|Ovx%#k_Tk(i7D4&o1vP=pQA<-UlAi1M}6@v#U`97dqxA3`8+`@u-!1mcqjE6 zW~Yv8gWMuUgF9o=c-u0jRU8$62f0{4j^GRt|6uxwC!|q$*QEym%3zF4e{|?3-la1+rS}0e5FGdh|hLh zSDjeg5Gtw;DQ04EbCC8xZ2UmjL;;hFnZVGwJRwZsI4< zTe-z)T5|8Z{DkIm#LMPgA<-x$9Kix{sd@6;8bGWpUOV6kc~LA>a<)->Oo!RRh}91a z4<}sCKhA_&+DtmY+M=tST`zkI$Sq6`V_Ur*_lZzOj`4NVMGDZ$(m}q??Wkhz2+n0x z_n=X+yFbab90ra5#QK%cb=vGSaKf{dl-{70FW~!xBIlwRS+r8vlEas(O}L_I>#^$( zLKUNgezsKks08Y|fNlSP4+#dZYxNQj zgHb>`c;b9XtCvcV^UsZf5{YZl+o&1Qbdt}(DfDPg()={z)nsJgzQ)K83@_z0n!#@f zM(y(1Z~X%6rY28?>;u%X2EN=^|E%$v&WPby;*lY@xTr&;l`8b-yn3`87w`q3-d@=o zAUq@HSh5%b=CxloifW^OXO$pOSRogTT9!K7EFIWh0}XMsGwBjn?@y#sY=}?G=^PRV zZ>0?|pzc`r3=7oZl3ybmPTrZQ`MGLFNQL;z^e&&EL0-n(tJ-l%6z#l`R(qVqE>m5IM}O>k8BLK zbc4q0wBT_A6h8Ne9#tG!8mWzW4S)P!VkZMh-K}yTO!kkHsjf2loQ*Tl;p{g0DoljE z=Nwb#T5q|KY3xWJl`bX1_%1<`M$-l$s>7HLV9R#kM$JKNtQ-v zx7E}C98;=8Z<%?ftTE|)3EF8}YBExbu=f@5J?K?WO8()Q&)xJEu^!T~zNw|hEAI<} zO1Ly_{2i^ok|h}4`233~RGIWzgGIkdO#?>Ddr5*bVS|kPpyH&>@BXR+N7#(u!2GB= z3%?PFRiwdwOA_<9T$cBuqDW*>jiO`#Z2Sg;keRXn+jTu6J*-NS4p7w*i>HH2|6NmK#gHoC|+g6{n*pO z8{~c`&lq2TE%gfZBlm5;4#btN^fX&|2Tb??8S{mzdO}>brpy<0g4aF=$dinT6zz~z zJuok3*@Ui~%ljZH-Jsef6Ga=bwUr>Re2p)+%j1{SMm7Ir_)Mm;8v6UzoSV1bs=(cU zHUb(~P9Hg|f_;jc&%Cv^Gft6Jrb^~i!!|oL~Tc9a+BE6k)*b(VWsIu95^#O2q$6xQ2&)-W_RmB zDJRgfqu)nr)6(_3=B#qizZ>1ZQuo|*qg`KbZ=lFdG^|_&X%Er^NY&xNdiH8jJW=rC z*hrq3XGL5E#dd`y-~@u&JS1cJL3^vFUIoSiAhZK(EXaP<=n`T#!vGvmsF#KKFi@Rk!J{#SmbYoE^20#zmUg# zmSzk5kiDb6NNJNZY6A8@e>r<$`e6?oC@k4UB=JyV8Fei* zGPo4To-)s;Rl*Cr1@Mhs&*UcGSm2W&s9z0_B%2myKrgdEJb-w*(!^xBWCMxl{9x+u z@vrO8-y)0*^}E%vsGo0pxn>V7i~Xvcr6Ec<4Ap;)yh&eP?b8lb47>eEg!s|n%e(#S zcFCDG!F{7Wk3fYbp#xphV}JTWjkE?n5gu)1v=Z$yF+ox+&-lAL08HwS=^}{_dMbk* z90Q|%bmEY`+&=sB*kk(?jQ@2Q0J;!YCB|1rMax?*XoUFOP&r5<cj;JrFI(Q-e)+3L5R6!nn=gV=$8$goe{ZZ(frbd+fAtk%^t-CGvk6f zCR*tA+aN-_*u$b5Ptb-4Ff)x8X%f-eS3p`{OKEISVQ>BsgnDU6_(MTmaXML=84j*C z;D=kocb7sC@8Y}h^|A;zczlJCJS;$1H2DI!4+y?;llyJXA1tKs(j~8;g`?g+UDR{%01_w;W;z`(RlrAKi;ay`z2$F5{Oxn`iwb(a?lDPsueXav)`aK7aVHl_{N_e za_C30YOAv(rFlVzoIf79_m(I-1`z9%uXB?TdP9J#Y_CZI{SShynq0mdwK8`YXn|5pjJTE-T#*wINM7JgGquJuQKB<1B3z6O{cK z!_ApNThq3>p7YHhfj9y;$-c0Wb$cSrVYEs5x2ka6WNYE@+yXsFey(g5WEG*)1sZ-W zD4fYlhCSDeN!|gi6BcSrvrvD|d#10Di|0sB$;+yB=pZWsQHX&f7EB&}97+*aL=$&Y zs^HH1S6&@IHoPUS@90(xtCr%E<}(EI_U=T9wGs-K zl|kAT$6&>y_=FQbSWbBIU85(4T8xu+Rc8gEmodyWD0VCr(V-JV^di2qDD}|?{AVhq zM1h!fU1{{decI(WV-@>KWb^V6uhXLhpHC{cfeuy)d>;uW@Ai4^OuBWlk$v|Im_m zJ${|fNxpYv`jfbtao$Y+9?cDs?}k()u}wN$yx_ewARD{!W1%Khqu<}73*@m_u#?XR zpE#L$8TevZbboZ7Pg%D3gLeSGl9Q-#wtjdJWAJUuZtI{V^N{m9T=;ehN*V5G!AyWx z1#zZH*=r0a_sXGK`+YtbE{5o3mb$HAY8nGnW zk}ahi!Og|6uFDJ-7S&h=eJqEf%>;Lze3=j{DMhfdf0oSmDGd`sGzOTgUWU(Z%lhx4sOz=7@iozc|z!z!DZt4K+tZGnGd`Y=FGrj{*Y1_I`w(fiPcCIQp}3 z5)AJ_@v?VLMfpnL43?o%jPy4K{Ns>UKM7P{v}3SF?5fC*gBzUn)$MkQu-+tg%w{4i zV#6RDwCH_Lw}=n!EhlS9IcXwS)&Y*nsd`&dsd<8W5x8C01R2VrLahE4WN70r)0WNB zdU7VK!F4xxdeZ#hOJ;b1D(D)GC7m)gOjW&f{!JfJbdsnA6~U;MYmtw(y4K)nf&vN% zBqv9J2ZB26*k|dw$sO>i6c(}J^}e!)Doa*iV;#$aeoj>*v4SogSmtE+*6^{AC(j>} zEfwEI8)yz@P_k^pfHpIFjY2O81|T4C2r&0RgZpgq zEGxCyROsS%$wk7Pnumjln(x#pEIi>qM@DDCt3|vlB2JU1Bso$1hP0JT)`~%L z+5r)dA4R{;3~5YcY&oX>B)CzrbF!9sv!G==h?Q2e_-e71tOd~2aE5*ph{K3s(v}xq zPdAUe>U;Q~9Da!$wXwb{f3fR@x5Dr6ju51Gy@s(Cu3Tm?7SE~rN7Y=}3v5{4RH3qmJhyclr_&bQbbuTXK2Y)j9N*q4TpuBaY0#IKU=`hf<+ny5Z!NK>m4S25(7Wjx3QrrIdXf0#Gb&ZV#$FFlpvQVa-F|R6Jrl?#y@7CL{;`^ zaycdV-P4jYMJ&<+i;oxsWgK-7f}gk3<8 zYAq=$5q>38o=qc;yV=?>vo7S56<8j?nv$BDUj+%f+_E+FB2M893r|cbhi+QWdLBCo}vOSA`IH zHq5d?cl**HB=)?g%<77m*#o+6daK!_%=y7PNT{@uD5;)33_en3xmTP?vzZsEdEy*V z;4KL;Ly=GTZ!z)y-berD1Y?xtrkW=!nia;GEQIXq4&~AOq05%Fh_Ei)(0{#Om@EX{ z)v7&-*L3X=>PC8(fB*aF#-brN)-#vr`c&?pO0=`t0$dnd%N!@HWu^m91DSLuegbGnhfzj#BF6z17IqMDG_707kCtW$9{O|p zQE-}B3E@7m)-i!Yp+9N=ix8ukzSInnCyIYpL-Zwyid!iJIto5+lF%ptdZ;0$S-??- zFUmK`z^c=4;7D6IZ)E61HAE0BB9zSiQT_Rms4sPI$RT^R*cO!20=9)cDrP9*_fGtI zxM%U?_s4KTvQb3*Bh@D`n_8xi@VJ!RvFF|A&I@Yts;VRh-Y~e_ zDR7Q|H3=;r&pIwJJ0s1)PGuIL#_F(rpS#&Aq!9jD&Z47leF@;;nH!Khff8Pog$F5R zilfZ?x{~L!+LlF_FDZfK8FV59#F0~+CMJy}GY(wjUH1PxcVyyaoKRo%yyg5gjS;G5 zW6}xUoH=+#omCQ$n#3;F;P~`rL&jsLt>2a??{7m4H@!f!M5Xql*06{3&yn7#@1=?50LX03$ugl`d z2w6U(DskU=L+22lvEn!$039tg*v&g|U>p)KobG=Bxm$Hnw*j@_D5&Zet1<~xus>-7 zL43Z*G(y}Jat;@}MDpQ@8q7+foR#4nPFK$Wv3amKkjkLIEaA_0o;+-O-1r_!o?$?` zT#xAwm(f8yd%EDvK4rWckr}m_&y10l@$C|6b5F{J7wTIc;t0Q& z&pX46)&&l97XF7;5R&)ePY4xWmCpq3v8YVaYQ~az7T}N;(tpPmCgCavsgMqk4yPUqUqm{MZibU_2${;n$jwdY5MNniN`T7Y-!GuxFKp%2q-HRsjM6I1ldeHC|D*VZ`7>ko9H zbd{pXUT+Eb{HC1=!kg|G2#deD!>DHm5{!Q>E`+5sdly`n4Mme-VFJv4F7M%%zqoPg zDIqLf%&_UYrwO5F^E3x!Z&Kwg9zx_x_wn*E8+9PZjVDrkdeQNEo@K-)I{H--!%!FH z8_KJ+1FS1ko0L#efM0wNr~>D_sRb&*NNLgAAVZ1(D5Jalm(+_-6Ma>_qbKx7V(|-A zv6im6$O4J>3^hNsP;|MsLXwWSSIMQ@jfq>d_e@N!$u~j-e`{%1n2$zHz}_+xOXq-% z`!4j~xqn=jv05^mb>dC8a1B0s#S||~7YnPlQsxIpLiYiRFOQBEVY0N7f)0$w5vU4O^5e!TNzcQ7xN2WP zppLWp+&QMjN5-}uD8ZN#TcmAev*(Xdq;2uIz>s9To*ZZMuMnR{0IuL!w`Ud-woqGn zpAG}1a(Z&Xd`J%f-=dX@B+KWNxDPbQ%Ot3=V$?J<66QNiopaxK_PYZcF*!DirA2Xz z)TvKUD@B=-8p_{xD~V|$w4L`&5)?A5+NO@d(m8~5lNaAX^AW$6&IF#r84V{r4vDw! z$-MRF^@P6g+8z6GO&uKy8SbrgvoVvMfh70PFw3_derA@iJfcR+YIXhE!c?FlyrU}f z$~?rE!AVLpJD$71V@BZA3-o~s4r}6Jm3WaZdQ2ngJ+7HqKZn<`(WVN+MQdvDQdp6zdhJgsi+c+LSw=wSxo)G2G;m5(7@YR+;;9E072 zu-v1vvKF_%$Eb=Fb!lQDE6FzZAmOk;KgqwrF%`&T|Ev$4fTKvSHC^|ox~>mOs0IBp z!+r6%Io*H8dZ8)DEF``Gjf=pE?#OZxry z7fqK^74UCp?1%`1urRVSQ?BO1Zz}DS1>rP)C7Ol<2GbeAyI`#SAH8%U{aY;2^2_sU z7=38c%CY4JhwkR!^*G`t{HT?e7hQo_`b=y-vuOh0S-KB7{7X*4>Qm%+vCljJ>LcJ6hflv!5DOft~-n*HX@nf;lD+s(Ec)Nf;guHqwYQr z=>UqDq_$)~pW)egmSrMu4=HDTRZ0xJwwHva*41`OG2I8ABrsg@ zi>SpJb_(5Q!=JPog+Pm2mt?EO##>e!)hA6@r11$I8N%jFEiZ$64C3?M2Bmq14t82k zON?uC5|KvjoR@{5I#RpjefStSs_b-D8zl$nR$J!ZtqR>WcZ0I2t9g$9q(vtv2dc;f zwOz#Ww$1Q`h9M_dSepQqbrCgoIA9^P{nXL*#nNcv)Gm`;@^c-kGD~#yNXY}SRK0QG zY~GAPtQX~a$zPtCyzMk#oDgNt_23A*8&o>Ulquh*mHolHm(8OKy0?QN75G`B`qN|6 zh;3v*@BXC&=CJg@rf%V3c_;yFLT+UvEHhB!6>D*=e7%7lC89a5sxVAXs zPplFZ&+iu6aGq|9Mt9=ImncCLiv0!27=~~IIpnV&2r1}oipqj07bE;a6sKx87S>=V z3mlpSAq;(b=5PCNRTHrGJA`f(TGBVydMC9?cpKFQV3$OdyvrrIu8xaJ?9~G;3mY$< zLw)SY_z}|WSAaKq6(7~=L%y#v`;?i;pHkK;SyrKg3vthyn;)<@crE>q_O-OTc3kJ! zvd`5e(NVfe-s%^%&O=arD(<7WmjgWBx2sFLM9_~=HcVpWT2r>)4eE6bBwO&KaKCPn) zTS0linRMDquR$&3Snrvu{Mga2<%Ar*YSPhBu1%~ngP@!>5MA^-Jb2L!1aJ4lJK{m5 z7)Fr;->BjfHS0|bqQu^uZT~;}y7;EQb>!np%NbK@vo)3f*3IVZ+3j@3`}I5a`_~=& z(&jDuE3)MAJ8vJKsO(*?p3&E*eb|xO`G0bqhX0=osar(~2D5!cPRHHrDYX-Ch~Vln z%FR!^qA(}=h_hs>fB55jzmGI$T;0bT9CFph@L0dy!a3iISR0tjmL34LrGbFSh(*e) z)KJ7Ra^ryms+Lo9i+wdWU(pw6OXIY){e5BS-Y)Ci~v3|0)3qPKC z0EQqRW-Y($>0kaUTvOUR{40x*d-XT=W0T$snmBYaEKiKDT!>sQKBEgVUPC#UBTd(* z{Bjg3xRl6(S!wUxJxiZDd25Su4|ALhO|egP5pk_HvBp~JbLtBVpmUnCKyp?wRV?lk zCO}`TWPm*aprQVdDkkL%@f@OBs>9En@al^mRh66`b>w~MRvL*!5{b^E34}`9${*f? zPXg!!2vxv_K&6e%`ok|^lBho!iaCFRZ?FIinh*>=9|)Q|sH=DO_5LUCI^2FxG!f9@ z%=|q|_W|d1J@6Ly`~NrU(2W`S%K1OyepBs+ci;2;__ceRRuGL{ia@X*f1ml@%zv~) zjDHgBhWp&T1+9G}%J{6aMIDFz zzDEB);&s#S|1^Kw_ItPcdzknByZZZ+nvd13*Ch z1{O^L=`_aRI?wo~g;$>hZBDTnpRtd#aWKxTI#{(x0E=HDR4R_ zF_HsiAN%lZRUE91%?)nxr5Df%0LuE5_zrk`xNn|h!m|38GHLM}ikF(QjUtrY z6teeurg<-%xM0IGcx2sOHj83F+t8jN3f1tHV^%QTrT4s$@1vW%fi5r-i|17GQ3`F# z4fXhJd_N&xABn?YX?ky%+B!)+(OG0G{P;`wn!aX95nPS=A+?mDr?*TFb8%JFVNLsl z77q11Zdl4{S5n?SEob^zRp~3&`}goOfHEpq4KaX%r)J!OVh6Y&nZ##-^)2W!#Kv9CjETi&fmchK1j_+4 zN#MLy&cE9Z?V4hn@?vW62%69o4PfTz0-@m7##S_gDNTkqkmPi#$Ol)B3Y5us#NfYf zw8sX0=VKYK-r*1&tz)l+m|H9v>nicUoR5w63+&n<&2x&YbdX|w8C8b$mYE;PhFyxL&Cphx zzMvKOEGHbn=jCv@F2I?$5jG&-u}KE}!bf5^c%W=|G?NZlDehfJZUVIS+LPC{19O~u zsrZ)`Nn_fxN66G>F#?igcg_}N6%7bjglc~lSd<%gldgKw>_DsbX6P+YF{!Xg2Eskd z2ZB(0+r=kKsx65bVd<^-%cQCB|HcC-fMs;;4;O zE*4dwRxseS{p>jzn=e2`#dV(7&~I(Mm=;Bysh%FNyL=DF!2yNYBE;&yHMm8zHKjbt0I_G-#s)o*eE( zV~MzXEpGHF`$M9sv4GU^2!p9nYPtxu%B8#}yPIsmS0@`2BaG z*|J^HFNL}h{GD`W077)8IpKn+{<{hhOBWcJROo7qCF&lnG)v~tM`mzv_V$Nc>Pkbw z658gLT@NJ)I{S;5dgmo%WU2N95-t}OP~u?576I6Bhyvj|DsawmfoUepK}sp4=~3mK zfHCi`wWLP5fNA|MpF-F}d?eO7I?czVhRy2G1`l97;fTG3+nP*2bm`y?1HL%Cog5h zcNYtf_C^($#)_cmNi3|qfijKTM5d;#hvw)$75{*`qf&TNPSCAGT<~%kTqjj7y-h-Y z9P4-FxyLtma~ix_@NH4n$SPE`%==rayXZ7tCi>0j>6)=2E1ddYPX^-^iBoRvPNu12 zk_+s_adhwErPXYufnkS_kkS|bITJ+N*GFLG_txmt1+Y-=JM4Kw3W0@*wgnr213X9j zm(T$^Tp2s6NM{=y`0K?;b+PS+&mIRo5Z5M*Ex2X$Y1+odR5|a0;RIeELlJ><@pSCL zgS%D&m*LDtcMdD0HE$||lbWOTiS3>aveL*gIg1+vVXXliGZxTf$op|AyuDt{8TX2> z0jX13+<*z?x^i$7covO+%IFk(?PInbHUwkJnzq{`Hh_+YMu&CUSW*?9Kw^NP*hAy+ z!a8DB?pXw{`|f3DR}Ep95@tc#&HH;OL+k2~C${FaxgfMt#AF<`$2(pEGtg0$>`?o? zO1hvHF-PD)<(F3lr?3Md>1+_kgKGBfgCMn>M`4ee4 zv?_lqioJZBNeh^Zb2tLQy*EtR=P$dDeD(NA))dWV?beLbi|G!Fa!|{D1=tHOIa z>_-P>rdIQ7DI}?%&g{BM%C{iXKPmUjLOa64!?1=qS+sANN?}tJC1J(VI~;xC(Ky!J$cGQJ@Nz<>b zAaEJD5@Vzb^N&R4VbpXZ^1-g|)_94NR>Q%FK^#fz?_QAQ!RMm^er*WMB5RyAXnk#& zY=}TQ+n!Hk+wC<#`B#Lk$<}2^CI3i5fLvIj89UhJyLzKYPF)V?^t-TTZ#XQH7w}rF z%maRP$SDidH1QHLNpxt=goP*jt^}dhJD~n>0>i2mmW+s0uuu>!{n?dyST&0_qLP|P z=VfHQ#ShA7eQjNNMl(b<+;@8dar?lT|F_bGfs%98VBu_3Tj1H^p-*Ibs!*&#Z-4Xv zJf{KPE#)>gDLk>Y^?EonTPBL`uuFp-JAkLmX6dZe6Svj5#ktPi4@h$~dC5vk+I7U1 zmgi|lFSffAaP6bvLcfKpY%{?9G`M#Ti=!!TSo}Bh#`{n|ox0|o76+tzef>>Jh!&rG ztaAhRRT|^8iM9dGZsrTQtkXkU{~2l8rlW=^SSxd>&Yv>9KgU(RdN(a<1<7Jt4k{1zZDQjsne%Q^|rBd68!3K0;z&l-D~=3 z6+T((#NtlnkhpPD{%vK;lB^>dT31CBfLp7>qCQj#?_W;}+1Dc6H5|0#;1$Kn8TIQ{G4ouSp$6Gfkf=T1PdjMp=# zn8GzLI4d7hPS~;o@-<1%)Mpzo$?X~NLp#*{wQz|U$CfGi;x%&;|3ft!U`J(mrYC1& zQ>jQfADBM41HJbh#2BFLU-D{`|Fzeu^Ln_ZwnUJfz5OZk>Q}R3SO=xyv6#Orj3UmR5^Y}+U3#r$Hq}0;g2SHrr_M#C#SYzr}4gSch6BaJ1uSl2c=bLa*MHg z28F#3%KY)~f_yd|Au5zrnTs4z3*+g7vxXliNZEn>IXd<$Tk~+=($??gE?*HfaLHs% z9X+xM5j2so>ehGV+ls5gaR}RgeU(e6L9B}OV(+MPI1vMGeqYW@gLZ}eAcJsvOq}!2EXz3ya^~QA%G{)i$~XuW zQs>P$qg@;gl{{v&Z%pDhcLfzemTh_j9U4C(?`qP%@38+js{9{!`vL*+mi*c+X@+K_#2qeDfsVr7w?z6{maiyAt6cB`MLubn0bWdUT(1|jeI+vivK+{WE9k`+ZAW^+S|w<>P#7>v1>E4ZNb|(=!g8Rr2ZfCmzMh`B}ev zu2gL4xL046sc8&FonVeh&?uHQjBG~@mY1v-d#i;t>;jzh47X!#Y>p(3pMamNJ|Fvx z;AL3>%j7D8PmX~X2l)Q4M zdgP$lUXxrkyK?wI{bXDHxo;YYAQgDpiPM|FPcv+DnS(4WXs`*Ih`P7MJ>rUB zr%l^oN;N+TTJyFLIRP#qLnSDhN{~Pl3p^tw0NK(2klkVe2aO4v%J#un%pzr1h@Pq~ zAzAY6ZT3x&oyBTN$8pWhW@F_I=d(RGyQ`^X_H00<`eZ;js3rA9hr{PiYs?n6Ul)zQ zGvnp5=cj@9a+0fz?RAr?-*(a27L*QCe>`=?1MZplswEmP>dCBRGyN}E4PTDF!#KqB zBy}&W#4G`8E>dkRX2;;H-X$Ru6ODm$r{=VznqOL7B_hIY z8=c_+kn0rP!_nRZp}-$rChKb|i@|eO0HAC#Jg~KG5+&rG4{1jZr5c|CrtC}?6mVgq z5}y|7BmV2Zv(5z02hy1yqzuz0?b?xz!zp^*e+Y?qs2R$kj}!(x1?xe1`B_314cAe; zrdm0&EI-vT<%Ht9Vs|1oqt3;gDh)nTmo`0{J|buSla%S6IYHRvVm5OE@a287*@LXO zU@{rzP8w4k=cqNc-|Vz#jME2(<+UMTkzFgBwEp|xh zP%eRQtVlyO0Hv`Vr|vasEH!?#X)NvxNQp#W9&mwkYw$`GcMhwK&iGibR}&VVxH-{S zH!)0vy>1RWYRgg{%AE47z2uCde#F>jtfMF%K+&_KC@ff7;nP@i;P;5zV8SL=$rp%_ zEFTEKlwvQ-!Jgi&9w_LCZFA)DA^hI?Bwi9tz9(cIzc;9<`#UC;=9Fmy94F&S&SxUN zCRL=uAMKfj)LEedZNeDd;Jl)4)cwaU@mPgYyYv7Xc_bOR(QUxs&P7`qyMcobZo~d0 zS%TYaMpjod<(WZK7OGZFaO`TVW;W5PRq5j?F%Nz{NN1r)W zn>I#+!x0po@q;RRF!evy*&zvVwBABw3C{aT2q_ox}uZoVDAKo zf@EF1-f?12R&`5=%TmB4p1f?ksmWmr?N@LTXgq0V>(Ja$NJHzNO zPd!1<5-Hpete2-JCgL9SpVU5=J`MdzxQuIRY9E z0$?4_8{r*Nj)@tV^@QiSQ}ZGG$?SOwdUn=d+oRrrb(kRRG_pCY0fZV>8hqxD)ghLw zB4sROc00$Cs)X{`&i7YNn^cqRYMxLjDA=yP#xK*~1gdem@$Ew-VFgrFR~2Gu+1|YbG5YR66jqu=rpdfJ^h{iSXZh zaX!8cbHV@5KcgS+EZ|S?PgN{dr?gNne{<}{7ya=nU8_Dm$HBo0M5`L9v)!J04{8L4 zS_kje?;QG;0kvVZetVdpm&ccT$wdH1))JvyP;7;FpB%B4TeZrdiEFaV;%w3u)e>%# zTk}9076%#?Q5i81x(SaSW10;pkd*_cn;`XJ{M^5&v9w`HoT3UWJ9|}+$CG#;o#3c3 zdd93*s+@atEGZ-O?8y?U78=&lds6c-8(VM10lb_VcDz0lQbhrMhoOC(66sz@xA;-g zAYPiw5hz+ROgPeGXVcxF(u-K()-;^^hkQBPM;VNr`BFXq>3^vdwp_{y`pZw^V|c3y zE?Zzxo!vH4cP#odXlEtn9x`Rg9{64S_tWS&(P4BrW3)_NAP;7d|FQ6M+*fv<{$xD# zWjYN-ou_T0E?^mO9--%+tx@Z)uP_U)!Ub$rXMw$7J$Fajtec z<@JaTed;=Fsg!jcacoc{}Nc~G>jjYeuIO{S&-z-?yg5c(aLMJYxNttks zy>_+0MS6m6fd)iy#*j0iTvJgkFIdfm1p1jlET&dfi@0Yq$!i6XE5eRCqB(PoZpcml z*PjyG4+q`Zv2;dK`73a!R;5tPRd$tJqDy<-w^)1|i=FThna3;K55Ft0)KQgdI;``~5G=!MA>@W&Xj-_LEm(BeER`#`^f6N_U zS6BdLH+dJeV5wFCUA&{%^v4s(v^!>Ww|rdrHru%_!R2jw8Zq%?X^_#)=(xa`D?nt< z7vkTSmq;H(hFK`Bd0xa;g86-ef2({-n(Rw2*fZbkvESl3l>M+~6Sf5*n5v+Ncl+p# zrhnOI#z)s45OEI``>~uhy@CUzkxUPe-+1)TNIYbJ|B z*P38p$D+4J&|`z}EcW+UCuw(9G<-q~6&V>nw%8ZYSjMP^1JuDsfV1jQdVIUCSest3 z*+wTU10}h^3V%fj$Z)y%5iiFL>GYw@y(kT*H$KRvP$T)g0gI_C>TcueQvR#=VS8~N zX4M?2D6TO0R(ABrH)%_E2n9r}LUiM<*h}{c|5CAF^|lDUI;!D5fl>nrIi0_jQ_|4!?vNayJ`TN#; z85Ef@zqBK6Klewaui*KT7_XFeaY$`{0kc2qjYAW&$rB)^3Lw)TN@=%yO}_A|4D(>k z;hOfH4>5;gN{yx*JRf8uS*?CtZ^ubRY#E^MvqgG4@s8b1ypKY@phc58f15CV9DDKP z4PBmIiI%_BQr0KRlaPqTcF!f2sfmsux%$(CqQ;NRChMWD&kSTdktmvaxS4aEF5t9_ zWA+*|I_>$H(jIC|Sx=WN=7iVmf?dxkV(iVSQXYzkr+O>MrFL~5dS)Hw79nv#31 zpCzc>uX0hX=LH2Z&Gw}y{ zpl#ltYm8Z?!qm9`c>_65(c-N!J=D@?mohR%AkN&451+sTlaSK2WY*#LsVf`lPg>ik zg!7*7jis|8n4}09aKgqDPY| z=ufd410A=_97&tr{yM&8cckM;QU{|~4@OF83LdE1m`m)C#H#ietZnDx3!^l*`5)Y3A?jhS8K%^YI{TsY#bJwZkUD558 zcx7MSW@j#>6w4cz)nCxiuZB+jd-%pMPEjbJRNHX2HV|E9>_pw;9~lZy8#93?hZtsL z%V;cmvxBL7qdg00n=Su%oIYhky%uX3m*rjkx8B9d4H}}WtzBRPGYD5Kd{kBSxEwUS z3(%iMaza+`sQRDA=hL6x9H(>5$N<42|Ir#@V0H zyDD3GczxUa$>`-#cguXz0iJg8UWm-FUHWB7XSZLOy#acl)rC23g1k*C!YuH*`T8hK zDGYxfSd4;QT3m6WY zOaxzj;bbRie}gQEtD!bQ>Z4W)!T`Y`Re!EpQZz-B=L&o{0%!>H%l8tXXkQR@Lz|Rj zPxkTpsoTXJ@ydVX{cZ--F^QGi2M$ML6h-8W(uG)i4?T;DD~~1mp@tt)(Km<>)0DUP z?tXeFTcw{o*imw;FUCGD88jOB$=U5KOT(wRxLNs(IKuDIlwhniCD|?rN`F1($6IgK@_AIsg(=S#R9s5 zB-?%a=ucSDBrS}hlO{Pig_?=9z_JH?;&|DCyS>2eOoq-y3Dr1sfw$-InU?pj2AKyd zZPNe&fWV~9_0%Q*_&#w)Xy0D!V%frC5znvvjaX$U?3sECGDldKp?MlHWsAItS-3Hd z10utqKbwjG!w;bwGE|ZKYrj(v`%(09euL)$f1ybpkYnspI#K9ODiIl3`VpKgXjX9g zR)*EsacxDUf|+EXVAm=w1+TemjeEgJUNO3l8hQjacz&A%g5CWfghf>vB7JIOOa~`)%k;6A15R>{x3N<}xm1 zdHC7o8Z(>f7_JoDR!x?~D$R+^l~@9~-L`!*u@kGl?;n-a5m7mE%CgLZm?+H47`F7L z#-pgwIElutW&kZ~jR@yc{ncp0 z^c(Sk=SDW*^on_fwSPS=TdIIX;>{e!$zJ=_NDq>vvbFUeG3TCj3djyy7Dt}=^P}&d z&jr1fd-%i4GTQ?jWi4Z+UkN z$z!$_#>)C$tL4oWM9Kxj2KGX+DQ%7TAZ%c*m@1#v)j5Q!3O>cN(@fY@Lq;@5?OII% zrw6fd=y&&ZWX2|bt@*I`@qIr;CDt>}_Xl)-;U>F2(On>Jids(K- zQKM~5?^gQMCS^Fsd!C$aY}B}U__B{d!_=3YDa;OSwOX&E_=H!TD16}_I?k!CI$>?_ zEPB3_@`ZMem)ld@;cBvRaiy>f8z`ABczr~Ux@wO&fTZb1NsLEG{!+{LA{t>T&(!9t z_wCTAA4PgzzU+@taa3Z@ySNTBTbsPcwX6EDbxVhttsqU>@g2I2veGj!_ zb&`Vwr)1||IqSoVL)gCQXz*q_?g)-NtdB8JH2dB{7LUQ?`bJMZ$&y<~9t4LD&U{Xp z-|2qDvx%R}1NdTT??4<~%Zim3&;)<&{N@Peu^}v5$rCKk!=hvQu>5a@PX12)Iec3T z<%_>^OPgX+rF%0uG%^p*F8h8!pLq-Mdl!?KSGW3lydz*7#y9#!%B}Y~8@Ik<;imXA z>(mebA#^N{ZT;n}SOQqBqq-J(CR5tpOP)Qw43oZNaMt()OB2d0Wnhe2axqHYqfG9Y z+Llb=F$}H?Mt-Zrs+KSBtVnVH`(97-o)lbb*Nh0KyT8XoR6k-MQ*%5iJ>sW%U4BJ;kh!K~nKWO( zJwN1Io}_Ui4Glan$!CK=tsR=B0-BFJnDQ?zHkWZ{^%P*eGlNJ;#-Y6U@o`0-%;kng z2_0M`9Wu}zT7&u0_s^{-sk)>wYE-#eUUE^ijowAqtb{~iZ-qVF}Sju~5%<7gcDAm8+xQc4ozO_g7Wu-fi?}`Af zi@ut)wcTOh)2XHN?GAppn^tC9>78f)<*rt=2HlT%h`vB=dlI@O*+u<(ipsrgJyOtg zdu38U6c_UX5OGqL8=jrUWD{$c#-Hgh;_5DAw#yPXQ<-Jjd?}a@<69BSy4W_mAj$+j z84bu2sR<6;+>zYoPA(Y%kM|7!kH&tv#@%u}aW24Rva^OLRaF*<0qyP_)CDZsMMg}& z=dREBImsZdf_dfoCoRE|qG>R%icgB>_-74jyeAp(t!fbE0(~aje@1#=JlYayC+R8qf}Ks0VXT+yIQ`s2q#qcNlPUxsPec z4ko@gIBgcckbsb0*Gwfwt*Z(hv*&SdL=@$HTU(;U>1M@RLj07b&3%|jR|c~fV+Z|$ zeK*m>yQ_UXG#mW>y-PHaDe>ddXQ7zJCam}&zgJ|V%6>0k5aWl}p8v{4WsclH@?YU8 zU2@qpHGCo1Z~z9g$$FlF$af^Bp|FSf%fuA| zk${ZD`MCn{5P$_cm5?mHx%K>I(MAe9xCQ)U!6&FgJWDz3(qCEfJE_2p6OTva-ujxV zkT1(?XKlk!w5LYh6)3L(JfI~B+IX-Qr+^`Dt6Hp~hN(&9g}HZiPdUv%hENhenSpB< z-Fv*3j7klYUbNY9SsY#g&k^Ba+i`{__Yi@f%`yi`Qd8tHw%kusjH?MhKWt~6Rf$GW z>bL^vdu8)BDpx{VJ)x^iLGHTpYJF*D$GmJRNzn=HoCA1b-2M#Oq2=&gvul4W1VVC6 zg<VU*D-cQ0gd&LvuBBk zN%6@^IS7U_-K-j!(2aDxi=^<3G}Id}w>0`RPjVMQt%Y*PvmZ1dv#0xFL;l@Mo>C~X zE|O7apf0gCG9_e|cJOk0slTv|;U1)+WOVAL#^Ds;-HKUW2XeruaQxA2Wf60vWku|w zw+i5h)JmFipRvi2N=fUQtaiYT1`W5s*JJ6hxO@HbD~r2`t)?`v@ivt*{uJCmYX?J29nG zfmVP&9pCaxg~eNBlS1@Ky~pk)rq7ROpb!g71}6xM-22*zZ`iDR>Cz|R>%RayN3fL8 zxaS$L%xdleX>W!95lZX`w?9u&d#d*JtP<927QLMi*NKs4l8M>*#6@!@4ELK4lqqGE z$mDSmj>Jq(tD5hlWchbC6^BreCCU@eI!vEfYFl?gAfT2z{wb(2J88m+(u*xXme_D) zLp7GOD#KXPxOIph4*btqqDe?*t5pa2Z!ByRGRdx_3_7=%uBRL=xeS7&eZZS`=?XWC z2^_-|$)2a&joCRYO0>{XafwjMk+C^9TdjtN?>Q3-!dX|v#EA{WB(4r?g^ZPbM0gpG zO>44$ewo_bV%L}N{|+bxjU`Q}PS+QD&N>-LSh9=s#n4*$ch(;{eFuYY4;aHQ9eB}N zsR55%$P5^#g4eI6jYj3&?msn|aZ&#@_(ZZJ#y~4icYi*Um%CWB>)biR=m*9)Wj?v3`bzb!je*7ZR7M;RZQtaA=FU6!*(E^a(@u|F73khtooa#1mjQ($u>z1^>1Mio{Zy;8d)n#+95OY z8!O$TiDLJ11OkkNGBoPlk@g@#;6Qcsm1Kq>oqM%zpoJ#I=+JC* z6{iUYZ1-deFrqCV)CMaRt?lU&)*x3~(8Rayl)PBuj}P6r&x6Mp8msWbrEvDt$&1Di_zXL^z?C#dduXaOkUtafOc#5A0!t(%1& z&Z%zB?ZgO(H%F-3pNCVq`S%#DRp|LwcwbizZ-~SriVe*U`QM>zZc^d{6z&w9bF$HJ{rgUUexVj@)wR4a0<$4&e7ncR=6&OV@SIv-46$b-xr!qj$W%?~Q?2{Op@(nX0 zdD$Ro2Z|d%pM$!674o)Dvb>S3#&MKz@8Eg5__^{YJ80@yiX?H1?r0IPE?}Q#x^rjO zf{dkU7}1NM+hJP8MFy}SC@E&ors(PU0-)0n4Wg0T@z(hlwghs#>5|+!j{(9t9YOp9 zwwG?7HqE%~vZwi%sM=5oDL~H*R&1@mEvp9t%Al9Q`xl@MItqs#dT~%hJ9abv@r8zE%r!cg*=s ziO>H9elSOjKePHXt-YZ~=7kw^@#k;H3CG}lwFkWSgEKgUOvkv4B|JvbR_vPJ-HX_m zv)IzzPT|d!AlCwDlC(doh??7jijR*+$Iu2=cERX85g6-ygnNp3@DQ5;ViS>nu`(FB zc(MEZjuDG);-NonYGI^HWJCYCei0WLVeG)DcaKk}elRa_|8ZpPpB7ws%VK_FmM4@2<0v=U?^ zZgeE1&LxJRunQvX=EMZd&1O54Vn2c!b*3z?Cz%|jk9!M>0=Q}|0f4Bd3zjxpKt5CK z8S(>k{*itwJEzWVmvw?F?vznxt!UQsI)O74hHBLkvfI$oxo|Lxz2e(gm*+4tQ8euO z({K+VNdE>IzhiDQE-9jIZ@?#~(WImi;5&*4Tgq2N^5V$ zsXS;ES-#Szrh?WG3Wk+24aPX8ck`==1@IYo+({#YVMQ=uXvDgiuJz}}S6umc8r`J; z>_#AlAn&)-X5gEue_>NqRW^B=Cn?O7JxPhb8lEbV0w$u~=N$-D z@3AUF+d1ESEJ>DoO}xU^1!w}o*$r-uSG4-@!^}^&mFRW~`;`q#!o7#MLFnI1$Q9yB ztO*h>FVd1&j&wxbkplk}*veO+KR>Y*L$mR&?bIISK%7gOzw4ND#|*|itnkRbCm?g) zO6^Do{MCIMen1mH4Sv#dn&_ImV78Qssg>}1e+@kG$EyIbn|koLSgZl$k|_UXx`k-t5kZ#Thsz#n40B=0!4*0;8ZO*0qAE!%DU=FJ`MQ^wSb#e34c{mAr1NMUHPkOK5K#OwjeU{+v8RhRMQR)EN}R zTmtfe>F? z+gq`MR%QCM2B|ijoLhNg%9n;z<|&~wp{=~10w3%cK-Gqj78Oxk797U~7XdeczMLN$ zC2YC~f_;5PEL%D!8z$R&EK;XjNNXQ7_IC7|Qn0fKwFrm*%2?jPJ|__~-oO~r@2^G81SW0+%Rd`>9ze}cXWC}%Y5`u0~=c-K+@r*)}k z4-xdeH2(>l1xHcAMcdJ`jDLYjP$(4vX6DhgqxwB1H2_u+|5beXenq2f0ZvWojZ>_& z+qt;=YtEeebSYy8i*boa3pb>)OzMGl-C-oF$7z_^+pLw@%o|GxM`jIpMk`r*YbnCl zV~Tak=PiJL?Md##WNoipVBf-}?R+kyMPFAiWV1kZq_*mhc`<2JDo`uprXq~0 z`MpUF8`0tQayJu|B|Hrx3b29IIB%c3IKqIM+-siV^@m8>kDU`1P2w$Vd7Bcqm=k6c$hmHbkCS3EEcRyBSW+t^sIvC5S=RY#4?DKSZAjB#SzXEdt~zVM$K4)Z1%B zhMs2#N9fT~aXew`*SE&$Int|XkCs7jVv3W7nn+t68#TL(r5CNdK~KX%iYwTN5`9)I zM~#?c#q%&lhs$z;c~iGx$-8=5^mfwTmlj6-;Ov;(xG55ymGK;=W%&u zU0DrFVL!60+YIzyBCZ4l$O|9}rnd0E>L^I{ZuR3L1Co;PXVomnWAOMR$)9-XOk(9^ z1302Xp&n2iR3Pa77sz)*Ac+7-E=o>)OWEt&cr8>QN*Ic(b2~6i1A;J3WfNt*U*d8& z6*0Kfp6AT7)utgY*66`++Y9nGu`-XC!W$#n{#=W=64bcvQ48@l>dp|?IoJ#TkQv>9 zF!qO7K1B;32BPhq7$E?Rtl>5q|4c%i^U@>-@|!OelYHDs*{5doSY_5yoBL>yOqFbNAg944uQ>%j%;54A-l` zq?ky*{Z#P?!ls5$>L152MQ51&CjeKL)exS#e=YDx@f?Hq1oISVe?1^fy=Vn=*`&H1{?@8G`SRM<+Q6{NuSSFw0A{JQb+f> zlsms_u^5D!zCUr%-TBW-aX&uzSlJIoiU^y!np7i^ED&X^sc5EMpX-+ahF?%ZuF(Wt z?sBid&;wD1^a#$yniC3G7QK<|$N?6AYOZm4j z(fb({5BEJ*lq^`=M<7?t3m{Q6hKIR9 zuuN0Jlky)Ka(nN;#nu|0L)R^!D-uuwwtd4|$GZfZ>x~ZwbGHU5`K7zzg<@?yc)Mwh zJC+ri_JpHMfL~vIma@gzRwqf5oW)MzEuAKgh~ou2-CVIV!KSUF0}q{i-2y^3=xsj{ zbRB8bk31nDuE0j5wwnZ$nNM}^Ah?XR&CIb}!1Y;GisCW?D^Lz?a7!EBW<=SRB@e1L zMmoorjOHCp*ZehT!8K^)5h#@D4Y%J;l{4+VQ5I_z>_HP2XJiW!+~Fy+JcMa5mUPXg zpL91_-Rft>T}xV^gQl@?!1@!v)`;5xq4^x#f{W4(HEUZA9DusIL>F&D$x)Zoqh?CC?10bzG9|$Sy<(Qhls|B>gORC>0;Y!$g0sRyD{@+OOrvANz2YK%6J=icA`MD(f+oA?RA@8!&ls>88j+9Pmj+w*<`= zlF<6L`e77pj`9ubMBTLDJMrpVpIRUNJMN672;8ce^fymM3FGxMYW%7fr1>5q$6f=o zv=oJ9uRRT5cBy%Un@^f?C2U5K&2wVy4Ct_A@s2V5s%l_nMuHEeXiEdnm(or-Qcw9< zgO9&E2Iw>WeEKURPV)1gp=Q6*&$<$C*sm1$<68@Kiw;>zWQBsZ#yVkp!-U7OO6Fe<@70S4u*U zLs(`JgUQ#tshT>>Gl(n|Ql5kXu+397)V69}HxxiIF(Fb#z`W}@T&c1sW+v1lBF%4& z3Pw-pl#uKJS|$FT%`_PE(CLfK91`f$B33 zkalO^b_oe27qi97j5DuAzYs4hh+zH`WU!Z9)+YqmFaZ&ghemN~O2==(_`2P4t;(o@$JF}(aJ-$!@IkI!{6BIJ_T`?5) zxfGvibKc*ta^39`J6z%}!dZo%_xb(z5rAvwtLfz0Jd;ae-0sf!fqCoP|7V)bCYu`_ zWl5-1xTc?2SgWXflcs$Aab^j6ACU*AI*ITvo&|JRZyzM_QQ#Lf~~K5)1X55SY{KRfMT zRlZ2(La|;O2%c$-hJP+CmVE5kWx`K&1f6G3BCo^-Fb>P|Y{)hn!?1?#)CXS$@xN5I zzJM%1G~kaA!TJu2?kjXnPR2~X-8?qrO0lkIGw;sBOmgC<@r#)Jw4bnr9*daA6FFf) zU|#Qt0V~cxpUB+T1R1}Ma=D(B&gvUa}~K z)d|C(NCyR$;n{R91${8NRW1z+(e2%HVi9z(XULuJsF`Ban0q=1-PYVI9D2(lug^a3 zl)~X!TS#P)%UgRA7O!(3s#^$t0r~&RuEs}ZE*YOW%aVC1yfni9EU0)FHcWCNlBHdl zrmvuj8CZ8h)VE$*hTxBmkJ8880Uu7XjuR|ue7_-oMwx21A#>aNG0{?a75+44r7n@Q z6J;_ix?XvlMtN$lgz)_Pkj{pUV#4*Naa{H(M?%GH9%k=#56^5bRtn)kthSlOTAg1I z)6+YolF+icG~|qWV!_a{t{j!(^Yj6!!HaW-m~*E99dnh8D7GUkuip}kl(eW{lRaLR z2VfF;Z4vrREXoeDan1cN_TDnMl4VH~6f-k3Gcz+Yvs9uIGjoZVnVA_&%*@Qp3?+uu zz1{CkzuuW%+u8ZG*2nDFu{@a(X&LF^{`nW~9wlT-ANAGFZ0w-9b)+8xg%yd`3?cQq zAEE*8mi~5Vu#(}OZo#z{LaRnanZRyQND?;(cQqLK^5loH?BAAxEx`JRy(@PTesl1T zA2^37@f^iMk=dc^mNyWu4JVlRBi$Z|rEFQ@qM9EdL@K|@gfOF3u5b2gmm4E8Y5$UHu;5>cPjG`;czBwt-Y-yTHXhS&1ppG#r z@;lRhGah{|@Q$@Ii!sXC-Z`k1^SO;R_+(QRRL=xiS$NAB`S`{Vd#xF@{-+22#|%pq z;bp?!*4x@bKjM!QKye65r7^fd4>L=wJ&%C}qD?eGQ9R`|?3!lFxvfCZ%H2lTD2nJv z#-=&DLC#`_bsDLFwCs7$`K*? z(HL6K$+MpBN?MbM-+WEv#Uq-?^r!6WC=v&y%qGbHr!3LRxYRCt90<42sGik}kP;%^+Sj(*2^_ zi7;eiFiw}AE*DJ3i-+g!g}M=o4ELk2l6c65mopNw;2IY1MfuvJ5sr0 ze1@9%OcG#m(G|Pr5UUUDscHzV&rVUbar1`Im>)pZ$vi27kdj;Fk5`fnXu)g><*`$u z9O@Zv#v4`THc#WrC76cKM}CD`6e~e)D!J$23&#%!zGoCHcV6Wt$m9Tw zvLi0XIEyr3UGOtKTh`r=Am;4yC#~GIx8a#uQ)V>^nyi$!6EOcZNy-ML^dLk)J`H!m z>-SzJ?~#TTckS+|$0n=-4+`5v<2}XuiUm84S&v#rJwcTAc9-ZnW&D^M$pA3LBCkaG5 zu4CqxUX+>zaRgdoCTciU6~!p03WQ&0slz2d=u3pCFep`%y<<{NZP^a@E^MAP~5?jW8Ddd-=6G}4e$;w!QJu9ZCEWwGa?&1!2VrN05sY986n^! zlR5wX1_jKGnIs8+DZ^|3MQ=eE`Sk{ zF4D+jN<%OVm}>)qoy>GfWli{QGn`JiI7=V=H-Js1_I8N2*>a2LXW}%FjC0zY+}rpH z4Vp8036+<>1>nk|k$*q_J~RXRMUMRd#z;(GV+An4@pbC-TI4j;Nm z!n{$t(at%vE9aqg$LQ8RV0HnC^QLti(Y%EOA=QUDb99cuawdfSe%;p5t9ys|2~;$W zOd5;YaY#lVXUXKu?aH5n+c8<*iF3gz?vhX)Kt(gcErw?wKHe4A3-I+vmZKEl<0zQ# z_0ouB5m=WN*@bw;6oo@LoLoQLpY5pV@KWd~?GCJsx zWYHV1Orb_XJebAEahKuVD711jI|UcI|y|vbp6^+rXJ!*O|)By z=Py8*>mSivh{Bj1cCgAGSpK%@9SuXGcS(6|4%e_Q!u}jDr)!oxdC_ zg|tGq%}=Dyn{$wN^Wv8vdP7BJjdi+kk*=g1WvU~i*Hbp#L%&JGB~>)Mlk*z;JjmMt z-zR^i{*ar}Fd4;@E&Op=?v_EK!6mO@L|9kgmmu(hI6k2!SDd~R&d38;=g)1;>sMxV zkm+D{WqgL7`yD5x_`sFxGDQR6FdRIl2LrkB-ezEY2n89{MFC0f8)zoZU5Xb>H^R z048m|V^{+!DlMfqEM_MLNRrFAn1w}N0Iyc^&?kZJUiDmw5|ECXa`mY1g)E}cmyqs& z{ej<5@u_RxM-q;jJ9_IbyBmIi?1{U!x2)Ufbfva=f$!?>B{mBLha>4+rPtV53RrJw z(@wSp+DbiW>=BI24X^_$@zC^0YA~ZQ4LS1njbL|EMsquNikgaRsyXL899(r2`Amb{ zZme45d|2cZqa%~vGNnCs!YVbM@}dvNYF6mlc0jY^G-8D-?oSAvYnZnD+zX>&9Yilu zo6F*%$t>+0OuhBkj4k%;bA;mSyLK289oT{i3D4X5ln}V-<@)QhI zG$Rh9Z-GjMD&{{~5DaH|rw-%VQj{pkQ~~`CxtVx7_}ZY^72)(3TZiO1?5^2y(K>{W zYZ4C<s8uyV9Rw%P_}{Db*2jg6i)#J)^@@?zC(D$s7k7|IKzKsuXC6kTQc9^USKbqI(|LF&~38QLThf>$GVKt`# zg=GZvMA#+C+G};*Uy{D9B0zsyoIZMAM+)o5+P&-oG=a?~EMNCTh=SymiZWYU7%5gE zm0XH=nRaEb1*ey|ZrK}jb+&tRH>XkwY4bzLk|kg}$_r5i1~Qu>N0Hb<{ETg;UDAs< zK8H1CoHcPKGZWRAwQzVIp z0$vt)vPOd6@6fVpArT!lqT^8ZIFnqn+6D5a4c1oL(gRY16qp~C&3iE;aRpqNR0Ft1 z!5VBWrrW2TtMjod!?*EEA1-leT^q8&_hn+|+_XsCu;R|ZC9ncOFDg>L8D{`qMk9kf zTZaJ|Zm8l|hb_MX5sE3M>fb6p6Das?NwVic)y&hXD?2Nxs8Nr5E9#gOW1&2bF_&r$H>!mQ2L?8 ztRD>9#VBM)-m)CXa%ku1)pR;y^$mq;DrhH0P;KcgPXH6n`qrmB_8J~k<6|{9)6pMK zphmtMnnmJm-k_CXHiuvNY6HmU7~*_m^%m^9*!??6Pr!(i+J$!b)io5Vh4uqxzb&r!WpLxT& zNA@PCH;(X0s5rUYqDm@1@4_1!RDB@>K1ESl<~@C@3#!YzPhu}srMZ!mupK^x7Lz6SzZlvhJjg?LQ0?loiZkF=EU zG}?52D;fTvlP71}RqYuGKXj_Ng7$m}ZqHq>1OfP;o3{5Iq>4L)t@=h&)K`Z{j_LaD zrQU_~hJp(_n*k%NvZyuNgbM&$b^#kdAbgmVBn0)hMJAaa;yG0@&!n$r#~wIRXWKc< zy&^4Xl|m0L(NTszpyAm9%-}aUx+NYZE_IdtDNW3Kv=dGebgGR4>9>kT3DmeM4hvq$ zQWr#t7%N7)pfb1yzZ*egNr+naWIC4aWR#>)T9pRd@tB(0tSY)zs0b|XjfJ-sVhKG%~lY4E5)|A@>L{)okV4vAkb zQ2iJa7S|h92nOtS{!PzUKE`_=EjTb%65A9rWsLA0Fi)1-pgV~UVP=55L08!73n_HT zm_@sW9Y$Va3E$j1IAd%`d`!1GJE%&q@+Fuc{&pgcGS#;rh44hrukuH*hH2wiO=&50 zT}qLB2Kf!DcSuVaL4PEuzvhjBJL)Z!`=w$U*LuMXglp;wR<@M~?-zL`^2bYAeIQXf zkXl?!`^R8NdHiH84qsHG$W^>gK#N?`Y@wt33iQj^UN{5c2Z*h#;zsxT#zlL1U}aT= zlN@J~R~0=uePNM9eJOD;Tg>C^Y0aDcxxRwLWA7twr}8?LP58t^vUuj_nkx-1MW99WVBXi?0Q)<<_G<#${<6rqB5hY{4Xvog&(7eNGcxt?j0;vH zFa@~_W|7jEPM1qTtzk3|H^r8k#^Oj*wq6!9uGWEE_Jh`-;q5QZ;EaP9WW+@*OC>+z z1t!+Yr6=q@?3@QFF+1l!wwU}Bm)EIrHu2-=Z_-iv-NFSK#qy zMHHt_9fVvnFSNpq%3u0Uac&*~K6!AuFbX)+Qe&(2RIErw20y5$`SVkHYL@kTG^plb z67@HyuNAd~JSFw0M1I@U5o8vKMzuRI+9>JlT)2lud>$TOOEFu&)!8ACE01^ULtN7~-&tE25OI7mp5Kd-rSBGxhN6 zZEYJb%OU^i(&2qwRt?A1KU{ug{cg7sI9*zWH% z4}5-nx-Z+$m+nXG+ovye{Mh{0?ay)F$(mp5|HuT{@816W57hR5QhEP}50|fQmjM92 z>$4KXhXVk_N&#m9QbB@i0`tX*<;aj01tbJ^VvV9B%^bD?R=qLTD~t=OrPtYeHnBCe+_=Ad_?{!`pWr2-Z*~JfBlN@ z2Ilme`^4*R`C9zgd#wBVTK$@< znU_D`-s(2=t@8Q~>N@j1Rn*GdK zq(9WR`qKSqc`x~xzQ@07&xmy~<@BmIf)G+(AqllT8V{O{5De=7{Zj~r{#hZZWI zniv6{IM$?hO;o-#k%D^BZ1FEzN&LxT1U2H=l3vBA#Fq=?cOwI+C;LC?lggA|jE$fk z>>E?Y7Rui189_b%(F<~t4xmxYlcPy|om9>^F@kzQRAHA|k^Es?DD~{noIbTu$-nhd z&69HexPWSk^!m{Rsu|eTZLPNnR*JbU-1#H(kDB1Ix~_5~_Y&u{sxh9k3xIA?S5YJP zfRODljJmD@UUv)!iDTAXOV}F$O7|rUtvOoo02%-s4;jdSOB|Q2_mq}|H>M5d<50{? zrl(esZd^9z%+bp84ztY5eYfPW{bnAPbO3I}vThO{A6w8l=BMrI)mXUwe548%10da| z3gK7rh{^keA2T1#P^MIGqsS)u((h}8lt*$GMD)iWf3(z5@A!Mz$p1`PRhep@cK0vu z57yEgBDjc@f`Cb4WddqbWIqe2KJ}|a&i#~>!(xifZGgv%TY9+Ghv$ugc1{nK0`Epr z!=^-;dp8Q%7GwbjTcw@KSZ1Y{WH8}mRuhpd0Xb;~@aWWEID2<09|<}5EPXYxU=@iq zQFSJ*Mf3_78^nDt;PK9PK(jt=DC-a&ML5e`edT*VfS9?fJw4+vT^g+rq$dOYEDi@J>jN(?tQ{TVL#UtesCl?p_$H z*p#h%-`hQ0KS^SB&oTqLL~mDE;2I>nSChEoDVY62bYp1 zHH8X=sxJ?c!ZegQeq|+Bh9tT&%$EJ0kHoPZ=fy%f6crLz+cBV99c*1rWtRK|F>LFR z1=9%nro&_>8C+_|<(UADC=n1=yRAS(Hz#ht-aGfc(S~h+AV`wvo^~cZY84C>)Hq_? z=_1UWt6==MOlx95_Oa(uzHJUwh2rNk|DMj_Ubfs^NAOwGrv+A-jCA25FU1pU)S#u` zB>-_5PGS)aGSzi^li$aBQIbdZr zD0>huC)hC=9Jw4^?~%zSzS-)Z_IXeIJF&I|<1kXBHagjGknl#f?Q_*;Xtb-Tw5*9P z$DG$Oz_-lSZA|nups~Du)%>C_8&xVC{UEY;YY`f2P`E$Nv|e^1L?SKnQ*I2fab;Ol zak>~qDNXCm^4hygD?WYeJPHD26s#>l>&HHw_0_egqrQX{0?rQA=;Vabx2LcBVOV?M zLKUOp*|6w;0Lh=^j%tC|>S#=uHrf@?7x7?A9?^#C7zCezVQ6I_!Leii82F_Ey_yA? zC2c&!;I}61EKi5;`IQIxYhXx$)drxkYq{5pB;P22kE2XW?HLSm)=oq8kCO{pyGdwx zr}~`XRy0K(p}H?S>5f^#q&|ai;*Wm&&MU9jt-@v?`W#_~jB>2mxC?G>uOy%(4g~Wk z!X$W}fv%(a#D0nJ<)$c8oAbrpEM?`&A7R1>9!zv`nTcn056_sZ!kjs2RRwsMTGa=u zGrln*Ct(M+N+Lh8$45{cy@7=g+F4N{@@vm0Xk+j!D5MO;V9X5WFP zeR_>)mbM1XOCic&Nk?+Yv7TYr$G!0t6X>pwR@ouoEanoPi6}z89WD3b)Al=f4+Vau zlQzJ!9kS?A8BBwLY0QqU2nU#tw{~~`4Od=OlXT4ZVtHxHSEts)KNNTo#Dw<;`nq`BdozX^lm z=ww5-0O4rCbCm4$F=BUyo3hSk=e6(2_cYzgaxFPe_yGBP44LuZiV+ArouGe(r2UK~ z-qv!k2;o2Te`_5O_rpYU$6KjryP(B&=|Mj&$u;SuJ6==AJ&}2C_&9H;SwWPD3RY_Q z$Gc_eMh`iTu_=UiYqS#{@pFm4U^g}sPU9tabktEMs;?C1w>Qji0~3upsE{YD5{fo$ zNVF4Ln$_pZJv1dr63q5d#x}hCH|!^U>!v4AmQp5!pZJ>$$P9J-rmTAdNcIj9DGl3J z^;j67$A5cEvxh>=&vj;#EWE3>a^BI`XE`yJj(=n@db zK{Na1O45Je&q>Sw1VU2wZa(ud+aU(N1R0z0R^4T~)BJ3eG}9@7|0!dXe*swo(E?ep z^PR=TmivMbxU41Uq5}}W*cmCh&;e!3;kkbRTw}nrTXSK##37ARRn0APAAKW6tr`{7 z+9=HHL%eZof_hzsgOQBXSEqaeGiE7Sr0AEwCHc>~t@$F4d9Dn9Q(?2S%VEL9;kKqy zvkYXH=o`loqNGHg78-4POm9Qq7{;NNTxiHc+LEO%s^UCJC&N_r0#H7)NE~odF13>zaCwl^CjPt8o#Vp(%RXIiA|EAL5l3N6i24P0s# z?Gz2ZAv~_%;;^Hw{8ohswc4+WPS8ixzY#dPR(EUfhLhpZlT{>Ep-M)<;^~gCv+gp5 zs_S;sNu@vAtk^@KSm&xj!27Ym>xSZWC~TW^oY?-GWU+L5$${7Wck#7#QI%21aw};O z0s9|4jmTie4Wzc8?rU~Fhf;1643WT~oR|xce|s`Zv**1uEo?z0_ZEUBW~)17dWyf> z+uL3U4%vrGr!-cSimWz1b+UTh<+)D}3Qhjq4f@t(w0@j2Vpd?z1Bxi>T(?t4^?{G= z&&Ch@JA*Xm$eUn^M7-n8zqPMdpB_>CM!0p6p0S~O+(OHw-Yv+wiW3)o_2_X>g<#4o z*ljVg@!!5>@>|$08v8X)+z48EF)_3>gSE?kZPqvDkX+sPzQXMY-JxMavjD)pn(B+D z>wV+}fVTykp;ZT2;p?eP90g3<4fEq+y?g(yp(gxg7mj32kcg!J;ko@S$+nRq;qwNw z;4JMZo~Z>ypWoByTk+EqtXo~t8)&RtuU4HE)ja)4%2?@YXa93*Ep!V@bXofO!n$%v)TxS!qH zV^D(7Az#-$6Lazz6w;eAI;+l(OSF-~YpDwK#5k$V9Aavy2Izz4=~ei+_%UO_%o1p-o$nF+ebpx|=IZ?#$VqAJF0n2m>U;!w zYfv$Y<%R&3Lb?!Gu59U#z`jY9A z%1#Fhnry;;u2$qi(mjQeR$fiza!n=qz3rwtR#MZFd(*y^>7AnqqI@=&rQKqC*(=|e z&Jzv|iGlR0Sybcm0(hxuro7Qb%KG*;?+xW0b}N{@NH6j8@{o zl)4*a4Q!c;1U72ubeQT2ankJOa75k`kZY+BQ-*FpH58Nj=+*vtFQwKzef{nIe~-c- z*-m)op(!%~X3j+$3O0U#hY?K+N=>T4!iaAW-n*5xJ+;iAKV)!DeB(o$ovT76!tU;^ zavLO9lkL%qEm+w%8k7*A{4XeDmhh8HSkqlWr!wkN@_bfsVx965evgqaz{b$x|^lr6mJ+l{uHt0 z&q@v(8Uy&De|LSJuN8?W+L8{6^=ep#GrW1V$f~(HED^>!+KA>UslT0t{9-3@S;_un z{p3oKhe&Kr!{zK}f;Jj+t2wJ;xiQ$C}>^xScO4bhG!|n$w z^0FEe02s3(A5+2kUsipResK3gdYprFMSE0+rLW!vNtUz=MSM~D0ebwD_7 z)s0wcdq4ZtH*(({SYhW!&OlZQp0m3*h?gV_tf0g{(Ad9IIe!`51>ygJ!M^Py1MHbJ zvnYTSG4cn<+_uBF1^ye?jiCGs?PDr{nS&OHJDZ96R8cc5sTBH+@MXSrO0yEH>Y*^k$@kAESRKB&g3nX}f)Jiz!tOdp_HZP{5F(aoPdKFhti2eC7%>(0qq^ZnQT7mabcU z>G@|IuY}5ZO8c|5^^i7kg~Lu3_(jujg09ELgr}#?()DJ>+ALy#||I9_pd8{U9tWmL;rbR-yD-1n-Y9T+-5+V zpAYs&02aF!xDQ}=El<2*rf2*M1&5x z7RR0BrvoZI)&E3n*h-s2%powEiddjZ#P_GFf44k~eS0H+<3|3tV?z==i=CmL8HeWx zUSYsPQi1N~rGZ0xDF1X>{+8=gHC6j2p??LBe<}TW@&%7+$_tl%3=}K;2_yl#vLakr0`P%TZEe>v{W)v$W)C%zCZU6^!6NUX zV~)L}y8CaJlK#7EW&-7Zp<2@bOue+QqiP?=$Nm9K_2(+fH{4Kh>-{^7BwXY!g^Vvj zghZi2Q2>^?v8@I_*h2BWyxcUOh_DlG9h8V5dU=Is&>@%`*8jTK zUpJcY|Axu`f!6&SE7*MdxBs}{`|RICsS5@`;EsR+%CYh9KH~pAOwi0a!6^9HST(Nv z2TS)q<@&5JvwIS##+?73D89cNH?v0RFQ|0lFydbwjguPv4@&Vrd%__)9y$2=|L$D; zS9ErZGInj`zrXzdrojJATK+{;{y7K!#WMU;O8UwbUn_J=%(gyfikqo~5zqa1>d zw1wqaIu<$)SN}1kL&`75AK~0ae@}ejek_H0(qh)Ry;Ya>aU}=tBCrrbg@cls6*Z;# z2;|9rmx^xFg_`S`j9FXP^1_15c!QfcF?dXial~(q8J(VoMeq2*+=AF;59S>=Gd}a0 zQTl%EUaTNQ%TO~x?r%ng)F5Q=!t01>VBg*Z<}C$L2EC>!n38k{ELE!XhhbmfYIET< z6VK@R*lddZYt@6dR(*k=L$$!6XcVorxsqqeaYxpPm_03qF$Ky^HT;s0M1wRX*N*=3 z6d`vS#{FK}z}(6P_gc6^e<^lsALn&8y0y|m{!UGHf|K_maz}rRw2;<{7j5E*5MJqh zX!5j>G0n9S0WP@?89}Ro#)*MlcL?`9Uj2m37(-VKZ1-i$&uZ~7nR9z2on9ce9+!Gg zL$0tZ;%9t$IU66EAP%!BVPExtq23YM#l{T!BSE)e7W=WUnlTQty5(p>S9Y$S_(2iR zd+pN$*QM&n<(wd28WOo4^UuBgj|7WL_Pm;1rFsE=MXQrlAjaNWs-!Ojgf^zcT*4}kI8qqr~mFgdtg0UEW@t$Ci!Y{Z4FXV^PI zd=0mH^&k&;1L{n~9?RSHZC}u~9a;Hl8yfq$0lsASeTc#RY|W}NZeB?|vC9D&*JTW5 zUPf?X*S_Wm%P5&m4pu3zrECnMjC-)Yw|g~p%S_GE9AvjMe&zwSc$3#`wUvU3w4eFa z({+<>nZ8H2JD7w1{rOR$n<7fngeU*heI9|;_^}B~e;<7T%|~MH({ot&LbO6t1w>Gm2-x?{QOF{V#(bmLszga?{!HZrzVu@q?WZRx4BXTnHX zkq^qnOYLa$Ln}s{bxvq~A0Qxtw4%i6=9zX4!tq|X5fqiuw2pcg+it$IWN9s3$ZTdR zi`%`4LV^LfFFxFiBZF`f87^X1RTpwwbYCIR7r<45Mx(7dz$Ms|jyi+r0*YA(C5b8= zy~7h6yo*E)wq~+g;G`7)Zt+nDcrTVeOS(LyJPW|9h#MssU?uf?=g2U- zAZNQys!>f*P%a@6tje1ccWQUOv}`GHw?pwp#D#?jlh56u>AL$&)IyYNjLyvA=lypK z*hQ<9_U%u(=)4iJ1fL!ai8XF@7JRnuxH6(Vh$mqBa4nRL#oJ|tmyF!Q+P*EfSz0o( zg$S9{+BI$oH8=LNO&`DU7MN57B(`hxcH-@)2Q73`7lo3#>{yGu!cl`{vZ#hsON_I< zH{W_SSD{te&Tmk0{2ncWB9gJ!NRMfcW>}&Kh8Kq0a$4Ba8_)RN1#PeUl;FV}@)OhQ zADtHYFDsFHj69Xj+}>u!u1ZG>v6l+vavvVhd9^}PEGXLgB_w3N+yg|%Wi#jKgBMbd zV-FX6UYvWFxRHu<#ry3T_;8SxWd#PAL3VuZ!{g21P)*waWiseD;<0Z$WNcm=A;ssJ zPnu-%kwrij_9+n;(2--p0Z|UlCT!@f9AwMkXgNrZ2${k-NlP*kf(<+bDxGzExI`jR ziha>Sz_6J}p$PJ!8o@2SlK?DnBe^sA`DHE-z-TA8Zj+B`*?N6}UEd&-lin?HTn7#p zNKEx&b$YKL)%+!8n z-6H^`Gg#pxCnF4si*Tg#G zo>@duP6Ly&G)q<}NH_XOxgq{itGSuOQiBe3I?0=UMn;>I`q^n5B<77^D^RXDQkD@U zW8euqc~)sU&J4T`y6lf}yw8%ofy~V1UAal|=icNHrTwifq5+WPoUOgJe&)DHCvCkr$#`iZ3X_^#!hUTv6^fMIJ% z_T1|rL3;Jvdx2jK6N)k_M3{KUX3LqEt>Fmq5J`93?btB`qcG#1N;E2XY^u^3uP`9J zOYuFau`;|t!07l?vB%Of;Bhf)sn)UAgER!#T*a9mri`mCH7=VW`|cL!$MbbZZ6w2tLLy|nW2(<*YCRM?}{OUNRzNf2DK4P#bym@&@RF1|sw1=Aof zPX3;&CFpiUws5mz{V;nC0M^v)v&%#)yjb;BA^(=gVVfp00szbH(I9A)<@H;<+74kJ zj^mg1scZfV9P*(rXc48PfWn|7>1Sla$CK4g1BjFAmNkvk%M6AR+@G@O*=cU`wMtl3 z5~W>$RuZG=$Mog9g@Db@)Zz$3?dqp)x)A{n6>49Ii}cgnp*I0tuLqUS!Mt>3oh#}F zLh~RM8sD_**rM>(upt=f&oeG1ELLV&UUp>{z3dFb6&&CK&9A`AxzX@`TMNiQX$=X7 z=OT?wPw>m7H$W}#2jhhcj)7A%fbBTPu+kF^=I%8tdC|^=?bGy`dr~0WA0BI?WJbkC zVD^KaC^f_@DY`fOPK_C{h?wl$TNz8n{jSE`NjT}sN%%>cst(;a>TSRRgpveMLzbk$o1wUFz7*>PtjevU_oT=`7alrL#c8>99H)9Ok7QK9l z-C1?EOwJ!wYhF5dDP%}xB$5CqA`WS96+(gN^uBFcQ3%h-^7JMX9$&KVex`mZqDDAm z)3smag1iM$dQoIwvV<)OW(`l~7BNv_Q5-0hIiA77awnN7Z>(L~y1^a6UNTt$d*A~I zCcJxXf5=xPXnOkAj>sf1aM4{Beb-0xP&$Sm9y&VXhx7l$;QD~b4u&J>v@7h+T3Wwo zO>-DE$*nPr>GK)(@J2P43MwlcZfgvE^oHjl_8g%C9u?81H)tRS(JD-X^X`)db+L=N z96OA5h5wACKD*kM3fJRX^qP+ApS>!4#;yP8Cu;t$A8NvV2GRLe{RvZ&cD1Oct7>8<4L>FgTkvRfiKt$Qm)R zxy%ck<-++=|0kygnpBSVEbq7AsfKs6?KY5Kw|hQZ$4?O70ajt;?M8*M8+`uwNpP1V zI7Ro=Knb^)&$`gm7*ZYHm=Lt`!*ZlyTi{C=BF+`Bng^pT2uBzgwYmw?I{gJmP zlrLPJ8LB7;&@PLMX7sa_=(anjha2`A>OuB}dxTj5zCuM=gM4a1u1Y#S?Zwf>fR%#4 zHncZRd3V+^@PHa!hI%u3CC2o{Mn~fgQKyCyOBK|C5WbDU@5CU`b9K^eZf>@LunUt? zPhw4Up{WZKL;$@Ib!pY#ztlkSa5oUs_^1C^m(gzHdgfKFJKe6JC|2FBx~6S_Bw=PO zpEQt414gD-Y|d&AS}-?R^>Rl*9B;qW87-TME0UtXRiwmvg)^cY_6g7-!ccx$4m&sM9l!XQ=G>#8e*iP$1YCP? zI#Z?pd&TtD=UY+swuWA8ER|9m@b=E@<|J8(dw>UV_A69vchEnN!_oGtDaGWkfqy$ZkLlVhPE*D;|$e6FWDXymfLLmLnog~Og+{RLJKk0 z*-;`J22dnVdM>NOMvLdfh;#2F-c@|s8&@l>y0|f%>lTd;QS*sA1{xjfr_f!w_1dTt zH&a(@p(XjE)S?iab<)-3$;hw>O|ZSYnGljKqr5{$^M`T`0*b6t1*MOsBOTgUPjwC} zU0&x=avjDaNCEvYe5l5pfifZ9;QGUPC=~g~0(z}hOo|7$n0ZIEi>C?HJk}Za)<{2i4RT*OF9Umn0jYeY7oD432Kg@QOG{KY4$t}vmiMGAOTeS;Tt@A z^jP5R*OIC7cm*z9e#_P3S|O3EPCl&z9kCmkzJT;F#z~02V4bib4N@+LJik;nonAbW zA^kLJnp6c$UMCL>h3cuP+E~fdmle4*bNh^LvHxslWJ2wbH+uQKK+WN3K(AXMnO%#= z!i8J5fsICitCYBjS?;wxg!kZ+X@jywc&M$qT@1!MX^#uEl5oqs5Wcw4RvHCBOW+@i{^Mv~f;k^T#WP$=___Gv{u z#A%Kd3~hHV09MY5^zzrHWPk;up}IfMe$1h5(gA>SCM@rwEzz7r(1SbMTZpKPrld8K zhE#MubgIr7Pi?#3q?jCbnPuoq6imLcJ|n(8uon%iXW`|Z45ADflp)7X6JOdL4?4CF zNV_CX25s;fKhAT6lw6-P-5OPB5=^v4g?uJiaa1z_>|qk(TKvHCdsSwH|6n^T)i{-u zD5?UrY6oWSr1~LVUdykOMw;BJ>zyE4*bg6ZuB{C@tLvcPm z-%c>s?nK^mJ9KK`A5%~KHM<&8Nn^& zqUADd$)a||U5ZlKasH{H9l!YAjJ_DsrrPy_n0=0?MvH$7FD&6n20Z`!14}b1c88;HZ`LYRj*bz9;c##0GK>wQ&`>$i z+cxO1?l4S}l#+`PRz+V@T>g|f$H=7|9-lh7L!}l9{T*BXV&fI1AWTpBkX6Sxcv=5%1 z0MZbM1uWL=$-Hyc>s6*q-h@JE+??_TN-OCHgz?Exb(HE$aiDzX3(k_c|{ zL7{Abl%!Y#wUz3@k+E-OUy{=V2DTU+7ktGnBBmBguZiK9+2(X1jX~khk@!P8A@wH_ zaN-3n*(0M}r#dk!%a0(;(l$E2hRUM(+K@p_GL;*f5*(7ZhSS%ZIgJSr#A8RpQSHq# z4;JBLfKNo?^j|vXFe4ZHh8`m9bFW@2$BVB;7q?T*Cydkd#oj9)AI{IBBbPgoZ`YvX zx;f&)2r!D1Q9hbS+$2{5v$>12Mj}7iQU|ttWkjHYP?C814^q8#{AO+-k_Z5dFdsrG zz5SnjF)QR=!`=e*t-9Z$<9OE`uVUvB-pg{~+x5A=-n#f?uGZhC$(Fs8JL>#VV2#-!bKV}E;TK=tYpWAYCxUHiqA;YN^eypFgqyYIk=rRnO zLeq0*ie#<0Y=z6qdl-74xg8n&D8~+4m&||KD8|A6^<7=QWnK5wc z1-LxgMM)5$qE!t87Vmqkm5b4`3ejfm9cViL5Jf4k6~IYrv>QVS$Hfn`cdBGC>I5<7 z4zI;v?p~4<5uQsTR3^%g69VZxU*oATccFCzd0CQeSdtY|AKskAP4G>HA)E zT{QvRe(E{eMESMbGn4{=%|L7yT@Pn?u2J&l3%Qdb(^wi;i2DZ7)$}_jl2Z_O*!*TF z4pR4*RbE`CTK`YdzY|Vc8QmE;zmQ^BH69Fw3j#o%4a(yA2(Xo%DJ7u(M^TDg0&)pG z|5}UbzT&q$!l=T%j+7ii%*`l%xhIP(k#NXX?_%M7jioTG=Iu-Yc+W-L4=Pai9?F z;5lZQd~EK-zCc{}GZMWBi<@}}f(Osw8gR(Uk=0hT2yoCoo9cyVpf;lMdS1Fwc!=(u z(G1BPYl{ywcjCZ&pBg-3X1NZ%EMuHCmsl_+`tnBA2;Q=J7qP-f04$lbU_FUdN%oWX zXBY00CH+uZh2NNev^GM{3&U3UQQ&xAg+3?*Pi8-)yFFDQwyV61{CDIZsr~2?#*Bp6kT*OWt8t`7^!k%Z=Dy_ivJI#h6kKaJWJ*io2 zrH!XTxitG@ZaeN`DVq}XTRv*GHx;|uHt}$&KuA);-W33Y zi?KkVXFprdX|R2_n^|t&L!0_0DYOqct3P%@iE3gCU4hjK_e1*q>12tIvykd|V^Lzi zSnVBUX92ZEf?WxQs8|I5!xOfuU=wnfkfDWnu$GWh+as{P?G_(_b|r!kfXmnv?0{%A zO`x?L$oG620E3)ZgAHS`cj=s*68FRS|flR!qKxmsYM!wn5Sx!W-XIuJfwkIAUA>B zg-&P$Eutv15c;x0WuwXyN9p#XDA=H|wHp*TYIo?y-vd_M4RRXl$A4WqhyqRH7>DAe zqTPZuadN|h~G$HM@p|u`jc&~UI-$X*zlGk=6E>f z#wx-(c-sK;95(-qA*7hrB7z&wsZa;nA+1dT58#~V3h;%tI+sedkG&^NDXZ;(fy%@$ zVq_DuN%+%DipU-`ke4EvM4Oemj}jz%ROil$OAQIZ42nz)>QBWb-R(ga6SDCP8$UGM4PMg+yqAjAXmfM~06p zNT#ehSW|OfHdVev@bES-rnM*yh-1^Wj@?eR()DjuQh%pRL>5T2DXk?rYJ|%iZ}mHK zGYHAnG1TUXeBg-npI*wdeE{`u5#fB?AKNT+W$gc)-lg1dHkT@pCmvQ+!%~c?2PB|tFc=nn+M*FJD&~RRK;pDYY<3MmO)R+)Sx7!5!0{rW@+^p-huZyd(BtW4|2(bXw3pn5e>fNz0; zr{dgD>sFd*yIM(jVJ79`@W`wQyEO5}$T!!>wRi*rSTBBcet11`(5_?O7 zy@~DgoBkm3nM)y@Ufu;GzK3m-hDRAWKQBdUz^>pfrC{<0KM9MFP}P!MQLnoHh*(ph zmQRk)u)sq~!DtyU5riwrjPQS55-MsAWDUiYl!kK$86xQ^s~@btMtv@Zp-6-blTWeKQK${n!&UF2#1%ZA zAgSc>1y3i4DtSCXQ_12Ao=*@|=Cq#+=cm9x0&YN>rvLx|1#2Bc(C|w50000l4%uw; zEe;2>l*f8oNInFP1~@my4yMs659@%vh(qjlkm=GS9MWC}&eX%(Jv;i|D?6kd;v-3w zx>5fH_dVT@%yA-&kY;Ihl$w}2;KDLC3+w!|wdx!rFeX1RIr*Cj2Gv6-rUa8oy1h5&v@-aZ06wg(Flybo%X_rwSm0D3C& z&fG;ao4@WIPYgeG#Q0T%$i_^yT{j2mpw_2DHq2ET(Zn7q0q<+{A!Q6F57ZA(Wf@NmMt;(;oEEKSw-1g-4h*n^e%i8L2EC!;%IDzVOg+b_6Y0dSMuJ zgk?{MPh(H|H3lKiiuFNSejrD|62lsQn4nhLpjF~gCNf-fA<L13&dw5 zpE-)Imqq4b(Tez)`t`-(j}2(q+jI;KU`|=oO`B(SziiP-dOdmO7~UcY5Kt2gR}sVY zux3*FX|cH)Y@yVABOuh8EC$*?TphWA{>=QX%Y5TD6Gm)=1zhm!J?c3F^X6Unj#%HSoN@8c3|O_3L~SS8?*%rSEs+ z1jFfS%wUw=UwMt@w{W2K8)#(t@do6%>lQax_T%cdmbRQR!T`XgKv%ui>=-?O#S(Wf z_V=+bCb!`vZxTf;O*k#@4^jer&FUvqlmQ+gfEiLaogB#lq5gB3&TE>iHQPF{gg}f@l~!b{~?rRntS%6&H9MJ zaM)7b32>nAA&NASF#gT15Rqbs_eArX`*vlNHt!%Qj6&8@Fyh=Gq6yt(XT zVzb`0yd~X?E59yX)Y3b>;4Q;SS*h7%7%m{ zBZ8x>RcL>1*uNU;J4Smc{eSm3HaD}Jrh0o_&#C+*F{H}$p`C*Sh}>j$n5#Vpv$Vgixmh+K;_gloIiZ4w>YoC1iy^u zFTRP{z+VltW-k8;(ir?+97baET3~63Ymt%^$_^GtD^AetwH+?p5Zq&+1e9uqAiTGn zA2P9!CQcDm_vK1DjK7>Zs*O+!EHAht5(F{^R&?<~UVdU*1tYaE^2J_lpCh+0lN{A9 z5v%Z3%F(dZGddF-78MagoIUIsMk-l)%-88k>X0VASgUqIf)^%38*+c;&of z>Ei_jO!l4w)9G3ZhL6at(rIguh_c~*2YQ?CG}ZCPe>@fH;FeIm28H^wIQ^w~mYMH5 zsQ(RPw6iI)90VKpi!ZB?wGawOm9rS^#Te}G!$_L?k`PPE|XmML8xcV@9 z%#4{}Xy!c-b{Ao?ylaQk|>x@am_z}+Xgyu0WZ~cEBNK^PWH{?XsDgD}e z@@rBus7|p3hh0t>Pu&vI*!eKp^uiswif&pSqBr)P<}o2of`%K;od3u+)s)rbVzx_q z1mn8i&MXDln`Zciqs;Q+hHNo2BY!{`^}NHd`$#75m5CWYm0&DEilD=Eop&_SfP|_x-)yYd`v2xskCS)epi2qOCLMlmyTVr()%C~< z8MhZj=3NOr&V!+TJ@jP%VoU?1^78%vx~S=BK1u>_jY%nf3*a7#x|oROf<5snQ9e6$ z-h`Ws-q(Q$!40vn37HCJepADZ-0PRj%#nOeFsbo6PE(XPs7Ur^T^YrV8v;#|Wpz`| z+70fUx+NL_o}~E;Cto#x|xJ&3SYp`u^VmU6g{*{e3ww9)fyk#WHo1llxopAdrj;)Gi~=1 zWv8I`I+54fzuU%?z)q~fBpA+inM#AWG0dj%pe5w^(Z7`i6V;b@YIiRHP4HqE>xAGU z#|A8fV#~bTT`Cf%E{Saa2`ip|P(#gpc`OT~jawD2VKCDn=E0Qj0bd9~L=xj-sV!u!+tHJ_oEQ`#*zzTX#?<@e}3&3yqV1vv7+B}sgPTo$h|TO`{dfkPjPGQz7fu5yz$-08OLk!mX0>n-8f8$H-NKhVV;Dt?#f zcp=m>D|6mDYHnd%&M(4(A{y)&+Cz^ljwyy$@6a*Oh&Szv8(Zxp(>33Sk!k6-IGaop zq@@w-%7K6>f>4o*p18^GjD4l7LlPk5WBILERQvYupWQg z^BC;Sj&mN>!jxqnncucU1QmxhFvprr_E5;jLlf~J1Q(e0{^ z4a_+Lt*ZCMFa@)=r~e4VxVMQ?9>uo%`eh%JAjM4^cgjIO5%9E+`B3`RRWS|YVG+TO zPRE!S?X5>-PYuL5^$x6*3tfonS*E&gP0Bn&RBG00N3>XOCX(2G*DEa=49Rn=*;zB+ zi@u{#Bp|ocHYcefdSAiA8|)u!Fc>UQj6`SdA-pBVF;@&kOwX=^i+WJX@TXD7a2|!~ zlNlgq@W13`Ox-W6$FJE@+T2L>)H=?GPX$F^orQ||fgHxtqLTNh*D=plN3U z3NnT8iXhij{kWPrg2>DiPJ(9HD=q9C^ac{XtArQ`D0{4d7sD1xfHEJ^Y{NW`wA4zC zaw5TWzA7t_zN`W4g_pG4c7LWY_)7bI8aq`8kJw*&u>vP8LPrpz{z$EWV=SuAlwnL3 z6E#{`=Ea35%H(6_rdhaXuAr_9H(mm}mK%9`f2=Oa=O7a-?NcCh<* z?^Ko0@^D5PaRuxMgkAETggVswn}Q*ADe?>{&6E71SlsBhN9@+2noYi-rTc;7KuajX zEfgV+Tl^nf-3Q?|n&w>P;Owpd;}g4ST2%GajoRz#7|IsS-E#%fNu! ztf}ndHwcG$4;}&wMNkJexzJqJ#Nyo%z`OdMIj7oPbOZuWVP*!ThCD<}FV~()$ridF z)~#efw20SE5JGitf~SP7PlUo2=Sbbcjw&|)2zue7pvNobu@Dx#(qS2=XUYPJ=R2DWvK$`D2=X+zcY5UXh7;-Z!zYlSd#Oj z1Oc^eqO4{q+5@T+cWD7+H&OXxXPDZIhig>m2h{^3HjQdN_nzc(a^3Y~U`OfmmA6V>yLJdxTUQGzGVhzXqlm}bbk|<4zwCYt`_|qqbDW9=U82gkF}`I zLVc6jh?X^QU&RVlVEsq$xrg_|5JO>#(Poc!V~}JoEFf9XttK`Pa&#h8;h3Og#mh0j znd728E~#4*@F8${Dg*U8obZYnOl2dx6o%Ha_|@{f@1SuB!8eNQRH~y&}JG zC2@HbM#pNay){agHN%}dppm_I7Wf{AiRN0z$d9%?4%|!Sv~d`Fdift7CiRVK;kC{j zYrGIeynjnOqwGQ=tY#_N1FQ@qmhcL|7=oKocePJu+z@m>-@*Hqit(hHA4~-#ZSi`F zHFY34A_wea7)b_>?EwN4b1wBdHNU6LM6__|YKlxT<?gXpr%Icfssw4ill{dIib%_ z>7~BraKYsU9mPGjs~<25Mu@cZWY`&4b;I1peea=`oGk!0mP%6x5Y>a!74=w zQ_60y#*&*S+&s1Flf!YN?+TH`j9t%Hd_3Gv%CD-7ry9#?p%`CE@1lgh+)1{LRxdR+ zb@N8bY6Cw9L2bukt%--6BS$S4lI`Z2q&z>m+51=z8sRG5ML%i9=z5K@(V|G7BjvNw z)I=JGA08F^;D1+Xkt)O{{rAZ|^&`YcLoj(6Berh{RWdT^S5G)@3{V*8T4rI36;H^C z0YZI_+cNrhO^3{vqjlgkRrCXYSkQkHl`c&YV~~nrM}xXC{5h=zn7+%kt@a;-&kiRb zY6Q-atPn$lKg0J;-GO{{`);%a3|B4mHO!{b#X=Tz-ZD5)1=of7du`2zIDm~HG*&>l zqO*gDJnpDKnsqc6EI2J*^XwUxs7amR_t(!*bI**8w~_JBd>5{;$hRS^o!Z>#6c{_i zYbekG>)SJ7^FXmsz&l`aMz4D1ndg)w;M*+=a2zVNzCInVG~zbF(`7A_6M{DQSZSWe zSqk>niq=(JcrFbDU+86g770cB;w_XK1iq;2Vglp4DWIB=BcpLuf@F`)@>!lDAR}0w z5I0UlWlre5fd8`;9Wx&ZGrYO(;VZ8ZZo>ibuGuNka#x<2HKVBC+I6*~s6tU+kI(7J zZ|HQ|>Pa3=npMJvhBuDc;$&OrB2-fYRG1=3WHWv3@!ehTR&0+bc*XBeVPv-cu1@4H zpK<87;#x23L*%%^2bMDR#6VyChj^Umn~5{wzB-2XJ(>~ZvSJywP5`{>f!FbB>j*OI!{!lcTZt$J^os7dvPqsQMmt$tL{2CFeqXk|P5IBAvK^88?c;8Gi-)Cldh%L2`2&Z>t3 zQc6vyIaI}{rnO>crw6>1iOdWuv?+d=r-1OFy1uv6OMX9y;yiup=MXoG(;l6AUK4lx z9J#Ot za)QZLO9)1Y$Tb$(V>VE^_a!0k4NVWoC+IkT2H}=~6rM|j`kkBnY(2E71NTc-&gN5` zKA80HqOjTGEMpT-0=+=4)Tp4Gn&i)?2twY+(Tb|(X=LG^J0!N6Gj1UE$n3e7T2wtB zP`)1e#caFk8o;0#7to;1Iskz-7Q;o4!pn+|Xxor1jaAF2ef7V(mm2?5p$(e_uWNQ? z!nznOieTBks{1G9VmEyDQu10QSJoj`P@vEZz221s!FT%T%kWkO^k@^~5#^6hn}177 z6VaJQ_;Qx?09JgoMsyOhcEvwFL~7|5*#00lZwkS#MmXtC6pt#PXzyPB;#G~GMXE-4 zmd#iwf#y~g7BDB369Hrd9f6^|{S!wyZ+cXk?7Ru~wR=>UC6dAQ^cjx*795-*#Zts? z7{#w(GpX-@Wab90w~Ut)Ce{CbP`QQ#t8tFxfKbNwq?kW#w9x+cB5^7t=T+**U#HJS zkJQbWa!TsnT#~ttC!x9SsfKwp6s_LZ4DOB&!cmG;V%~{|w#r)`{@Qr9{o7+gSl8W% zL=>~n9uapH?(nG-@3ve74E7phRD*_J#3xBvk|VJdZjw}6@WMHu>yHFc7NRa@g;&Zk zn@>E~^D(NNY_`>xePj3M()Abkl~iHdlN4b10?LiSGP-(q6x1O0%=8;et6-1~$whSu zv72~~WZ#F(o;V|*=G=|q-Lg@8k^n*YHah=ltcAg7!hW4lV~%u!j*oM_z6bG$FMZ%C z7hEOTxKQ8Cw>YA$D)26Azge3WA~RpSg6-RW+zfcDTZp|>hFwK^+Ylpu3OzBh2NP;R zS^S~rQ&0Aq2z^{-BuGZ|3o5{~P9Ucx|2Zb6cOOX%KueTd3{9W%R!hCA_#Gb=8VDky z(`e<7OOLrmKMWVM=~-Ss>sxU_tcaUu;_kMvILv>HmL|(!($-$4{&&T()Tk=z^$@z! zDyeJL_SqI$#4e6=@Fos4cF04lCs%HM%@DSK|#GF_=8D_F2Q%2K{jj)>qy zB2=-qGTgC#))&Uiqxhm+Ksd)ViOxq`UedF*p0;HGCzrFETT>8wbM9c+sM)AUB&GxK zmerigVsC%=R5tmG7j>Y(qDF|oZQDN_*-bmh60K-Je>hh!#79%Uj zkW(9z4%5B&U_|5_lk8<&n)TAVgmhYZq3sd>lhKralzm^w8`Da#{6OtjW_ezSF8*N; zXp%wK>^tzHA{#@Zw%Gx0q&y1Hw`4vtv|sCF;(fwYwo1h`m`;2#8h_gnsk`NVH*8t3 zd8U5?vGiCEK86unWwMi~OC?_UG-=z@{L0{iHhs$XHuZU4A~69&k`fq-9&n{qxAN2W z$56_K%0au@S39ncvscD+nKHpp$A(0fPa0a%`l>f7T>Ii3aQ5_WOF*(T!dSQ8RnBv% z9a&?CiBu*Y!r^XySr<|6BeH4`ds%Jrjy|Vn;iv%v4}rWt){Veth2pF83;}j)HQ=Un z1W2m_rU)TgO+(PVH5B8-5rg<<#JlOdy910rmk}Z%IwG=Mx~#6_hk$8Ty6{^>Km1}b z26<0RCW=jPE42i!)8d7G|4aXC9)AWnv0_19yC{9Tw4d%<>vD-djRA>SUUukBGd?KE zKVg2wg(m5;XzE~q@pt70upJ3Im&XTncTEciF}C3aO0%0DrA=zuG~$o2!wnD+daY57 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 PXB?q@|23uk|Hl6UNAjjR literal 0 HcmV?d00001 diff --git a/img/diff.png b/img/diff.png new file mode 100644 index 0000000000000000000000000000000000000000..faf74595513c9a8e7da58eaf32c3ae6cc7a1595d GIT binary patch literal 28913 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 literal 0 HcmV?d00001 diff --git a/img/favicon-16x16.png b/img/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..fa78ec3413d236f94e0f124b2c0a6d4358da915a GIT binary patch literal 1738 zcmbV~c~DbV6o(Juf`Wq91-FWWbzDmF5|%*hXhl$nf{GCpr#1nS5Ro-O2Buc3Vzr7o zv|7huu%gJKVU;&i6gnf}u^bKZI9-S7O)z2~0O zJA${&oUv#I0L%;w@C!lSX~OJm(R-Df<1XYT3pNIA1Smak|A9LN#WtdlExu4BU7|&S zOGH3O5J2imfV2|;W9V0!1|SIo&~X5mmjM>UXWiZT4ZtMsj%{pz1VCsO0Co5N1DwPZ zu$^YLS~D(W<`$K$yHxXa^6zbJ?Xu3U{SE!wDtonBok2gueWYSH3pt#Ltpv{i zw|d>|GBw<>iZU+4EpoDiaBQ`L)w--mPODHrMh^^Hes00fwQ0chD&!4z8%DZ`5$k)4 zb<9GJjqAq7l}1vb)pX%_X8X`NnXan6f7a}|VGq9(Oq4%c_o>PDnG zBEJVum+DWo7$m*AKBMW)phDW*vc9DIY#aWPwB+O7JzelnHgO2(#hch)J#1 zvhK=Hw+}TFqeq@==3MTDi!b5A6NtY7PAu0lMT(4Q&|1pg5WmWF35}Ws1+O4m3P0w; ztuaxZEVs4qkbM$^kmSUt@MLxyJ2RND2XAnHs zFS=ub!r{#i^#>l~nH@vL{luj?nxlGpmQ zCN*4o4LJjluY{W_$m}ca)$|Z#4`D&AwvJm+tMgtCc@+=3mZ)8eRg7}gahX9PH+7Pu zZ$ErM%^x(9ts2wso%*BFq0}bbPi^{q`EbE2U0K(_7@<7Vrn}ywZ^lhhjp^Q?v1WiM z9WZqo-!?0>7fb3{wW`!6Z6j`y6T=-^Qi_|NsfUg4#;w*-G)v#J#=FprJr{=rPfYLs zdF;QUU^HyC)1(=!!pDtGt(C#kr>rZK*4@4LtRigYypx^jA)#SDE55K@{DAJ;F&_znB+BmKKqA5Mb@0uIM% zE-PRgD>yJ{Yl{;fY-YDL-PULI)qObTJC$}Jt=eyALZEP8ia&36QpSxH0Re@TMGe3JgI@n)Ft@ujpzgHZ|74w)8i9FUM(6h9p03~dms33~ti<7yDJP3^8 z3V1+dAUT1#qmrkH90w%BAlR+A(|4GDCj$B zK!V^rp~#L(iV0^j{o*2$VtBD)CUXZuML^55)>1!XKGtM1qj*9=lo)6}bVo=`N6dmx zbpB@c2qVQ&6G;2*<#q^J_z4mujNyq>;(73KSJe1e!G^NX;Lmh|*oXp}rw_y3-J9m+ zwSP8cK0+Kn(b*+TJz5I=WNCLuAn=8Uc#8SWnL&G5l^d~Sp{#_;rDP*4U1?a#O0^E*@l0{w&iihMc8 F{sR3wA+-Pi literal 0 HcmV?d00001 diff --git a/img/favicon-32x32.png b/img/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..074b012cfe6b206610734a6d33e0dd7f25ff7b1e GIT binary patch literal 2815 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 literal 0 HcmV?d00001 diff --git a/img/favicon-96x96.png b/img/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..2979534978339f59aa3cf56fc1c6d4093daff1ab GIT binary patch literal 11652 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 K2%-ZD0sq;Nd`!Op literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img1.png b/img/git-beautiful-history/img1.png new file mode 100644 index 0000000000000000000000000000000000000000..0c76d8e231047bc12c5ed56673abe9073c01b420 GIT binary patch literal 18781 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 literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img2.png b/img/git-beautiful-history/img2.png new file mode 100644 index 0000000000000000000000000000000000000000..721e26435e24a81bf2dba16d8ef11a02f3213387 GIT binary patch literal 22105 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 Eg7(1UGXMYp literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img3.png b/img/git-beautiful-history/img3.png new file mode 100644 index 0000000000000000000000000000000000000000..0774e7adba946e523db4a998c1cd25c567ea1718 GIT binary patch literal 35920 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 literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img5.png b/img/git-beautiful-history/img5.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2ef06f0a440c344bd247c04ea56fa96614d8f2 GIT binary patch literal 82913 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 literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img6.png b/img/git-beautiful-history/img6.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ee3941d26a8691a088f25043cadc84a07cca40 GIT binary patch literal 30654 zcmce-g;yNG(msqYwu`$r9;Qc|y_RFO1io~Qu`6IIO^x8)9qhm!APNMVt zdYyhn=yq~)Qp9~Sn+OFW^XdPvM<$^^jfaW#e;8Hyv?Kk$3we^bPXD`UlkxwrX5-`t z1!l<9Yn$`~8tLLXf{VrD`XnFxMWr=~nQTEHX_ z?MIL4Rrky2dAXL08_kOkmGhstMKH*6XYm8SAA9g|TBHe$?mUs7N?0^)7C(u;e;*`i zThHy_&yaFh9bUXsNnaM03s-P;ro|9Th+pXR^YF`5$2y?F3*qHEat7`^{6R*GQDGf> zT5L%E7M_RWrtsie|EZtL4mGJL0>-WhV+S0blSk{0?bOXwgm&mewG|WKq-uK_ttK{9 z6MnTE^YKH4xiQbR_qPj_Kkq_{u;p&PQwkJFQ_rQrUT>gNOW!G#J=RZW%0@|(H|%q0 z>?DXxj>1X(_m>kB>ETtZF%8B6Yc@FfRa`fsTwGgKYF(@ke@s73az^ex@HeOK|)zuyul~wB%REX)_hsto3@WH79lPX zhy`JRq%WSxq9R7qJWPb(yM7(B>GlufRY0_!2m>nL$+J8z1wC)1)=J8D1T&GH6%JK7 z=&J(eR_!}kO;pH~SA#3_QBH}*dY4delW;!;(0a!lTRnc|&HABu1y+8QAC{wHl8CA< z!ak_|Dbk}^Z}AFUC}(^aT2lkd({iD;ke{Wo=udl1LWX~3=Ne04A1LEKjLN^9W+`*c z#m%P4GWV2J-xc?#)V}9sebHM$gV}rMAhptiUpG^t9RI70364y}toai@Pf%&oEbnvV z*avu$-t6DW_huYq2Hshk@GYky6*?n_vs2SHlq`a|zPXGA{dMe6CW2y@7&_H0tPF=I zZ+mfrrqC=I7oJXt{S`jPs{(@+0L>a&@0?=#TMe7HHu7v?OEr|Z&7HhE3x3$#bO@c{ zAnkA+Rnt9nYotn|@D5W5Z#PU_pV;szgd5f)AHsqbbC32jgZkaq;idAlEnLIZ6$bat zMnTJ7aZ?-Ml(17o+8Y+SV7;5&ndy8+Dh{Nj6XP76l-~>iIT<^Ergm?g3{r{CC(1JN zn4`$2Ed6~5)%UoWW|J~3k6j<0B)I*6`?YB9Y4rGw7n=CHR_j_Y>l?#!TN~+OZ1-mU zaRe~5v=kP1l@|DO_^jMnGftQlu|pyNr8EtB?ojy_jwji-J)Ks@W!k=-fW?+QfVx1u zJ<{-dxXg-7u)XVjgp;M&Cax^w(HJgw^P1$NW)=?sjP{e$8S7h5RE|mCQ3l7~Okqni z>h+N^u!XhiQ>Y?pg~T&l5x!KF*?O7|;xHS81*9GZl=H+h*A8Wx^=ilp$#s^qgC3Ejv~+G)cuf?x6E+ORE3&_W;sYM3!vP84Pj z@T*g~jC&4>m+^%;)$%>knjM%)*%PNIBW%btG8G@Od=tU~&)JV_g2T|H(q_b z=HtfUt(76~Y5pnwkEYJ?!=0v-GHsPfRi`y+Vid#SI0&#g4**8BvLGl-7H1+ob9Y4mUA>3;qGgcsMpnz%s~>CoDGd z@^lqZ_dD=R#(KQbg70Vz0o6e2NGYp>$SI;MYRML^>znuo@8n++)sgPyrkC2$+F|R& zyaDh_Z*ZS&ZL~jE910Mz5TRWm6Y^oeS-5Y^PS;=!h=fLA5%t^ghF&_Ft|%X^0Ue4> zkA-bS;RKgL)?{|#{z8yQbImSP8O{;wKp`Mw1n5wL%Zkse1=@t5M2FqB({$_reeY=C z#kEP_q4~tlN!=eg!6fjcw4Q?@5+I>_{hma8Dp7TSTs8vGYPzA1%st1-W`xEFd+|%^ zXcl|yA;cKNpeIrUL+N*!H1wW+dyY=^H|0y-^H5+VW_lWYlCP--?(P9vH^-E;_&8Cr z{4CB$V5kr#uU0fpHy-XnZ*xJ!I&3z38!%#kNAhK$oYMU}DW66s^tXMX(@X*K<3JwL z+NA18g<*A3vKuHlWR5|V0_13>Cg9))^$Mf%*60 zhs6@-=>OECyF@RPcUu&##7uI%VZTpd?Yo{IuHMIFdZ_^d$?QTjacyi=;6(SIEri(n z@N*^)uxihU7_;nS~$%h!H*dIIyTJ?JO~+a?K>MI<^}E`TM{ z>1K;{MX1)>ktUBR$t%Q}(lz>4vwN4<9{9bsJIY{RX0FiVwh9vCsEd~j?@{M2XAHNC z*XTz|ZiLmEa5Wnv$PT$87aS1LBEc54@$a%6ShocjI{m#LQ(uVrLM1<5T$44zFlUJY z?fm=Nu%>P3K0S+9tC!7yYO%*`xiR(G;o{t^gl~8UR_-y)B?})-i#@WDd1ZHg&$!$p z8#bD01bUz*u)VMYd_u$Atd)E7q1v@O{p zD>?#}l*Qvh8!m*o?NgNw7N^siMgkTh$B{(O0E@&8?5H9D@oH4eO!U$%0D%xy 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 Kv_{w<@P7b+iz{gW literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img7.png b/img/git-beautiful-history/img7.png new file mode 100644 index 0000000000000000000000000000000000000000..d8d08380be93eaede2cec4b8ee9366c8adcfcecb GIT binary patch literal 27513 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

VUAmEmMD1RFbQ1gB8a&ExK7EIW??h+qb- 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 bk5321gg39c3*)=9=+2)}JDsLv^5DM!TyLQ$ literal 0 HcmV?d00001 diff --git a/img/git-beautiful-history/img8.png b/img/git-beautiful-history/img8.png new file mode 100644 index 0000000000000000000000000000000000000000..110e86464b9a32079631cbc621f66df49f15e6eb GIT binary patch literal 30240 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%0AWLqor+a=_dKFgFcz88cx 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 literal 0 HcmV?d00001 diff --git a/img/ms-icon-150x150.png b/img/ms-icon-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..a977d225e13291234e311e2a0cac3992c2eb154a GIT binary patch literal 21929 zcmV)aK&roqP)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy24YJ`L;(K){{a7>y{D4^000SaNLh0L002k;002k;M#*bF002`Q zNklc1xBl$)OLhFb0_*B!rBS48{hd zUl5o85g;64Y#C5v_oV@a*1yQ`}! ztFp5)^SyWPJ$vu9=HSO%`<(N#s=BLCy}DVcTrYR-bI-Z=e2z2cTyu^&Ch*DnWPP$e zSwAR?kNpH*S^wmpJU^>i9JjUNjl+y5bH%g6grgTcJ50EpD~_eYji_cQMz|3LKrx^a zC;%#j%5erzC=?0~z#$j`LNEZvJoDX$ z#Xs>s`=31arw9PB$9@9mC-P7IX;>-w0|^_4k7sBE4#jCkN?=H2;(+63W4@m6>KK3H zzv3~ls9){(zQfGs&o7sWc9d1ZV(*Vt@z;5+RO{4g?^kAJh2e z>wHs!gTuk)&AZ#XJ{$LYN?Zm2lFHvnYeGQW?^pvJ;29|aA|wRz<^U8x1QcD05PC?_ zL+TOHdqj`W)_Szo)LK)tCP-j}iWgxr8lXS;Km14VNB_tF$fJFp9}QsH0qP6z-U(Pv z`AJR1+HvN~4uWRxZnYLKUff;9I|>OWQDE>yW&+Is8c0hY#vrb~{^zxOm2oBrU3(h5 z;%fn(eHI}D&Op>~+rkd2VYzsQ*4c<^Ks*FVKmZCsT~J8Th2DkM1HFe@3-uP!T94j( z?^|opT8nLK(bhF$+XO|>9pMFaYH}|$H+={1{A*hu4Pg0GV7mjJuf)RxU?2{a0I6E+ zG)?|6g)d!YmFgUrnowPsx-c0ynNT`W46pz^cK3L;5FB1=_g&h()^23Z9`71Z=Wqt! zbY0%rhwk<2HW1Wq7_pzP{z#Cd1eSmp-oHuMBy1tAA#EXT5!!l0>s_t&-h1@kdqnTO zLjejxi?H6o2yuTBkF*{iSQ7BhJqI=cEr6{PCZZV8!qDXr@-EeoCJ9qOhX4)&jsoWW zfKZj2!#xnb#=cp1L^D41#yI5-({HjyZ#3L)X3fiJUJ>uio-)kn`;T^=*MgoU;)P z#0p{|@c{6Fz&(fu0`~+8m>CZeD?tu-O@J-qJAz~rsLAW4|E$>^(BJnnm1H z!VU!Gn5*MZ9g~--c%7Y7bsh?N>%^@QPn~#T#8U%qjkq!5Kwu(Jm}w{54~H96*x*@oatad+E_FX6$=^IT;EuCoF=m`ngA zksNWEKqY7>f}z|M3=o~qzXT;$UQT zqX*53lYM|G+$Arf7nwqe2)dh>62+bFehKs*X*~k4X5h`=4t(x&@IUhvJbQ66TkiR? zh})Cu>h3VQyVq%|_32@n-k9tBZ1Ur6@tdRb_F#BA8Qz!-Z&t&bg?OVFo)+q+0EYq; zBZ@(0BMWfxal5sWrR5R91Xl=jf*Gr1Qep>L40Fb-K>Qqn=e;JFn34Ey-EidwuXmxA ze;FdW$PMH|@&Uw4k~7G%XFp|(Fz?kpR6I~iu$Hi>5mZ2Ox`$7drB-?=ARjmP{RqIa zk!d2|`KSMP_}t(4JNW6_Te~Udt5*kD;8u$JbS!1Mnd*Ey)#L3{Zf+*Ky(xS$JD<$P zXVvg#$>R;Do)z-efkQD&1#&0MAv#6^5xd3Gh_5uP)riN^I?-^kR0B->FsSsQpGO3) z%unG0Ht3A70Y=*HF|*neB-S97Anr(%Fpx&j*x}YtY(w$JQW|S*Hcj1o>mBOh))3)z z?>@~|rrK?)nRNO10_zI^?g2dCuOQHX=U)Ndc*f=3cft4HwcBd`mBR3Uy<^!HHUc;*=Hab-}$BC}cWH z)F>B2m^W$n}~-nm^%@{ z-kn=_J9)8_7e9IRlTCHjV%4 z(+mlrOI-#d*0W5g(ICkX5V`~xfgmHmO<{)~c8FqguVrqvPJN!H)~0ETW9>i*x6-HT z>MdWI8Ld|Oe1z5MW4j?QVWWv+8QmZ=_V zDL2*qc5=I&+@4IvXVv(0GCnQjlS1AW;?}97Q3nFEop*)u1j$}t%w!J-xNuIO4sSOM zT8!j5(r`vLZx=qscEjAQM#c-Ej6}U)LKzQS}fA66tYgF7Zmr8DX@Oy z?+3p86@up%_@P833BlD`G4)cRdT=`&-41j0+o}4Kx%$&u{Ao3NQVmaM!_$f9<4L8C zg*Z4g*|1VcIZ05B>VJf?ushC*1QkLFsz^6x0Z9MaR2;_}nl!b|A0r!sLfyon8s@<)|R!g+W)w?6Y1UN~fJFQgE{oOi(d~9B{&cSXthzs&+@4nA$!vH!Q%`2< z=|tR2#GxRjf=n%NWSJyHD5(KW=q(go>WzpN2ngs|1ZL!pj$Pc-4AjVf?&JsJDx*4p zHVhC5*sxlALe@yR4L+a|MuD(QTNaUpL?KZPa$`6VmbLO2nJomJVlY^&L)J{*jUL54 zTJ=b4Wl&^{NRZ|YpcIDCu$K8ibO#?f)$m$@#ZP}4T2|n# z9|6AhKB4CXB0UyAK&?TIK!?;Ngo20=x`;M_)dX~rU4ta3Z{lzP7hu5vGl&kEL+%W7$i+M` zESUh4(U>;e3Jlf6$)wrXtDzO+=D>--31&+K)}Xe|vNfVNAPT84M?@$hq@C1-oj*3L z*2fuG&p!QW^xhF7c`OF|yphcnM+e_5_{?YP;jK?k$0xV*G|zJ_^-$ezCg*W7+|I=9 zWPCCkpH#!`WVo%wVIt;AluDEWSOrv}a4INCQWzry^$sWR6IBf{8G1FWPAmi; zAUp(l>aryqtI3-Qt&uG(dh`LSog<@BcO+r97mYrqzUONgn~bw~I~#6h)6HbOsfI&M`d=-8l`Pl5q~OR$ z^33c_?*VBWoTV*k^lClOTOe9MJ%DW-tH>5$1DIVjxof;+(Fde(N%>kn4`v+-Cdx94 zFEf*OicX}v-7T1GO| z5>yAn&1^VcgQ^l%*6?`3u;!vla5pfy69q!mDu&`ETXVa7qn`Iu(jZ{K_ay$AbrV7tAs zU@xF1$|h5peV&f<&3rT69B%47-#HWjbo>(kfx? zp$*cSJaKGmS6jNaQ`ffS(Uw48I{MO~Qy`WOtRmI`SAkoIO|XVN)*AIco%vY+E&;q{ zCYFW3ge>P^lzZHgZ(p*sqmZakmfj;bLTP1~)ENRBfEDD4)XB*Qkq@>X#s|SpfF1yy zB(0J*5{+aGcbLZUk-gz-0oH%+U;6X7fBqaHa4R#d9lRqPP$f7!{8(zaIUMTkbeL|- zG~Je3o|IxwY6k8*xDK=FFp;yHsza8Eo3o`_LO3C`sN)o&wT0Fev8_F}Q`dIt*dBUp z_Z{t_t3PzasWVPNEnQe8t^(E&n`qmxSZyRu`^d`g1i$??jzp;nfl8uN+MCyCS(kK3 zW#6hIa~#+4+Stx%REj!?4ZsGSnWT%6Cj%FfCz1=#*W(nxN^nE6Pt#%za6NXE^;&=> z3G?v=p#Z%b+T=u35tE4rhaGD5n>zVTo$HfQ>yzSsTikD}^L8@aOoroZI2;UfHBBXR zil7k4&uWXbR1dA|zIQ!rU8gN#-CC?mXx%N=LsvUBw1?P%rC7qW1hIvA)DQO^;?5R4cexU(L~KMfBErt~>Tn=RNFy<;zQ@|bzg>7-1o<_ZlBJV3k^d1OUT=&D>ln0wx1y zH#@lV#*5vQ;uxt@ym8`Kh+`!VlVP5yIvJ}mJ5eIv?U2-3U|B*BFB|S&u6lX5 z>HfaO!$XVZ)M7ogJ+@L?JK7S6B@jzztO0BaG&whc9kK>khpdAfJHi1fS?tswom&ZE zkP6WY&?iGX5$#}Tt6^(_7OqW*PN2InY7b4FI&^9a%LH5Ou2SI%js)4*@d@aoEi8YQ zy0W9EOWMJ-?+ioA4v|OR6uur{dC9^v1=^l8OkhPLj zMjYHQ7huYrpo(QdC|XE8bC+9_)`za;Wz)lZo9^CU;_k(!hnH(C_brwkSZh}syTQH& zv~|lb4vJP56CS(>~8pUbs?3+tdqCvT%L-a~*6Sd8z^~SV4xYm=$w)ALQ zR}Y~B7EC^m%ouKzJK@3bkc^|Z_7alykp_)n;d)4lQ2rAl8>j~rECYANCMsybO6a35dEL0t$5y#?CRvA*nD z-rsb3XVJrZOFVqA#_8o6>wUVzwso|TyXq~dH58iw!4Ock<5MPrqCB_*i3Z8WW$w(0 zVGKkl4C)3or?!GvC-!A#tVe6>t@ZVZ_w9|++Xof>`OJ7ZTRa>~oLbcyp{7I*KshDf zOO+vXWrDqDzeJ)bFC&H@9RM5&QUGT8Vm^-P2D79D#Lku!%t06A239jxGt5Rim~kdC zgFJwk0nWL5*JNPLf^K%O@9axpZ%0>OL+zoVJ>Rgsx5fI-66-gXSf4Mk+-0zVP&@A9{AHFFiZxOHXIrmi$sCeQX3wX9VFK{GU6` zM({Vdi-?fE^rauh*WP~nV+btTdH3WLoidqBU@@SYu{tpsF^!It1ArO81aJaaGnvhT zGaV%xW%f5X1T`VnK!51!FPqv2E7~_!ZSS14y}v|zxvHI-TI=c(d%6!s#Q1!2o0&Wq zm%&6Bj5ZhpDgR)A9MFE*#wR>JdL_k65s2Oqt)sVwwl=n9<8t4y+->%7*LeT3`-|tj zym&7T$5o&H&3}Eo@tM!*&D$sV?LYh${?kA9mVVcdym_wwVTah&`8zR0kDVL^URR8@ zS3X8Nl@q39{5gT*L^ZM+IT4(hV446<=ghxo+xqYu>1O~fVd;bjvt`Pgtf!>5| z6PAFA`Is~$kvb%;Z zpyi>hLu&_49lCG8T?1Zh()|YXO;;J7ovsIrETztU(2l)}kY~{BVLD>CzSyl4&(|r0 zkf1R1o=4jZ>uOj|#KS#tcSpSc9QgWsz}LP?oc=O^7XY9?_7SiwuWP*?V2yJm+j3O% zF@VJZuA$-xR9w^@&sHi@HO4|apqTQC+2J{k!A!_{AJ+iZ0Jk7}WG*^?@ho>`Sz*kc ziOU{ubee`T!5{`G8`f#Jk-(^TL*Zv&NkDX^D{Kw16~tN)t0Oi?GzY^mnQ-$&c=%z1 zUR?G3^vA})Ygw-aSXVq`4o-J6Mv@2amf{x0lKNc;6bU8r@JLH#JG-EdjaY(8=sR~R zvS{1_>;a4X8{bsW6l&7<(cpAq6W3GX`)KMUY~qzWoB&-w9LuLoEIS$6LH-DMm}X7Aph z^6mxx5k8NICkC4{=_@>cr~4J9r3=*r0mhQ=Bhd0;ev zaaV4*a=fDqt=*rV4qq5^zgnkt4Qz-!O&QsvsF9P>JOSErv z;9UWKCxAcx*m(G!t=HawcCEmHo#=Qu&do1ZJH9>RJ=`A#lQZM%1RQs3=1Sq&Vn8Wm znTUEY_SG1RXRR+?VdfP^gD3}^_ex3@Bbditc8;?(+AAgOy0TK4iDzUwi`{^3K=+;K z2Zy6t!CV5G0}kO(gg0-5FMbC2;KzU$9{|gH9bf%G_`Civ@X!DE9~%?jll6V;Z2We; zNFVY=2v7m;@`>18p^bAud=*qIMwUX>*;tRpc3aq^n~KDi9mctj5WCV6_PFT32*!SC zvd?_ufc7p4n$A`+V17Q3F7p*vIr<5eIWVW8xM3;|N~jh%OolgZh0nh!#20~0g7}fB z@qMq>>tQ#1=sYf8W9TX>K2x3|hN(z%!6Ej_Yq1S>r4*z@S5l!$0qSI^2g7t*thbI} z1SSw$5`~+B24xR>51@_5-@BFv926O;?;0|G6|j#)d+_{}u?O%2e4_#ATn9d@Y#|#6 zeW=G9&rR8I2fQSwIKG2i!w<-M-N4$xp%~cMxkqu1xswq*G6+2efpdK5<8QOuDtC(7 zb7IwiTFAK?4@cwr#MxU(l5&ypL~-q~-eD2kVsD(t@{SFLsDe-@qC*|2GrMaT_hGSg zwpKfca%VU)YU)t5%b^abBVyMG`4$<^OZPnhfu=nH_;FaT1z3ILi-at@x6zF(43ROg z5ojG)FSK)Rfn*0qZulZV^}!|CMQa5XK$V%fp9^s~7?vC7_Ovk62^Tp7b~5nMQb8Wry`iKU_2E~?_)iW!vD-oJ~H+q(- z*|oWWj{=eEd$e8;u*Nw?60-s7W7>y-&4HD|;=lLk1gCQz)%YgvO4q zfxQ6HfZiZ&P>d2!*a*V{aRsh3z;v-*393w#kyn0l)VKp5p*bOc{8$yA;bu|bpx;k3#hz773EHXz$tw59uutrq2 zyUGOCIL?6Tm$ZfjY)HN59wE!>av&z*kNwvl8xP;J^?HDnCrQ+r!0Ij3kpix32NwV* z10E_kb)a_GBytXLjqGojM*=;11|t;Y+UGBUvlFcv`fQ9Fr%-4PS|!U&_-wG*VW*xC zatf#hqBQmz@TJ2_fZhdmMv%R2=pk)r(Xckby1{#cjT8b0s4!fil%1~`f(^|P?QSmt zW!~WoFw5T~NFVW)DeLb~9vcha)Ad?_weA*6zzW5Z@l2D@j9j~6fp{|Up^CMEwF6TJ zrXc5l%|WgK%p>!7*60Y)0anYFsb0yLEo}%jfCckP*<`dSz{#PhLp6cbtD{Y!x&*hS z!wwV-vs~B|1jQ-D(d zhae6KDy}^_Sw+fJrt(8|=B_Y`A*vB!B%NlW6~cT?T9JRr$AeSZ4H!7 z@-1j<$d*pN(TMjZ=$9?x6s;pbcn=r@wpX&nv&F*DmAMQ`Nnm+NQt?i&(O^{UoZ($_ zgbsKGDxe?#JAnV@Kc4f1T1&PB1pG7q=wsvLyI!v~#tI3G5T`*47O)wID>R%6SU0dV zutZv`N#G%bIfS`Oa|lz2W#>VSM3(_7Muh`W2h=Fi%1|w%GIJ`S1XKd5&X|Nag!(4* zEr*LuU06dX9q=CVr5F3)S>ZdMns~QuTBD;yj~*Q@f{{m$h|J_Fki2zKtu%4UmE_we>(K;+gHU_0_zI=fgjJy|A(J^Y`lEO>$SN;QV3*>wMen) zVzD4B9;};K8jzZr;1pNmOaeNkhtgz$BFLC+Q;Y-{ne5WyWK?6&38RfsV9eBfFiMiV zGzoDKVhct?4nqoM`U6BWjE-V30?-l%-Z$y43->K>*8&eM@X!ON9y+za5`nGvoT`)q zEtwgH^Y{@Yh*DQ##AHN-sW+f)(6WWL2k7C2jTr2lzJ>c)we$yRy%u0)p(DS{8>CH) zHM>fhlN-sU0Hq1u#S%aXVUje3aEOSx2d7R<4JahtnbR*Nxi0R7B-{;kv^UTwn29c+ zgj57g09HW^)5`j%1~QFp@@?NN?iy(4o5q-F4`$OLrZ5+4JX@O}Os~v?V%Q z1iLyz!N|aV#PcJO8lC8!Nr2dZb#K#Iq4hypPr|kc>jJEcu&oKMz5>yHptAC>tyXw$ zkQ1T-u?@CM0ILb!MDK&6m4rT(kgB3jJvjAdwJWA(EHv1ewizf=n3Mr@S}hJWG_V`Z zB=bQ*t=VvQZba?6;(85cg#gFM<^z~QoB~`Hacx3WM^qq6R+m$Kk4z_MKzE@l&=Bkp zBlDrmF0MfK*L113P}``Lgn9==^+v2Kv77?SNjNLU~g^-Q?5ElZ!#iH(HR(VL;I9c?qTEzq_|tMwo}ybQef z2J!A!gl~NHv9a=9t=DF;lr(ZF>x2=xN7_i(&J7sFvdpgs9GxCS=|X9NvUNBu^`%O> zs>q>6oKiA@1*BP)5(^Tv4koy;TSUmkG+;TF4pqS1$0ngkhb|nqz}*Vm^uPm%MY+M< zVkp{39P^4SZNjM_6?uSo2w3*B~51vVQKzfvm>sR9>g#qgXyp3b_hf!_F` z4vUZcdVRpcxdkBxGdz@KomH3pQZS=ju&1GP+5@rnNm~u7jlcl7m zai4j`b63xqQvj%d>Esusg^5WMcP5kD~CdYyc% zYnn_SeR>~md+DZ-N5FbFC@gw-qkJ_v2$zwaL^p=JM{$>%g*)UVQ?}oX`^+_tJyZ(y z53)*%!T_3;h3`WMhZZ_+!6Shi0S{ezFych=fzSeA0k9HU4P3@~^;EB43$<0Ecd)?_ zmhBV~M!^{}h7diJtm$y;DO}4QMgz@68q5+uuL{-JV6hq5EzrwGIVl%uVPr9)yQ>tJygNIl_0zut-D!wN7M>P%ITs`i!e_{SW)9Q?aJcDu@&@?yE$H@BIQO1pIDgFqA2rLz5At8D z#k!^_>s$Q%TkpSu&#mus?XtD?tw$_fsvRt5R@~iCOMWkna4+gLc9AG0r8DEUt_$Uv zKncK2%BJ~zP`3mZQkn=p#EbX&(ZxrnPc_w%l9&clbt;Cb1W%JN9fI>BEStElz}ld# z0j*Ol$kvGj7}2`a8niaXwo&V1SQfYSp}4bFMxD4#L3LxGK;E-70L$X^bOa7J#O*Wc z@QkR3Na@@`6ui)z$B4x7Ln*n^e*(CiPuh{A+VvLLnwwLZYr!PcSH6L8z6*fzwn zQp<^`#kkPjqf{<6$O(ur1!{Il1^~L?6EPhUScfOXbTn8^;^28_eLfp@smPB&YU0tO zyuapyujm)2FZAd2)9u8%1#OWPV}wac=@*aQBU%sjCN&3|2^%$XOyVkGQE-vrCIWL1 zb4fne8~_|cpm#Ta#Lo){RxbX@i+XzeQTgpLVCu56g^xy7Gez_siWWjz1aWJ!MsNkVNnAr% zdf?Q6Q-PL396EFi>c+F32A+d0olus1r1J!OWH@X-#=;q3Ztx0t(rH*isH5p)?ZVa* zP+JFDmaNp8)V9Hv-K1?pRt8t;v{I)+J(!`u=-r)b0cxeZdr&=9DjG&qS_rR(I(5{! zqfC7a%Gs50c5r=oeI&#n9u-&wpfCS z(7Ljdte-)(4<}Gx5q%4_RoFIYsffja2NG3;hmo6`P6e8)#S{@0(nd*TD8Do5itys7 zwWE{{vn$Qfv$*Z``bfAz;3HtM+F$eA(drR$51IvOEr;(>Bs<9l+9va@n{QxQJAG~N z#bt|yttEJJa4FKM5^E)vnjFktDV570rJ);f-l?B25=n7TW|79UobwFKY~o0OrQmGV zKKD2;TBxttn$s)LSD_VZTNrC*^EF+PzR>2TrC2kq~a?viE))(=I#z9 zEvCFgNGY|JTBvG6*WGh6Wj9k}PK{U%nn@H876x`_w82qZz`hW%8r2(l*J)dr=YR}r z+1X>A#ty=>n=bY=3UKKr&*1$$nB}kX;Qi12&~L*jfYu<2-7*OpGz<6AOReNIZ+$v! zy&hWgL+_k7p*BQm4r?xKRoE)gW~$9pGzL1vPFYaip)%$O(i1@8$#^g)Oyc!eUhM!I zfJ;r%^p?Wto*t77Vw9>dwA%Nhi`YOdNEc`#Fh-O0?(7@b8`(PTS0?Egj1C+AQGDDe{?UPD2yDtCKPZhk%m8+&Wasl|pXKx0 zPw9ab3tVkz`g@0pDP};qI0m8{VmajyVcA?7fpf?zO*>kiSZl)ROt z9QQC_m)+RKlV0L8UJY)_dZ@vRP=;LYKB+ZGHWH1-Zf4zsnw*@w*-fC_cdqvx>nX4< zUG0>T0XxsJPAXD|(2QVt3p9HH@B~@Uty&c@D{y3>4gD5V>J=Ho$m|0YW#BUQG*Y%VWgA*H;t1&l*@MbTp`abba??>C zf~UKV(_P1M-?iQo+kMx1rz~~{#0C&aqwk2ZI~=m%;+awV=<24A4lDrpiU0C{_S@d} z4+Frb001#p^xIzsZXUoJ0mlGtNdzdG8u2OQ$>p z3o<3cNs9!cCu2vIL@{9+WWhjUdhhV^U6cVsM9ye3if$Q0Gvl`~p%<_hQImj!Xh+eP zU|k&3L+EtVak^T6r)xPv z%Zzw=LVqUk*-++l5;cH{!b+e@bf$`XgwQD!A~pEOp=|)mk-Y(gIG)JIa5BaBd@?LULHf z_$xI5je(V-K_&!S)_o#}DQR`$p%8~k)k>CX@X25sVUy9SWQ8b&*oPd3}Edmhg#*XJsa73UcFBU$-&QS>H=|-P!P)Txatn9 zg*c_fLM;ZLn82D0oJ=+uy=F0ba${o6Aogc5mX$KxIUMx;El0G?nB5ZbYHrQnaS?7!;oq2bg)RF*>(oQkD5DsH)kqcw>SIUl_yGdeU;8fL8&H>|e-?vg zp&uaKP@1Jc4{a@Q>H$SI03l)*Oz2KD2j)W5YAn^1Qb!3W9*lNy`D`qcaUMg?w_@l! zy?SuzvzZY&3eF5+LN%hBu^8aj;3CgW^0tF-3}OzXs`ji{0NIp24Mm9&ZE^w}WTizY|#3{BQ5GoWa)elr?3%lEz9@d7n zb+!l#i5h8YUikK{4q#187kF^;V6vl=N2ebhbv7-tahn{ihN3WsCg#wo^W>;-A{-2- z!pV-DC|@)JY7Vx=fFr~-rQlAZNGHkPPoek5$Fdq!l(J?I@wHqodwe7p$NDUO540ap@ z{>L_1KQO@h7k(r0cm2O#%_Z+`iqE_7vp@Zd`UM!xflBZufybs+l60DYAj`^{t zVB!Y|SOD8DQ%{wyqW_MGssoLg~ zA!Z|%(2#E?dJ((SyV$!F&BnAbqb8H8K~D54wi4Q^VeP`2O&2X1*~tke&RGA$7)!+;Skam!Ypxy&|wT32&FHhM90GoDmZP)WIO^i45v(SaN|ZU^U3B1Lu@0Vd`W}0IEPw?7_!IwC z!2ZEBFZ*1=SNW90XlZFcsz%sQ8QO_*?fh3ZrUj_S82D_8$rP3B#js7LwHlYnbgG8q zWL%nXoRTViNbwN%EEF?Li~y&h^+y{b6K+YU*n78nP6Oo}w7Ih!YzG$0S~!|RSgWCI zLGMF#hlEw5&0`4UW3P`7u>OHR1^mJX#Iqw&$Hv}lub}N+hC3r>r@WwnFhNV?03CK{ zp9&CxXpY#DlG7(cE0&gOB9_Uu%*MlPSek2{(qe7hu!W(8vCG*hhJn4BjaEo-2uskJ z^c;*S^Z}q{`om_Y%}zfW%Hk|rus~LvQKk;xV#HX3GE+Eu+E0% z;8+f(!@;r49qa5^+YT&8m$O4?R;(AY_dx2!WquVy3ILwTaxtK=G0VkiQy+Tug}ww! z8=GKqED zjBy>#z2W=u)<+vyfAlX8M*4Yut8XIlpZRS-L<)n9q2|DuqkiTn;jEXPO9NEX}(SmO~pvpM!;7UT}xZ8a+Qs&|jWXf3*%q|6`fSO@fNDvsJNk*U%@`-9U zj_p*`T1StLrmBuqiR=bMA$#d;mF(RtBKE;gJE-KDx!|ZT$_C$_PNY^nVbxG(Ls^}r zi^X82KxHFJHLK1KFDqq|}}0Cs*r%j!>u29Eu9`iRhK=8__DYg{(>Y zoT{P0OPMi^(-7qG%Zrj3WMhhYdWkcB8M=plK4HZ0a&6`=3$)+4TuCb0hD zKM#EQB``ZNok4X8yocD@)phCiQs|?Asl6~>-&GsoS?A#LGtXmEas6pX5Mn>ZxYuN2 zMW=cXIizr*Pf$NV{Xn#Xu{FciLu-g@vUpPWc69UX5o6sC00q*no66xLy^vl_J{d}L z6oAEnvXP}5N&@S$E6iOcKN4dPKbpV-FgWDEE0!uH*Kl!leg&{{^|KGFbzxWLU0usp zUj6(ljLjW1{PVvdV&6k?uLRQ#)fT2iQ7c$OS_51{TqG={)=^f{C_-04Go)Fd! zz62>=V$Lz=+E~Jn@fB1iQ|W?-IK+F;@mjXFk$mLD`$rI1fB#SAxu4$}ULDtQ)b;V< z_{z=zJ6o)?Zd6*V>*=QFhk50(t{g4LRN*tcfI#m7TblYpwH4aBBgIL?QvxPMa)-=h zA3MNeX@_S(2LQ+OEDGV=@^7h~>Lqz&MV|G>LX<9g2p*E_%3_ftukwk-8tb3P&K+I@9GHXRyo6`jo!fXgt~no)rhA&GSB5Z zn<1@L&c()649QHkK6ZEo;G+VpeeKl8c!f`N?tTHjDVD0(2MPf7$}QUYPe*K^dT@6YZE?QErldInco zud8?pz|b7U?gIA@aF0+no!380# zZ!P+1VLx^C)}anV2W%4^w3y7T8fPOP06a)I1+)rmkb>tVtwyGU`&9D1)jvC7M_O&X zIp2~e%8OXYqppt5rQ^B4-K+AbeDShoccNu4;`4D{?^d|vkKZGa_Pbfpb==4I?qGM zb$KcmoR8N1^A}BL<_5l%Y_hJO;G?dO60map#e3n0XW-BN67XB!625dKo>k$H!V6dF z&ON8dQ46#YaPKZ_SQinxinaDM>6uP*{@cIqa{2H6w=#YBZ~kfF7k>lrBcBTVmd^mc<|gpO0}}(zOUCEwlehw# z&P5zvfhqxY?koMKpnbo*e>CY#leHBfIxGh$fd~;DR0FkvaT41Hf#v6=7hk8oR)8;m zw(75aR^vyWA?A`wG?Rv2C5LRyUR&RvDj_>dDy8_u09SAyRJ9L7cvavQyZ`?LSl?>> zvwu^b`F{ld!0!P5vHwcoo&Of_H~ogduRV4=D}jj}h1obrMv81hBj1$4JI}nnbS*Yq z$+cM!E^g=gdwv$W9%SNxjWJV^^CsY_^CIQXvXPQ7ya>bHCKTvY$uHjp-#!IzDj5V1 zPSnA{$^i#B3%=QyeBddwBqsu7kn9-LY9l+dVKq-{J4e`se{`U-|>U zKL!AQ3-BNO>w*61j>G32MBvr}lLedsQ^4{ANKkRNWMky5b_=zujlQzSJBMB8nvSkh zr-o1;7Rs&wCItMPa3Fw+z|k`CK?EuQlfA!0dFLd5bC#2|P1$)}Ms08JZZ)1Wx^gfI z84@GsQz7+7hXj&=ZA>29wXsIme!A69EY^3l{v=@kN#M)>Uf?T#OW;ipl#=p@l`#fD zXJ-7`J!0(Su6y0jYH8;%P#p#1`{3t`#L@@Co6zW;8z-ZU}9VWilc218&1aAVe> z`l7}3!Dgje4o8?>UXAA2P%!`oIH_V#Nm1txvK!J$3EXyIk!&_L07$pEi(IeqvnDvBTVhbc}#~FW}%B zczYa&Bok5&vS*VsQ|-a6!xLD?C+@Rz-U9PO$9&f@(NH^3t5AyVM872G6$5%uk=g!E zpc%P2xTfqRRv0&e8;Ok?yUW4!7cS5IvC;KffwkVhIG5``yv_zeS9W}0rtccu0v?+1 z>puG*0)EdQBYy3T;i((uK{~OW%f4^>&OUDUcRLdzkV(r?_roRNzm#w60=)CaYPadsWr51jU{AU1q#|c#J|p6*K%JhEG5P@5$ZhH3 zBt?Sz(B0uImA9OClVVOH_PlH(h$h%6c0#Q<`dpxA6Y=TU{MlqvG2TKvHu13KoWu!3 zry-kYld=((r6LO5gl53jfVBdPz(wQ&Vqwl%TnTKu#lqMrek8J^uM=1UP`m^)-<(C? zd*R%0CYy(H{MKP|eCBBQHC_13Z2YND*YX#ix9KZ)eR^+=`NgK`)HQD%)21A%6ks_Q z^NeGcNQ1%7<8t?!M;bN?vhh7XQ&!H;Q5;TFdm%^|`6Q0)tS8&Fdp2A2g`8(llijw* z69NQ8suU?w7EO9v?;y>}vAkS>JYr5BMBsvO=k zXXd{5%-p#jp4s!v{;mI7&pcoD%wGSswb4T$QxY!z;JoTvzG4M4WS*d&baD7)q=JE% zg5dkGDtSUsdZz=X( zDj;-aZJl~?W*#Ic#8L&+#Q=}i*sG&EhCm9+WI8YBX$O)@cx(RAEt@AyrLV$K+*xpw=4S=zn+icDH zhyC-7tbh`%mlU|~1+J+a%B!oD`{p67S>tdtzRdKm^Huh@uL51gEJ0o90K}jc&pO^n zLqJReuQB#WzZNb270Mo~OYp^&Z40)(X*_+$@_q7FFGw3j90CYJ7Or$n_8NQOIC+Tm zZS@tu4@yX^Btwim^fr3h0}!kZJ!39`YvBbdvjC`EF~J-5eiaoZZ~&DlW%1ndj}F$x zCD~6+B(stAaUPiyWZa=-5SCrE!i81CJKLxhO#ytA6hjL^@(|b)EkT|9bUckuB0eNm zgmBEApPk#|akcn^M80B@M)2y!P_nbV%c~RTnA-bbMag5gm7js{(AW% zMjrfNY+QwkTdf3)10>C#4HsUp`r?`_e5d=_Es0NcvG=~S0{GbtpK4@lYknWL<=plu zV3uIbC6EBrOR{y6zXYLEnwa|YDm^3bL1!gI_)I^Sf_PTWk6@D&&HNPNdsV7!$QhaVT~`*d z)QS-h|7A~Y;kHah*($g~#<};szr`Q}z)w9A0B<>t;3Lvx9k*+FV3lqeCy!V?Irk$f z7UyUNZhU^p%vIk<6*%AtPa$YQyKb;N*Bk^&(N6N1j1>~n{K^2TGwU@pj@pnqJ*!#a z7dG!AQ9%s0dQ;Bg1;RY59jqw}B0iL$9%=>%`H4=iuC9JQ^78QV?MTB-#ZMhCcM@&_ zmPwWhu^eq4JW}5^wx|rL3#e#}+vn&5moNCkC=7w?6D5dp^s>iflhc ztI*!G6A&UjGkqkyN^$g2qjD2@)rxwW)*7+ZK{Q>m@zTd)MdUYzzr}IqsxZ=gNTCE{ zN?z(n3g>ew2l=>U+gGn^Za<9~erAP1&>$8-$e4g{(it5`3i%9}da^BA@3d&MpZ2D> z8kyMzyq@dy3GT!bG$Cpp2mL}cbkmJPh=l;*w@%|2yE`t{22u4m$fE%Lb^zUdGAV159J z-?>mnO4zG6kI!;>san;f%|i3DX$jwS(!@ta0@Ut}5<6LkZgG4b;=SwDl*b+21 zL57;29#%unn}AI0gHQ*jOJ+|UFTLwVgo|(%V~!N(XwkRG)<@i#CxrS@75CT{N6W*L zbhFUa`Y1zd9RI*lQbz)%mGym{0b?1A0Z&6+hd0`JLjYj^u+OeNS~51ed_;&^UQ~@Y zEAG>s`>cRDHBSa=WOn`b$ezi12GYeQY~9DN<}md?0p27oFCrttc!gY-2OTH1PG2t%UAjp>b_EQF z{DEK03~Ggdjs`FG!=B*1Pn)hM7Oo=7Z~Ai2SDqa5XTaBocH6s}e^oP|&=;=KlJoh} zbAIRe_!S1<(LmX#P3S+9rbr}+gVA&qK6vIF%Ex;}-MZ=95Mtr2+@JWjT7PNe-|qmxWlaeIE?31IxJ+4Re>Bp07m zLDx<()-6K<=@6~9Kwi%O!p=OR;!rOxfyMSUQ&q)Kw`@V$h!`X8S*g46!}L&TBL4;K z1^;ZyK?X*ON9L@wRJaff48h9rmpSe#CB!t z7_d#-uDCNIM9a7$A{VpDnFRF|Wa}#3Z9b zaK|j3ecSo#$z0yaT$Y7TD5KS8PHJ_JFD5n@OETdxm~tFjP05|}DZ!;F4|*3j)iBVV z$CRj$K_dOqgRQzrWv=G&*sT9zUdrC2kLp&&=shaD_AKwa*Ayk=lWQjD(i+wl)Ilh> zoxp3%ag2fE=J2Hlo!Yh>sG6z#u74%VGfBGkf;3>RKjAchjJzxUSklbJx05{uOxo6$ zqheA-{Z#1HsV~8jrs3!pp@oJkLDE31=I4>8S&v>T_~b9b77n!-8GJcWLMM@v4mkte zFtJi_hp<%Qw;lZma4243_88kgziY48?6w?56X<*osWJzTKq)@axx#Fb;kac$>gMre zPP&ujXc@K~(2j%CE4Mh$R9zka^xNBRW)$6Hb`l0FEkI=G9MOt0w*-4GAm;bp|UYG22R|cRW8v z7fksTg`>Fl0Il%{%7m7LXE~0(i|%`kQZJ;7Cli&o8;|WxXKHIE0+j6b7wsyhbxxNV zj#5MV;a^RM+z$jUd9Sx@SJp4ciZ8?@Kpi$U!}ESsJ%-%edt^dBxumx^O*kf)(o92L zeo#Q1p?3>&i{kE7mxpaHcRY0Xq9hmjLy6@g!L6e;y)!S>225AJZ`Gv}q7+^Dn3${; z-|1w#^~RkGS)IDhepo~0%B7iL{9r{2pU0{WR8&tJ*bR=p3sY?qw@Xtt?3}IeG&&?but_F)ws|Wy zal3iEd3D5Q$UQPisp#FUxPu*gly7%=Of7yO5*AH7KU*%*5FZ~QZSdPJTuKfPus}D1 z{K1Q*xA5M$ux7sHj{K7t4W#A%K}?+@TXT}n*3cEz&VVIv;GW)TOy+g`pH;1EqRWHp zZB?8Ju#D8$G!5C|q5yBFALX&)@Yv5$g_g26Bn($DQr^tf67k6nH^$SK0ZYwcej6|g zpFg*M2~N?Hyj}Z2i5WzDuLirb1=Mi*;06Qoc6HQH@AqMqQy0TPgzeg*n@AE&wup;uY(A<=}V4aL>3}x!L3W{*Spv@Je>H?oF!o^aH$P%Nf3NR z34HRK_Q^#-TR7V_m{t7CpY&o}xBKLw5v;!bsd=HE`|7B*juY2R>fYEhXBy)Km>E%% z`$b;2Umjn;NbFKxjpVTd!dYgLO&ny%>1_ng0L1(zXOok~`YU)~T$P>4FSC};w21y>UMFFnT(tf&CHEs; zoU#O`QDA5Arxk5Wui2O(3nKxrN7MJrIFw2F&~zyJP;C;8PMXmm^jKksfpeX1uJ#pA z)}YCLGn&lEZwey@NQj;9l87NgmA~S(I_R?@NA_la=xQNU=HX7xw10U%?qA>2vYQ^W zm}o#;3P|*n1)97sG3C9@Y<6#g;KrzVx`}PO2oA?Q5j6?E#=d(Z{Jizz#$|J?bv4M= z9zG-`jhu(kvY&|b$77G*QacP%9P z)+tz|ZmgHhzd}RvW%np9Hq&PCm9%)h#nxyU`W9z!-y|sm?IzRH^}Vk~A5#wVd4HJa ze3jRoV3cv}_c=c7omWTwbS#wWOnK`qdlJt8^4~+3VkX#+E_>vVz#(+UJ|K8?A@mO} zgz6H0InvYKWqA+)!xkkL&twyf#W+4tgxK^;3cX-M zO(MTyMA~_8-DjgIT&fF5ySjAoKumoMKJ_)9OKBZQ-%o^vEE_$K;r&to@6)RL;gI<)88(*)6?2w)A|M^^pxvH8&nk=m0 zEh96I2XH~$QP&}t1IR|%+gLbWf^A+Supj42w{c~9T|x*)4*&l3(c&B4vBgkj@_HHm zr(N6}55A7EY~j)RQ`Gi5$Z}z<;1h*rPfxH~X0g@;_jcUzeqpkSdK3Elq+ zfWhsY9sK|AfT?@spKk(G{?6bHcR(Pmz3c&MFl$G94QoedTUT~5esO*YK1p_AK_L-7 zK~X*-VRjuMF?J^e!UHNGfJ7qso&Tn9o*SAU?&UZezI!7Gxcj%FzLO8k1`1Vz+xo!l z-4Rfz_6_O{5GuHC68JCX-#MXBCwpf{Cj>x9QkW9p_3DOU_=nDa7$avpgwx;1STP65 z4Z`>jM8g?okMQ@f2mHG#0S|Y_CzXbp|D~g$e?tL;L?y)`5D6hMF;i-O`WuAuA3A!@ z0rmhv1%>z=*`1p$!+&fU=&Au6oZakiK3@Rlj&OrJ3OHE%I@`kCy#@Z~#|Vf(1SK5A z9jt}K>_x4`MQtE965^7A_72vz5`yBQBI5iv5&SpxDJ+PZ-(&!&DQhZ~Dp-a73l*S( A1^@s6 literal 0 HcmV?d00001 diff --git a/img/ms-icon-310x310.png b/img/ms-icon-310x310.png new file mode 100644 index 0000000000000000000000000000000000000000..862720d6152014f343e7a63488497ca423e8ef7b GIT binary patch literal 62765 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%0A~Sk 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 E0E + + + + + + + carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+ + + + + en pt +
+ + +
+
+
+ +

subscribe via RSS

+ +
+ +
+
+ + + + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 00000000..013d4a6a --- /dev/null +++ b/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/pt/4-erros-comuns-datetime-csharp/index.html b/pt/4-erros-comuns-datetime-csharp/index.html new file mode 100644 index 00000000..9737844e --- /dev/null +++ b/pt/4-erros-comuns-datetime-csharp/index.html @@ -0,0 +1,606 @@ + + + + + + + + 4 Erros Comuns Com Data e Hora no C# — E como evitá-los | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

4 Erros Comuns Com Data e Hora no C# — E como evitá-los

+ +
+ +
+

+ +

NOTA: Eu escrevi este post originalmente para o blog da SubMain. Você pode conferir o original no site deles, em inglês. Enquanto estiver por lá, dê uma conferida no CodeIt.Right, uma ferramenta que pode lhe ajudar com problemas relacionados a tempo e muitos outros.

+ +

Você se lembra daqueles posts no estilo “inverdades que programadores acreditam sobre X” que ficaram bastante populares em blogs de software há alguns anos? O primeiro foi sobre nomes, mas logo apareceram vários outros, cobrindo tópicos como endereços, geografia e compras online.

+ +

O meu favorito era o post sobre tempo. Até esse ponto, eu não havia pensado profundamente sobre tempo e e suas intricacies, e eu fiquei intrigado em saber que um domínio tão fundamental pudesse ser um terreno tão fértil para bugs e confusões.

+ +

Agora, mesmo eu tendo gostado do post, eu vejo um problema com ele: o post lista vários suposições erradas, e basicamente para por aí. Quem lê o artigo provavelmente termina se perguntando:

+ +
    +
  • Por que essas suposições são falsas?
  • +
  • Qual é a probabilidade de eu me dar mal por causa dessas inverdades?
  • +
  • Qual é a maneira adequada de lidar com esses problemas?
  • +
+ +

O artigo é interessante, mas eu acho que faria sentido oferecer informações um pouco mais acionáveis.

+ +

E é exatamente esse é o objetivo do post de hoje. Eu vou mostrar 4 erros comuns que as pessoas cometem ao lidar com tempo em C#/.NET. E não para por aí. Eu também vou mostrar o que você deve fazer para evitar esses erros e tornar seu código mais seguro e mais fácil de ser compreendido.

+ +

1. Calculando Durações de Maneira Ingênua

+ +

Considere o código abaixo:

+ + + +

Ele funciona corretamente? Depende de onde e quando ele será executado.

+ +

Quando você usa DateTime.Now, o valor que você obtém representa a data e hora locais em relação à máquina atual (ou seja, a propriedade Kind está configurada para Local).

+ +

Se o lugar que você mora observa Horário de Verão, então você sabe que existe um dia do ano no qual você deve adiantar os relógios em uma certa medida (geralmente 1 hora, embora existam lugares que ajustam por outras quantidades). E é claro, existe também um dia no qual o oposto acontece.

+ +

Agora imagine o que seguinte: hoje é 12 de março de 2017, e você more na cidade de Nova York. Você começa a usar o programa acima. O método StartMatch() é executado exatamente às 13h. Uma hora e quinze minutos mais tarde, o método EndMatch é executado. O cálculo é realizado e o texto abaixo é exibido:

+ +

Duration of the match: 00:02:15

+ +

Eu imagino que você compreendeu o que aconteceu aqui: quando os relógios estavam prestes a marcar 14h, o Horário de Verão entrou em efeito, movendo-os diretamente para 15h. Então o método EndMatch recuperou o horário atual, somando uma hora adicional ao cálculo. Se o experimento tivesse acontecido no fim do Horário de Verão, o resultado seria apenas 15 minutos!

+ +

Sim, o código mostrado é apenas um exemplo, uma brincadeira. Mas e se fosse algo mais sério? Uma aplicação de folha de pagamento, digamos. Você gostaria de pagar o valor errado a um funcionário?

+ +

O que fazer?

+ +

Quando precisar calcular a duração de atividades humanas, use UTC para os tempos de início e fim. Dessa forma, você será capaz de referenciar de maneira não ambígua um ponto específico no tempo. Ao invés de usar a propriedade Now, use UtcNow para recuperar a data e hora já em formato UTC para realizar os cálculos:

+ + + +

Mas e se os valores DateTime que você tem já são do tipo Local? Nesse caso, você deve usar o método ToUniversalTime() para convertê-los para UTC:

+ + + +

Uma Rápida Advertência Sobre ToUniversalTime()

+ +

O uso do método ToUniversalTime() - e seu irmão, ToLocalTime() - pode ser um pouco chato. O problema é que esses métodos fazem suposições sobre o que você quer baseados no valor da propriedade Kind do objeto datetime que você tem, o que pode trazer resultados inesperados.

+ +

Ao chamar ToUniversalTime(), uma das seguintes coisas vai acontecer:

+ +
    +
  • Se Kind estiver configurado como UTC, o mesmo valor é retornado.
  • +
  • Por outro lado, se estiver configurado como Local, então o valor correspondente em UTC é retornado.
  • +
  • Finalmente, se Kind estiver como Unspecified, então é assumido que o objeto sempre teve a intenção de ser local,, e você recebe o valor correspondente à conversão para UTC.
  • +
+ +

O problema aqui é que valores de data/hora locais não não “transportáveis”. Como assim? Eles são locais enquanto eles permanecerem no contexto da máquina atual. Se você salva um datetime local para um banco de dados e depois o recupera de lá, a informação de que ele é local se perde: agora ele é Unspecified.

+ +

Assim, o seguinte cenário pode acontecer:

+ +
    +
  • Você recupera a data e hora atuais usando DateTime.UtcNow.
  • +
  • Você salva esse valor no banco de dados.
  • +
  • Outra parte do código recupera esse valor. Sem estar ciente de que o valor já está em UTC, chama o método ToUniversalTime() na instância.
  • +
  • Como o valor recuperado do banco possui o tipo Unspecified, o método vai tratá-lo como local e realizar uma conversão desnecessária, gerando um valor errado.
  • +
+ +

Como evitar que isso aconteça? Uma prática recomendada é usar UTC para armazenar o tempo em que um evento aconteceu. Minha sugestão é seguir esse conselho e também esse fato bem explícito. Coloque o sufixo “UTC” em cada coluna de tabela no banco de dados e também em nomes de propriedades que se referem a um valor em UTC. Ao invés de “Inclusao”, use “InclusaoUTC” e assim por diante. Não é tão bonito, mas com certeza é mais claro.

+ +

2. Não Usar UTC Quando Deveria (e vice-versa)

+ +

Nós podemos definir isso como uma regra universal: use UTC para registrar quando eventos aconteceram. Ao logar, auditar, e registrar todo tipo de timestamps na sua aplicação, UTC é a resposta.

+ +

Então, é só usar UTC em todo lugar! Certo? Não, não tão rápido.

+ +

Digamos que você precisa ser capaz de reconstruir o tempo local - na perspectiva do usuário - de quando algo aconteceu, e a única informação que você tem é um timestamp em UTC. Mal dia.

+ +

Em casos assim, faria mais sentido (a) registrar o momento em UTC e gravar também o fuso horário do usuário ou (b) usar o tipo DateTimeOffset, que armazena a data/hora local junto com o deslocamento, ou offset, para UTC, permitindo que você reconstrua o valor em UTC quando precisar.

+ +

Outro caso de uso comum para o qual UTC não é a solução correta é o agendamento de eventos locais no futuro. Você não quer que seu alarme acorde você uma hora mais cedo ou uma hora mais tarde nos dias de transição do Horário de Verão, certo? Pois é exatamente isso que aconteceria se você configurasse o seu alarme pelo horário UTC.

+ +

3. Não Validar Entrada dos Usuários

+ +

Imagine que você criou uma aplicação desktop simples que permite que usuários configurem lembretes. A pessoa informa a data e hora que quer receber o lembrete, clica em um botão, e pronto.

+ +

Tudo parece estar funcionando direito até que alguém do Brasil envia um e-mail para você, reclamando que o lembrete que ela configurou para 15 de outubro às 0h15 não funcionou. O que será que aconteceu?

+ +

O Horário de Verão Contra Ataca

+ +

O vilão aqui é o bom e velho Horário de Verão novamente. Em 2017, o Horário de Verão no Brasil começou à meia-noite do dia 15 de outubro. Então, a combinação de data e hora que a usuária informou simplesmente não existe em seu fuso-horário!

+ +

É claro que o problema oposto também é possível. Quando o Horário de Verão chega ao fim e os relógios são atrasados, isso gera horas ambíguas.

+ +

Qual É A Solução?

+ +

Como lidar com esse tipo de problema no C#? A classe TimeZoneInfo pode lhe salvar. Ela serve para representar um fuso horário e também oferece métodos para verificar se um determinado objeto DateTime é válido:

+ + + +

Mas o que fazer então? O que deveria substituir os comentários “do something” nos trechos acima?

+ +

Você poderia mostrar uma mensagem dizendo que a data informada é inválida. Ou você poderia escolher outra data para a pessoa automaticamente.

+ +

Vamos abordar o caso das horas inválidas primeiro. Suas opções são: mover para frente ou para trás. É uma decisão meio arbitrária, então qual você deve escolher? Por exemplo, o app do Google Calendar no Android move para frente. E até que faz sentido se você parar pra pensar. Isso é exatamente o que seus relógios fizeram devido ao horário de verão. Por que sua aplicação não pode fazer o mesmo?

+ +

E no caso das horas ambíguas? Você também tem duas opções: escolher entre a primeira e segunda ocorrências. Novamente, é meio arbitrário, mas eu aconselho você a escolher a primeira ocorrência, pelo simples fato de tornar as coisas mais simples.

+ +

4. Confundir um Offset com um Fuso Horário

+ +

Considere o timestamp a seguir: 1995-07-14T13:05:00.0000000-03:00. Quando alguém pergunta o que o “-03:00” no final é chamado, muita gente responde “o fuso horário”.

+ +

A questão é essa. Essas pessoas provavelmente assumem corretamente que o número representa o offset, ou deslocamento, em relação a UTC. Também é provável que elas sabem que podem reconstruir a hora correspondente em UTC por meio desse offset. (Muitos desenvolvedores não entendem que, em uma string assim, o offset já está aplicado: para obter o tempo em UTC, você deve inverter o sinal do offset. E só depois, aplicá-lo ao valor da hora).

+ +

O erro está em achar que o offset é a única informação que um fuso horário representa. Mas não é. Um fuso horário é uma área geográfica, e contém muitas informações, tais como:

+ +
    +
  • Um ou mais offsets. (Horário de verão existe, afinal de contas.)
  • +
  • As datas nas quais as transições do horário de verão acontecem. (As quais podem mudar e mudam, sempre que os políticos resolvem).
  • +
  • A quantidade de tempo pelo qual os relógios são atrasados ou adiantados na transição. (Não é uma hora em todo lugar.)
  • +
  • O registro histórico das mudanças nas regras acima.
  • +
+ +

Em resumo: não tente adivinhar um fuso horário pelo offset. Você vai errar a maioria das vezes.

+ +

Quer aprender sobre tempo? Já não era sem tempo!

+ +

Esta lista não é de forma alguma exausitiva. Eu apenas quis oferecer a vocês uma introdução ao fascinante e meio bizarro mundo dos problemas com hora e data em programação. Há muitos recursos valiosos por aí, comoa tag time zone no Stack Overflow ou blogs como o de Jon Skeet e o de Matt Johnson que são autores da popular biblioteca NodaTime.

+ +

E finalmente, sempre use as ferramentas que estão à sua disposição. Por exemplo, o produto da SubMain chamado CodeIt.Right tem uma regra que você a especificar um IFormatProvider em situações nas quais é opcional, o que pode acabar salvando você de bugs difíceis ao fazer tratamento de datas.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/afiando-a-serra/index.html b/pt/afiando-a-serra/index.html new file mode 100644 index 00000000..a63615bb --- /dev/null +++ b/pt/afiando-a-serra/index.html @@ -0,0 +1,581 @@ + + + + + + + + Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe

+ +
+ +
+

+Photo de Sven Brandsma no Unsplash

+ +

NOTA: Eu escrevi este post originalmente para o blog da SubMain. Caso lhe interesse, você pode ler o post original no site deles, em inglês. Enquanto estiver por lá, aproveite para dar uma olhada no CodeIt.Right, uma ferramenta para automatizar revisões de código.

+ +

Você está familiarizado com a expressão “afiar a serra” no contexto de aprendizagem e melhoria contínua? Se você leu o livro de Stephen Covey chamado “Os Sete Hábitos das Pessoas Altamente Eficazes”, então tenho certeza que você está. Para quem não está familiarizado com o termo, significa basicamente se engajar em práticas que o tornarão melhor em sua profissão ou arte.

+ +

O que você como líder técnico, desenvolvedor líder ou arquiteto de software pode fazer para incentivar os desenvolvedores de sua equipe a “afiar suas serra”? Isso é o que vamos responder com este post. Vamos mostrar a você quatro maneiras rápidas e fáceis de sua equipe melhorar suas habilidades e agregar mais valor.

+ +

1. Afiando a Serra pela Leitura: Criar um Clube do Livro Técnico

+ +

Não seria fantástico ter uma equipe formada por pessoas incrivelmente bem informadas, atualizadas com as novidades relevantes, e com sólidos conhecimentos sobre os fundamentos da nossa indústria? Sim, eu pensei que sim. E não há melhor maneira de conseguir isso do que lendo.

+ +

O que eu sugiro aqui é algo muito simples. Todos os meses, você e sua equipe escolhem uma leitura designada para a equipe de desenvolvimento. Sobre que assunto, você pergunta? Padrões de design, concorrência, refatoração, teste unitário - eu diria que praticamente tudo é jogo justo, desde que os próprios desenvolvedores estejam interessados.

+ +

Ah, e antes que eu esqueça: isso provavelmente não precisa ser mencionado, mas sua empresa deve comprar aos desenvolvedores cópias dos livros escolhidos. Se você sente que não pode pagar isso, bem, eu não acredito que você vai ter uma empresa por muito tempo, pra ser sincero.

+ +

Uma solução menos ideal seria comprar uma cópia do livro para um desenvolvedor. Peça que estudem o livro em seu tempo livre e depois apresentem suas descobertas para o resto da equipe, dando uma ou mais palestras internas. Em seguida, selecione outro livro e outro membro da equipe, e peça a esse desenvolvedor que dê a palestra interna no próximo mês.

+ +

Agora, falando em conversas internas…

+ +

2. Afiando a Serra Através de Palestras: Apresentações Internas

+ +

Fazer com que os desenvolvedores façam palestras internas uns com os outros é uma ótima maneira de disseminar o conhecimento por toda a empresa. Para os desenvolvedores que dão a palestra, é a oportunidade perfeita para praticar várias habilidades, tais como:

+ +
    +
  • Aprender um assunto e fazer as pesquisas necessárias.
  • +
  • Criar slides bem feitos.
  • +
  • Falar em público, o que pode ser uma experiência difícil para muitos de nós.
  • +
  • Responder perguntas.
  • +
+ +

Eu poderia continuar, mas em resumo, eles estarão praticando a habilidade geral de comunicação. Isso simplesmente não tem preço. Dar palestras internas pode ser uma ótima prática para falar em conferências, por exemplo.

+ +

E qual a vantagem para quem assiste a palestra? Obviamente, a oportunidade de aprendizado. Mas vou acrescentar que, no caso das conversas internas da empresa, a probabilidade de realmente colocar em uso esse conhecimento que você adquiriu é muito maior. Como os palestrantes são na verdade seus colegas de trabalho - pessoas que compartilham o contexto com você todos os dias e estão cientes dos problemas e desafios que sua empresa está enfrentando - eu diria que é muito provável que eles escolham um tópico que se relacione com a empresa.

+ +

3. Afiando a Serra Com a Escrita: Criar e Manter um Blog de Tecnologia

+ +

Quando seus desenvolvedores dão palestras internas, eles estão ensinando uns aos outros, o que é fantástico. Mas e se eles pudessem disseminar esse conhecimento para além da sua empersa, ao mesmo tempo em que melhoram a sua capacidade de escrita e de articular um argumento? E se eles pudessem fazer isso enquanto aprendem sobre coisas como marketing de conteúdo e SEO? Melhor ainda, e se eles pudessem demonstrar o know-how técnico de sua empresa, posicionando-a como especialista em sua área de domínio?

+ +

Há uma maneira de fazer exatamente isso, e chama-se blogging.

+ +

Inicie um blog de engenharia de software. Decida sobre as especificidades, como por exemplo:

+ +
    +
  • Quais tópicos devem ser abordados?
  • +
  • Com que freqüência você vai publicar?
  • +
  • Quem serão os autores?
  • +
+ +

Faria sentido se, pelo menos no início, os desenvolvedores que são naturalmente melhores escritores fossem os autores do blog. Mas como o objetivo aqui é aprender a afiar a serra - o cenário ideal é aquele em que todo desenvolvedor tem a chance de afiar suas costeletas de escrita.

+ +

4. Afiação da Serra por Programação: Coding Dojos Na Empresa

+ +

Um coding dojo é uma espécie de sessão de treinamento na qual as pessoas revezam em pares, trabalhando de forma colaborativa sobre o mesmo problema. A inspiração para o nome vem das artes marciais. O objetivo de um dojo não é necessariamente resolver o problema… mas desenvolver tanto habilidades de engenharia, como testes unitários/TDD, quanto habilidades sociais, como programação em pares.

+ +

Para realizar um dojo de codificação, você vai precisar do seguinte:

+ +

Espaço. Você precisa de um lugar grande o suficiente para acomodar de 5 a 15 pessoas. (Algumas pessoas dizem que 20 pessoas para um dojo codificador é aceitável, mas IMHO, isso é demais). Já que estamos falando em afiar as serras da sua equipe, um escritório ou sala de reuniões na sua empresa provavelmente serve.

+
    +
  • Um computador**. Pode ser um computador desktop ou laptop; não importa, desde que seja colocado em uma mesa com duas cadeiras, onde duas pessoas possam sentar-se e colaborar confortavelmente juntas.
  • +
  • Um projetor ou um monitor grande**. Todos os participantes precisam observar o que está acontecendo em um determinado momento.
  • +
  • Lanches! Um dojo codificador deve ser uma experiência de união, e os seres humanos adoram se conectar sobre a comida e a bebida. E os programadores são seres humanos, da última vez que verifiquei. Basta ser atencioso com aqueles com restrições alimentares e tudo vai dar certo.
  • +
+ +

Então, você resolveu fazer isso. Você montou o equipamento necessário, e as pessoas apareceram no local combinado. E agora?

+ +

Bem, começando do começo. Você precisa de um problema! Mas nem todos os desafios de programação são um bom problema de codificação do dojo. Como eu disse anteriormente, resolver o problema não é necessariamente o objetivo, mas sim praticar habilidades de engenharia como TDD e programação em pares. Então, escrever um compilador a partir do zero não rola. Mas implementar um conversor para numerais romanos pode funcionar muito bem.

+ +

Quais são as características de um bom problema para um coding dojo?

+ +
    +
  • É pequeno, então é viável resolvê-lo em um tempo relativamente curto.
  • +
  • Empresta-se bem à TDD.
  • +
  • É finito e bem definido. Desafios vagos e em aberto não servem.
  • +
  • É baseado em um problema do mundo real, não um problema abstrato.
  • +
  • É diferente dos desafios que você resolve no seu trabalho diário.
  • +
+ +

Você não precisa se preocupar em encontrar bons problemas, no entanto. A web resolve seu problemaEla está cheia de fontes para problemas lá fora.

+ +

Com a escolha do problema fora do caminho, é hora de escolher uma linguagem de programação. Você não precisa usar a mesma linguagem que você usa todos os dias em seu trabalho. Na verdade, é bom usar o dojo como uma oportunidade para experimentar diferentes linguagens. Isso pode ajudar a tornar as coisas novas e mais desafiadoras. Só não se esqueça de ter por perto uma pessoa que conheça bem essa linguagem para que ela possa ajudar quando o grupo tiver dúvidas.

+ +

Agora, para começar, você vai precisar de dois voluntários: um para ser o motorista e outro para ser o co-piloto. Estes termos vêm da programação em pares. O motorista é a pessoa que está digitando, e o co-piloto dá conselhos e feedback. As demais pessoas são o público, pelo menos por enquanto. O ideal seria que todos em uma sessão de dojo escrevessem código.

+ +

Então, com todos em seus lugares, a diversão começa. O motorista começa a codificar, usando o ciclo vermelho-verde-refatorar da TDD:

+ +
    +
  • Primeiro, a pessoa que está na posição de motorista escreve um teste que falha.
  • +
  • Então, ela escreve apenas a menor quantidade possível de código que vai fazer o teste passar.
  • +
  • Quando o teste está passando, é hora de refatorar. Somente nesta fase as pessoas na platéia têm permissão para falar, dando conselhos e feedback para ajudar o motorista a refatorar melhor o código.
  • +
+ +

Ao final de um período de tempo previamente estabelecido (cinco a dez minutos), o motorista pára de codificar e retorna à audiência. O co-piloto torna-se o motorista, e um novo membro da audiência torna-se o co-piloto.

+ +

Este ciclo continua até que todos na sala tenham escrito o código ou até que o tempo previsto para a sessão expire - o que vier primeiro.

+ +

Retrospectiva

+ +

Assim que a sessão de codificação propriamente dita estiver concluída, dedique algum tempo para fazer uma retrospectiva. Pergunte aos participantes sobre as coisas que eles gostaram e não gostaram da sessão, e escreva tudo isso. Estas duas listas servirão como uma diretriz para o que fazer e não fazer em seus futuros dojos de codificação.

+ +

Conclusão

+ +

O desenvolvimento de software é uma profissão de prática. Requer aprendizagem contínua - ou melhor, afiação contínua da serra. Além das dicas que acabei de lhe dar, há muitas outras maneiras de afiar sua serra. Na verdade, você está fazendo um deles agora mesmo. Você está lendo um blog técnico!

+ +

Desde tutoriais aprofundados sobre ferramentas como CodeIt.Right que podem ajudar sua equipe a escrever melhor código?até insights sobre melhores práticas?até mesmo dicas sobre coisas você pode ter tomado como certo, não faltam tópicos interessantes e úteis que você pode aprender lendo um bom blog sobre tecnologia.

+ +

Obrigado pela leitura!

+ + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/basicos-do-git-usuarios-tfvc.html b/pt/basicos-do-git-usuarios-tfvc.html new file mode 100644 index 00000000..80973b27 --- /dev/null +++ b/pt/basicos-do-git-usuarios-tfvc.html @@ -0,0 +1,734 @@ + + + + + + + + Introdução ao Git para usuários de TFS/TFVC | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Introdução ao Git para usuários de TFS/TFVC

+ +
+ +
+

+ +

Aprender Git pode ser desafiador para desenvolvedores com experiência em versionadores centralizados. Mas não precisa ser assim. +

+ +

Introdução

+ +

O Git está se tornando (já se tornou, muitos diriam) o sistema de controles de versão padrão da nossa área. O versionador foi criado em 2005 por Linus Torvalds para gerenciar o código-fonte do kernel do Linux, e desde então tem apresentado um crescimento fenomenal no seu uso, principalmente após o advento do Github.

+ +

Porém, mesmo após uma década de sua existência, alguns mitos sobre esse sistema ainda persistem. Um deles é de que Git é muito difícil de se aprender. E pela experiência que eu tive, isso simplesmente não é verdade.

+ +

O Git foi criado com o intuito de oferecer muita flexibilidade e poder aos seus usuários. Ou seja, ele permite uma maior complexidade ou sofisticação. Mas na prática, os comandos básicos, aqueles que você realmente irá usar no dia a dia, são relativamente fáceis de se aprender.

+ +

Tendo dito isto, a curva de aprendizado do Git pode apresentar mais desafios para pessoas que estão acostumadas com sistemas de controle de versão centralizados. É natural tentar encontrar padrões e mapear conceitos entre o sistema que se conhece e o que se está aprendendo; mas existem diferenças marcantes o suficiente para que o resultado deste mapeamento seja frustrante.

+ +

Com isso em mente, resolvi escrever uma série de artigos para tentar auxiliar desenvolvedores vindos de versionadores centralizados (especificamente TFS/TFVC) e tentando aprender o Git. Não tenho nenhuma pretensão de fazer uma cobertura exaustiva do assunto; muito pelo contrário: nos momentos em que for necessário, indicarei conteúdos que ofereçam uma explicação mais densa de certos tópicos.

+ +

Uma nota rápida sobre a nomenclatura utilizada neste artigo

+ +

TFS significa Team Foundation Server. É um produto da Microsoft que visa o gerenciamento de projeto, gerenciamento de requisitos, automatização de build, gerenciamento de releases, e diversas outras features.

+ +

O TFS também oferece a feature de controle de versão. Desde a versão 2013 existe suporte nativo para o Git, mas antes disso o versionamento era feito por meio de um versionador próprio, conhecido como Team Foundation Version Control (TFVC).

+ +

Então, TFS se refere à solução completa de gerenciamento do ciclo de vida da aplicação. E TFVC se refere ao versionador.

+ +

Independente disso, neste artigo vou me referir ao versionador como TFS, pois, coloquialmente, muitos desenvolvedores o conhecem por este nome.

+ +

Commit != Check-in

+ +

O TFS, por ser um versionador centralizado, apresenta um fluxo de trabalho razoavelmente simples, que geralmente consiste em três ações:

+ +
    +
  1. Baixar a versão mais atualizada do código-fonte para sua máquina;
  2. +
  3. Efetuar as alterações necessárias;
  4. +
  5. Enviar de volta o código com suas alterações para o servidor.
  6. +
+ +

Então, o comando check-in no TFS acaba tendo duas semânticas: a de “salvar” alterações, e “enviar” estas alterações para o servidor.

+ +

O que noto é que esta noção de “vou enviar minhas alterações para o servidor” é algo um pouco difícil de esquecer ao se fazer a transição.

+ +

Lembre-se: no Git não existe um conceito de servidor central.

+ +

O que existe são remotes, ou seja, repositórios remotos. Você pode ter, a princípio, quantos repositórios remotos você quiser. E eles não necessariamente precisam ser tão remotos assim. Sim, eles podem estar em um site como Github/Gitlab/Bitbucket. Mas também podem estar na máquina do colega ao lado, em uma unidade de rede, ou até em uma outra pasta em sua própria máquina.

+ +

Quando se trabalha em equipe é comum utilizar-se de um repositório padrão que é considerado, para efeitos de organização, o repositório padrão, onde o código “mais atual” encontra-se. Mais uma vez, no Git não existe conceito de servidor central; o uso de tal repositório padrão é uma convenção utilizada pelos times.

+ +

Com isso em mente, vamos treinar um pouco alguns comandos do Git para começarmos a nos habituar com eles. No post de hoje não veremos nada de repositório remoto, servidor, nada disso: apenas comandos locais.

+ +

Baixando e instalando o Git

+ +

Dizem que houve uma época em que trabalhar com o Git no Windows era problemático. Atualmente, não é mais o caso, como você já vai ver.

+ +

Para começar faça o download do Git para Windows.

+ +

Clique duas vezes no arquivo baixado, next, next, você sabe. Em geral não deveria haver problema se você deixar todas as opções como default mesmo; no entanto, é interessante fazer uma alteração:

+ +

+ +

Quando chegar a esta tela, é interessante marcar a segunda opção para que você seja capaz de utilizar o Git a partir do prompt de comando do Windows, e não apenas a partir do Bash do Git.

+ +

Configuração básica

+ +

Depois de terminada a instalação, é necessária fazer a configuração básica de identidade do Git, que consiste em dizer ao Git seu nome e e-mail para que ele os associe a cada commit que você efetuar.

+ +

Para fazer isso, vamos utilizar o Git Bash. No menu iniciar localize o programa “Git Bash” e execute-o. A janela do Git Bash será aberta.

+ +

Digite os seguintes comandos:

+ +
+

git config –global user.name “Seu nome”

+ +

git config –global user.email “email@exemplo.com”

+
+ +

Existem mais configurações e opções possíveis, mas isso já é suficiente para que você comece a experimentar o Git.

+ +

Criando o repositório

+ +

No Git Bash, vamos criar uma nova pasta e em seguida acessá-la:

+ +
+

mkdir repo

+ +

cd repo

+
+ +

Depois de acessarmos a pasta recém-criada, é hora de criarmos nosso repositório:

+ +
+

git init

+
+ +

Depois de executar esse comando, você verá a seguinte mensagem:

+ +
+

Initialized empty Git repository in C:/Users/your-name/repo/.git/

+
+ +

O prompt do Git Bash deveria estar mostrar algo assim:

+ +
+

Usuario@Maquina MINGW64 ~/repo (master)

+
+ +

Ou seja: usuário logado, localização atual e branch atual. O branch padrão do Git chama-se master. No próximo artigo desta série aprenderemos a operação básica de branches, mas por enquanto vamos permanecer apenas no branch padrão mesmo.

+ +

Primeiros comandos

+ +

OK, com o repositório criado, é hora de testarmos alguns comandos. Um dos comandos mais úteis e que você irá utilizar com mais frequência é o git status, que serve para visualizar o estado atual em que se encontra o repositório.

+ +

Ao executá-lo, você deveria ver a seguinte mensagem:

+ +
+

On branch master

+
+ +
+

Initial commit

+
+ +
+

nothing to commit (create/copy files and use “git add” to track)

+
+ +

Ou seja:

+ +
    +
  • o branch atual;
  • +
  • que está esperando por seu primeiro commit;
  • +
  • e indica o que entrará no commit - o que nesse caso é nada, já que ainda não há alterações em nosso repositório.
  • +
+ +

Ele ainda indica qual é o próximo passo a tomar, i.e. criar ou copiar arquivos e depois usar o comando git add para rastreá-los. Por enquanto, não se preocupe com o que “rastrear” significa, pois isso será abordado no futuro.

+ +

Vamos então criar um arquivo.

+ +
+

echo teste > arq1.txt

+
+ +

Execute novamente o comando git status e você verá que desta vez a mensagem está diferente:

+ +
+

Untracked files: +(use “git add ..." to include in what will be committed)

+ +

arq1.txt

+ +

nothing added to commit but untracked files present (use “git add” to track)

+
+ +

Alguns conceitos novos, começando por “Untracked files”, ou, em tradução livre, “Arquivos não rastreados”. O Git está vendo o arquivo que acabamos de criar, mas não está pronto ainda para incluí-lo no próximo commit.

+ +

O interessante é que mais uma vez o Git nos dá a dica do que precisa ser feito, como você pode ver. Execute o comando:

+ +
+

git add arq1.txt

+
+ +

Execute novamente git status e veja que a resposta mudou novamente:

+ +
+

Changes to be committed:

+ +

(use “git rm –cached ..." to unstage)

+ +

new file: arq1.txt

+
+ +

Por enquanto ignore a mensagem:

+
+

use “git rm –cached ..." to unstage

+
+ +

Agora podemos ver que o arquivo adicionado está pronto para entrar no commit. Então, vamos “commitar”:

+ +
+

git commit -m “Primeiro commit”

+
+ +

O comando acima cria o nosso primeiro commit. O parâmetro -m serve para especificar uma mensagem de commit, o que é essencial para o futuro entendimento da evolução de um projeto.

+ +

git status novamente:

+ +
+

On branch master

+ +

nothing to commit, working directory clean

+
+ +

Para terminar, vamos fazer uma alteração em nosso arquivo. Abra o arquivo no Bloco de Notas (ou outro editor de texto de sua preferência) e acrescente a seguinte linha:

+ +
+

acrescentando uma nova linha

+
+ +

git status novamente:

+ +
+

On branch master +Changes not staged for commit: +(use “git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory)

+ +

modified: arq1.txt

+ +

no changes added to commit (use “git add” and/or “git commit -a”)

+
+ +

A mensagem é familiar, apesar de ser diferente das anteriores. Como você já deve estar acostumado, ela termina com uma dica da próxima ação a ser tomada. Vamos então seguir a sugestão do Git:

+ +
+

git add arq1.txt

+
+ +

Perceba que é o mesmo comando que executamos lá atrás, quando o arquivo ainda estava no estado “untracked”. Embora o comando seja o mesmo, neste caso aqui ele tem um significado ligeiramente diferente. No futuro, entenderemos estas diferenças.

+ +

Ao executar novamente git status recebemos, novamente, uma nova mensagem:

+ +
+

Changes to be committed: +(use “git reset HEAD ..." to unstage)

+ +

modified: arq1.txt

+
+ +

Embora seja parecida com uma das mensagens anteriores, perceba que agora o nosso arquivo está no estado “modified”, e não “new file”, o que faz bastante sentido.

+ +

Imagino que você saiba o que vem a seguir:

+ +
+

git commit -m “Segundo commit: adicionamos segunda linha para testar alteração”

+
+ +

Para terminar, execute novamente o git status e verá novamente a mensagem já familiar: diretório de trabalho limpo, nada a ser commitado.

+ +

Conclusão

+ +

Este artigo foi extremamente simples, e isso não foi um acidente. Minha intenção foi de mostrar os comandos mais básicos, com a intenção de que você pegue o “feeling” de como se usa o Git.

+ +

Perceba que existe um padrão facilmente perceptível nos comandos que executamos:

+ +
    +
  • cria um arquivo
  • +
  • “adiciona”
  • +
  • dá commit
  • +
  • faz alteração no arquivo
  • +
  • “adiciona”
  • +
  • dá commit novamente
  • +
  • etc
  • +
+ +

Nos lugares onde coloquei “adiciona”, você sabe que estou me referindo ao comando git add. Você talvez tenha percebido que este comando tem duas finalidades diferentes, evidenciado pelas diferentes mensagens que o git status retornou depois de sua execução.

+ +

Você provavelmente também notou os diferentes estados que os arquivos em um repositório podem assumir: “untracked”, “new file”, “modified”. Eles caminham de um estado para o outro, como em uma pipeline.

+ +

No próximo post da série vamos nos aprofundar nestas questões. Iremos entender as áreas existentes em um repositório, entender o fluxo de trabalho e os estágios pelos quais os arquivos passam.

+ +

Vamos começar também a trabalhar com um dos conceitos mais importantes do Git: branches. Iremos dar início às operações mais comuns que são realizadas com branches, e também mostraremos como branches no Git diferem da maneira que você está acostumado a trabalhar no TFS.

+ +

Até lá!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/blogs-desenvolvimento-portugues/index.html b/pt/blogs-desenvolvimento-portugues/index.html new file mode 100644 index 00000000..32c3fc02 --- /dev/null +++ b/pt/blogs-desenvolvimento-portugues/index.html @@ -0,0 +1,530 @@ + + + + + + + + Blogs em português sobre desenvolvimento de software que você deveria seguir! | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Blogs em português sobre desenvolvimento de software que você deveria seguir!

+ +
+ +
+

+ +

Para o bem ou para o mal, o idioma da tecnologia é o inglês. Mas isso não significa que não existe conteúdo de qualidade sendo produzido na nossa língua. +

+ +

O inglês é a língua franca da tecnologia, como eu já disse quando expus minha opinião sobre a controvérsia de se programar em inglês ou português.

+ +

Além das oportunidades que saber inglês pode lhe trazer, eu acredito que o maior benefício que você consegue é ter acesso a muita informação de qualidade.

+ +

Porém, isso não quer dizer que não exista informação de qualidade sendo publicada na nossa língua. Seguem agora três blogs que você já deveria estar acompanhando:

+ +

Object Pascal Programming

+ +

Vamos começar a lista com o Object Pascal Programming, blog do Marcos Douglas Santos, o qual eu citei no meu último post.

+ +

Conheci esse site há cerca de dois meses, por acaso, e desde então tenho lido todos os artigos, que são publicados assiduamente toda semana.

+ +

Talvez vocês estejam se perguntando o que há de tão interessante em um blog de Object Pascal para um programador C#? Aí é que está: não se deixem enganar pelo título. Marcos escreve sobre conceitos e boas práticas da orientação a objetos, de uma forma que é aplicável para a maioria da linguagens que seguem esse paradigma.

+ +

Quando há exemplos de código, esses são escritos em Object Pascal, mas são simples e claros o bastante para que você consiga seguir, independente de ter ou não experiência com essa linguagem.

+ +

Além da qualidade dos artigos em si, é importante citar ótimo trabalho que Marcos tem feito em fomentar uma comunidade em torno do blog, com o uso de redes sociais, chat e lista de e-mail.

+ +

Recomendadíssimo!

+ +

Robson Castillo

+ +

O Robson publica em seu blog desde 2010, e aborda uma gama bem diversa de assuntos.

+ +

Ele já escreveu sobre tecnologias específicas, como tutoriais de ASP.NET MVC, passando por assuntos mais “high level” como arquitetura de software, Design Patterns e boas práticas de codificação, sem esquecer das metodologias ágeis e gerenciamento de carreira.

+ +

Uma área muito bacana neste blog é a página de leituras recomendadas. Apesar da avalanche de informação disponível na Web, eu acredito que livros ainda têm um lugar importante no aprendizado de desenvolvedores, e vejo que Robson compartilha da minha visão.

+ +

Embora existam alguns posts que são específicos a .Net e C#, a grande maioria não é. Então, independente de qual seja a linguagem que você usa, pode ir sem medo que você vai encontrar conteúdo de qualidade no blog do Robson.

+ +

Não deixe de conferir!

+ +

Elemar Jr

+ +

Elemar Jr é um nome bastante conhecido na comunidade .NET. Assim como Robson, ele publica em seu blog desde 2010.

+ +

Elemar é conhecido por ser incrivelmente prolífico, escrevendo sobre um número impressionante de tópicos. Existe um certo viés para C#, mas ele também aborda diversas outras linguagens, tecnologias e técnicas, como C++, F#, Haskell, HTML, Javascript, testes automatizados, arquitetura, e muito mais.

+ +

Um aspecto interessante do blog do Elemar é que ele não para no conteúdo técnico, explorando também tópicos como filosofia, política, psicologia, economia, entre outros, o que eu acho valiosíssimo. Nós, desenvolvedores, às vezes só conversamos com outros desenvolvedores, sobre desenvolvimento, e isso não é saudável.

+ +

Nos reconectar com o mundo ao nosso redor é necessário para uma vida equilibrada. E no lado profissional, nos envolver com as humanidades também melhora a nossa visão do negócio e de como o código que escrevemos é apenas um meio para gerar valor para nossos clientes e nossas empresas.

+ +

Recentemente, Elemar começou a blogar também em inglês, o que é uma iniciativa com a qual eu naturalmente concordo ;)

+ +

Boa leitura!

+ +

Conclusão

+ +

Você deve estar se perguntando porque mantive o número de blogs recomendados baixo. Um dos motivos é que, com esses três blogs, você já tem leitura de sobra para muito tempo (isso se formos considerar apenas os artigos já publicados. É claro que os blogs estão na ativa, então mais posts continuarão vindo).

+ +

O segundo - e mais importante - motivo é que sou bastante exigente com o que leio. Não gosto de perder tempo com textos pessimamente escritos, com argumentos sem embasamento, ou com títulos sensacionalistas apenas para ganhar cliques.

+ +

Evidentemente, nenhum dos três blogs acima tem essas características. Você ter a certeza que os blogs recomendados nesse post oferecem um conteúdo de alta qualidade, capaz de aumentar seu conhecimento e trazer benefícios para a sua carreira.

+ +

E você, tem algum blog que gostaria de recomendar? Compartilhe com a gente nos comentários.

+ +

Até a próxima!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/boas-praticas-sem-tempo/index.html b/pt/boas-praticas-sem-tempo/index.html new file mode 100644 index 00000000..c88e713d --- /dev/null +++ b/pt/boas-praticas-sem-tempo/index.html @@ -0,0 +1,582 @@ + + + + + + + + Boas Práticas De Programação Para Os Apressados | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Boas Práticas De Programação Para Os Apressados

+ +
+ +
+

+Photo by Ales Nesetril on Unsplash

+ +

NOTA: Este post foi originalmente escrito para o blog da the SubMain. Você pode ler o artigo original no site deles, em inglês. Quando estiver por lá, baixe e experimente o CodeIt.Right.

+ +

Um dos tópicos em desenvolvimento de software que me interessa muito são boas práticas de codificação. Eu estou sempre pesquisando e buscando maneiras de aperfeiçoar meu trabalho e entregar valor de forma rápida e consistente.

+ +

Pode ser meio espinhoso definir o que “é realmente uma boa prática”. Há pessoas que inclusive sugerem aposentar o termo! Mas um ponto em que praticamente todos concordam é: descobrir e implementar estratégias - não importa o nome que você coloca nelas - para melhorar o resultado do seu trabalho é algo que qualquer programadora ou programador que faz jus a esse nome deveria fazer continuamente.

+ +

Claro, não existe almoço grátis. A adoção de uma boa prática leva tempo, o que você provavelmente não tem muito sobrando para começo de conversa. Isso sem mencionar a gerência, nem sempre muito animados a tentarem coisas novas.

+ +

Então, o que fazer se a sua equipe de desenvolvimento está sofrendo com a baixa qualidade de uma base de código, mas não tem tempo para implementar as boas práticas que remediariam a situação?

+ +

A resposta que eu ofereço é o que eu vou chamar de “pacote emergencial de boas práticas”: uma pequena lista de boas práticas de programação que você pode adotar em relativamente pouco tempo para levar sua equipe e sua aplicação do completo caos para um estado mais gerenciável.

+ +

Sim, eu sei que há tantos conselhos sobre boas práticas por aí que é até difícil não se sentir sobrecarregado. Por causa disso, eu restringi a minha lista de boas práticas a itens que atendam aos seguintes critérios:

+ +
    +
  • As boas práticas precisam ser fundamentais, no sentido de que elas são blocos básicos a partir dos quais você pode implementar práticas mais sofisticadas depois.
  • +
  • Você pode adotá-las em relativamente pouco tempo. (Eu diria que uma semana é praticável.)
  • +
  • O seu custo é zero ou perto disso.
  • +
+ +

As práticas a seguir atendem os critérios listados. E sem mais enrolação, aqui está: meu pacote emergencial de boas práticas de codificação, com itens listados na ordem que eles deveriam ser adotados, começando pelo mais crítico.

+ +

Sistema de Controle de Versão

+ +

Eu trabalhei uma vez em uma empresa de desenvolvimento de software na qual nenhum sistema de controle de versão era usado. Os arquivos de código fonte ficavam em uma pasta compartilhada que qualquer desenvolvedor podia acessar. Qual era o processo usado para poder editar um arquivo? Você provavelmente adivinhou: nós criávamos uma cópia do arquivo e adicionávamos “_OLD” ao final do nome.

+ +

Isso aconteceu há oito ou nove anos, o que significa que as coisas devem ter melhorado, certo? Bom, provavelmente melhoraram, um pouco, mas não totalmente. Ainda tem empresas por aí que não usam controle de versão.

+ +

Como proceder?

+ +

De agora em diante, eu vou assumir que você concorda que versionamento é uma boa prática fundamental. Caso esse não seja o caso, há muitos recursos pela web afora explicando o que um versionador é e porque você deveria usar um.

+ +

Com isso resolvido, é hora de sermos mais específicos. Qual ferramenta usar? Como proceder com a sua adoção?

+ +

Git é uma escolha sólida. E apesar de ter uma curva de aprendizado mais acentuada paraquem já está mais acostumado com sistemas de controle de versão centralizados, como Subversion ou TFVC, Git é o padrão de facto da indústria. Então, sem sombra de dúvidas, você deve aprender git. Não fazê-lo pode prejudicar a sua carreira no futuro.

+ +

Mas é possível que o Git não seja a melhor escolha para o seu time agora. Lembre-se, você não tem muito tempo. Nós precisamos que a sua equipe adote as boas práticas o mais rápido possível.

+ +

Como nós podemos fazer isso? Suponha que você tenha experiência com Subversion, pois esse era o versionador usado na empresa que você trabalhou anteriormente. Sua experiência com Git, porém, é nenhuma. Se esse é o caso, eu diria que Subversion é a melhor escolha para você. Ter que aprender um novo sistema e ensiná-lo para seus colegas ao mesmo tempo que o coloca em vigor na empresa seria demais: você iria apenas se sobrecarregar.

+ +

Revisão de Código

+ +

Eu não vou mentir: eu sou um grande fã de revisão de código. E eu não estou sozinho nisso.. Eu já testemunhei em primeira mão como um bom processo de revisão de código pode reduzir o número de problemas em uma aplicação, tornar o código mais consistente e, mais importante ainda, espalhar conhecimento por todo o time de desenvolvimento.

+ +

E aqui vai uma ótima vantagem dessa prática: revisão de código é algo relativamente fácil de ser implementado. Comece da maneira mais simples possível, e então faça adaptações na sua abordagem conforme as necessidades aparecerem.

+ +

Minha Definição de Revisão de Código

+ +

Falar de revisão de código pode ser complicado. As pessoas às vezes tem ideias totalmente diferentes sobre o que a expressão significa. Então eu acho que uma clarificação se faz necessária.

+ +

Eu não sou a favor de um processo de revisão de código altamente burocrático e estressante, no qual o seu código é esmiuçado, em público, durante horas. Eu não acredito que envergonhar as pessoas em público é uma forma eficaz de aumentar a qualidade de um projeto. Ao contrário, o tipo de revisão de código que eu defendo é um processo simples, geralmente iniciado ao submeter um pull request ou usando sua IDE favorita.

+ +

Como Proceder

+ +

Agora que nós estamos sintonizados em relação ao significado de “revisão de código”, a próxima pergunta é: “como implementar isso na prática?” Da maneira mais simples possível que funcione.

+ +

Por exemplo, se a sua empresa desenvolve em .NET e usa TFS/TFVC, você pode começar instalando uma política de check-in que exige uma revisão de código para cada check-in. Se a sua equipe usa GitHub, vocês podem usar pull requests. Apenas comece a realizar revisões de código. Então, com o tempo, vá fazendo os ajustes e adaptações necessários.

+ +

Estas são algumas das questões que podem surgir ao refinar o seu processo:

+ +
    +
  • Qual é o objetivo da revisão de código? Estamos procurando por bugs? Tentando melhorar a legibilidade?Checando se o código adere ao padrão de codificação da empresa?
  • +
  • Como separamos “sugestões” de “impedimentos”? É OK recusar a alteração de alguém por causa de uma indentação ruim ou um nome de variável ligeiramente equivocado?
  • +
  • O que fazer se revisor e revisado não conseguem chegar a um consenso? Trazer um mediador para dar a palavra final? E quem seria essa pessoa?
  • +
+ +

A resposta para todas as perguntas acima podem ser encontradas na automação. Uma boa parte do desconforto das revisões de códigos pode ser eliminada quando você emprega um analisador de código para lidar com as partes automatizáveis do processo.

+ +

Por exemplo, SubMain possui um produto chamado CodeIt.Right que oferece feedback em tempo real de dentro do Visual Studio, lhe alertando de possíveis problemas de codificação, inclusive corrigindo problemas quando possível.

+ +

Ao abraçar a automação, você deixa as pessoas da equipe livres para se preocuparem com questões de mais alto nível durante as revisões, como claridade do código ou decisões arquiteturais.

+ +

Builds Automatizados

+ +

Talvez você esteja pensando que eu me equivoquei nessa seção. Afinal de contas, sequer faz sentido falar de builds automatizados sem mencionar testes automatizados?

+ +

Eu vou argumentar que sim, faz sentido, por uma razão muito simples: builds automatizados eliminam o famoso problema de “na minha máquina funciona”. 

+ +

Ter um local central onde os builds são feitos joga luz em vários tipos de problemas, de mal gerenciamento de dependências a falta de disciplina em testes.

+ +

Como Proceder

+ +

Meu conselho aqui é o mesmo que na seção anterior: faça a coisa mais simples possível que funcione.

+ +

Se sua equipe já usa TFS, aprenda como criar uma definição de build. Se os seus projetos estão no GitHub, dê uma olhada no Travis CI.

+ +

Com o tempo, você vai melhorando a sua estratégia. Lembra dos analisadores de código que eu mencionei anteriormente? É possível integrá-los no seu processo de build. Testes unitários e outros tipos de testes automatizados também são uma valiosa adição.

+ +

E por falar nisso…

+ +

Ausências Notáveis

+ +

Você talvez tenha se surpreendido por minha lista de boas práticas não incluir testes unitários, mesmo eu sendo um defensor da importância de testes automatizados para a qualidade de uma aplicação. Qual é a razão disso?

+ +

Infelizmente, adicionar testes unitários a uma aplicação legada é muito difícil, ao ponto de existir até um livro famoso que foca apenas nisso. Não é uma tarefa fácil de se fazer em pouco tempo.

+ +

Também é possível que muitos de vocês esperavam que eu falasse sobre código limpo ou os princípios SOLID. Eu encorajo vocês a lerem e pesquisarem sobre esses tópicos, mas eu não acredito que eles encaixam no propósito do post de hoje. Como o próprio nome deixa claro, eles são princípios. Pense neles como diretrizes filosóficas. Úteis? Claro. Mas não tão fáceis de decompor em conselhos pequenos, simples e acionáveis.

+ +

Implemente Essas Práticas Para Ontem!

+ +

É possível que vários de vocês tenha achado essas práticas extremamente básicas e não dignas de um post. “Quem é que não usa controle de versão em 2018???”

+ +

Bom, não é tão difícil assim encontrar evidência (anedótica, mas ainda assim) que as coisas ainda não são tão perfeitas.

+ +

Acreditar que mesmo práticas tão fundamentais como versionamento de código ou testes automatizados são aplicadas universalmente é mais ingenuidade do que talvez queremos admitir.

+ +

Para o restante de vocês, eu espero que essa lista seja útil.

+ +

Você já deve ter ouvido o ditado. “Quando estiver em um buraco, para de cavar.” E é exatamente esse o tipo de ajuda que eu quis oferecer com esse post: correções rápidas e fáceis, para que você e as demais pessoas em seu tipo possam recuperar o suficiente de sanidade para poderem focar e recuperar o controle de sua aplicação, garantido sua saúde a longo prazo.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/cargo-cult-programming/index.html b/pt/cargo-cult-programming/index.html new file mode 100644 index 00000000..f5c6eba5 --- /dev/null +++ b/pt/cargo-cult-programming/index.html @@ -0,0 +1,644 @@ + + + + + + + + Programação Cargo Cult É A Arte de Programar Por Coincidência | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Programação Cargo Cult É A Arte de Programar Por Coincidência

+ +
+ +
+

+ +

NOTA: Eu escrevi este post originalmente para o blog da NDepend. Você pode clicar aqui para ler o artigo original no site deles, em inglês. Enquanto estiver por lá, baixe e experimente o NDepend.

+ +

Eu ouvi falar em programação cargo cult a primeira vez há alguns anos. Eu me lembro de ter pensado na época: “Que nome estranho para um conceito relacionado com programação”.

+ +

Se você compartilha do estranhamento do meu “eu” do passado, o post de hoje é para você.

+ +

Primeiramente, você verá o que programação cargo cult é e por que você deve se importar. Então, vamos dar uma olhada em alguns exemplos práticos, usando a linguagem C#. Finalmente, nós encerraremos com conselhos sobre o que você pode fazer para não cair nessa armadilha.

+ +

Programação Cargo Cult: Fazendo as coisas porque sim.

+ +

Segundo a versão em inglês da Wikipedia

+ +
+

Cargo cult programming is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose.

+
+ +

Em tradução livre

+ +
+

Programação cargo cult é um estilo de programação de computadores caracterizado pela inclusão ritualística de código ou estruturas de programação que não servem nenhum propósito real.

+
+ +

Em outras palavras, é quando um(a) desenvolvedor(a) escreve código sem entender realmente o que aquele código faz. Talvez uma abordagem por tentativa e erro tenha sido usada - copia o código de um lugar, cola em outro, e vai mexendo e testando até que funciona, mais ou menos. Quando chega nesse ponto a pessoa geralmente para de mexer no código, por medo de fazer parar de funcionar. No processo, talvez sobrem resquícios de código que não servem realmente para nada.

+ +

Ou talvez a pessoa tenha tentado usar uma técnica aprendida com um colega, mas falhou em compreender que os conceitos são diferentes e que a tal técnica é inútil na situação atual.

+ +

Por fim, também é possível que o problema seja simplesmente educação insuficiente: talvez o desenvolvedor tenha um entendimento pobre a respeito de como as ferramentas usadas funcionam.

+ +

Por que a programação cargo cult é um problema?

+

Como Eric Lippert diz, programadores cargo cult sofrem para fazer alterações significativas em um programa e acabam usando uma abordagem de tentativa e erro já que eles não entendem o funcionamento interno do código que estão prestes a alterar.

+ +

Isso não é tão diferente do que os programadores pragmáticos chamam de “programação por coincidência”:

+ +
+

Fred doesn’t know why the code is failing because he didn’t know why it worked in the first place. It seemed to work, given the limited “testing” that Fred did, but that was just a coincidence.

+
+ +

Em tradução livre:

+ +
+

Fred não sabe porque o código está falhando porque ele não sabe porque ele funcionou da primeira vez. Parecia estar funcionando, com o “teste” limitado que Fred fez, mas era apenas uma coincidência.

+
+ +

A frase acima resume tudo para mim: se você não sabe como ou por que seu código funciona, você também não vai entender o que aconteceu quando ele parar de funcionar.

+ +

Origem do termo

+

Embora práticas que são consideradas “culto à carga” (cargo cult) atualmente tenham sido registradas tão cedo quanto o final do século XIX, o termo em si data de 1945, quando foi usado pela primeira vez para descrever práticas que surgiram durante e depois da Segunda Guerra Mundial entre habitantes da Melanésia.

+ +

Os nativos começaram a imitar o comportamento dos soldados, vestindo-se como controladores de voo e balançando gravetos, na esperança de que isso faria com que aviões carregados de suprimentos descessem dos céus.

+ +

Desde então, o termo culto à carga tem sido usado em uma variedade de contextos para significar imitar forma sem conteúdo - copiar perfeitamente os elementos superficiais mas ao mesmo tempo falhando em entender de maneira mais profunda o significado e funcionamento do que se está tentando emular.

+ +

Falar é fácil; me mostre o código!

+

Chega da aula de História por hoje. Hora de ver código! Eu vou mostrar cinco exemplos de programação cargo cult usando a linguagem C#. Vamos lá.

+ +

Checar um tipo de valor não-nulável for Null

+

O primeiro item é algo que me incomoda já que eu vejo isso bastante em código de produção. É algo assim:

+ +
	public Product Find(int id)
+	{
+   	   if (id != null) // essa verificação é inútil
+	   {
+	       Console.WriteLine("Esta linha sempre será executada.");
+	   }
+	
+	   return new Product();
+	}
+ +

Aqui nós temos o caso de um(a) desenvolvedor(a) que provavelmente não entende a diferença entre tipos de valor e referência. Seria completamente perdoável, no caso de um profissional iniciante, se não fosse pelo fato de que o compilador te avisa disso.

+ +

Você pode achar isso um exagero da minha parte. Afinal de contas, o código vai rodar perfeitamente mesmo assim. Na verdade, a verificação não será nem ao mesma incluída no IL resultante, como você pode ver nesse print de uma ferramenta de descompilação:

+ +

Uma imagem mostrando um trecho de código que não contem a checagem de nulo.

+ +

Você pode ver no trecho de código acima que o compilador otimizou o código, removendo a checagem por nulo.

+ +

Tem problemas muito piores, claro. Sim, a aplicação não vai quebrar por causa disso. Então, qual é o ponto?

+ +

Bom, pra começo de conversa, eu me preocuparia com uma empresa de desenvolvimento cujo único critério de qualidade é “roda sem quebrar”. Mas o problema de verdade aqui é que esse tipo de código demonstra uma falta de entendimento sobre características fundamentais da linguagem e da plataforma que podem lhe causar problemas no futuro.

+ +

Uso Desnecessário de ToList() em consultas do LINQ to Object

+

Assim como o problema anterior, o item atual é algo que eu rotineiramente vejo em código de produção. Considere o código abaixo:

+ +
	var result = users.ToList()
+	.Where(x => x.PremiumUser)
+	.ToList()
+	.Select(x => new { Name = x.Name, Birth = x.DateOfBirth })
+	.ToList();
+ +

O problema que temos aqui é que as chamadas ao método ToList() são totalmente desnecessárias (exceto talvez a última, caso você realmente precisasse que o resultado fosse um lista e não apenas um IEnumerable).

+ +

Em minha experiência, isso acontece quando quem escreveu o código não entende bem a natureza do LINQ; eles erroneamente acham que os métodos do LINQ pertencem ao tipo concreto List<T> ao invés de serem métodos de extensão que podem ser usados com qualquer implementação de IEnumerable<T>.

+ +

Ao chamar ToList() diversas vezes dessa forma, o desenvolvedor na verdade cria diversas listas novas, o que pode prejudicar o desempenho da aplicação.

+ +

O código acima pode ser reescrito da seguinte forma:

+ +
	var result = users.Where(x => x.PremiumUser).Select(x => new { Name = x.Name, Birth = x.DateOfBirth });
+ +

Conversões Desnecessárias

+

Considere a linha seguinte:

+ +
	DateTime creationDate = DateTime.Parse(row["creation_date"].ToString());
+ +

Aqui temos não apenas uma mas duas conversões desnecessárias. Primeiro, criamos uma nova string e então a “parseamos” para DateTime quando um simples cast seria suficiente:

+ +
	DateTime creationDate = (DateTime)row["creation_date"];
+ +

Esse exemplo assume que o tipo no banco de dados é um tipo específico para lidar com datas (como date ou datetime no SQL Server). É claro que se você estivesse usando um tipo inadequado (como varchar) então isso já seria um outro problema.

+ +

Try-Catch em todo lugar

+

Também conhecido como síndrome Pokémon (“Gotta catch’em all!”), o anti-pattern aqui é adicionar um bloco try-catch em cada linha em que exista a remota possibilidade de uma exceção ser disparada.

+ +

Pontos bônus se o código estiver tentando capturar System.Exception ao invés de uma exceção mais específica, acabando com a distinção entre erros esperados e não esperados.

+ +

Mais pontos se o bloco do catch não conter código nenhum!

+ +

A dica geral aqui é: jamais capture uma exceção a não ser que você tenha uma razão muito específica para fazê-lo. Do contrário, deixe que a exceção suba até que o gerenciador de exceções geral no nível mais alto lide com ela.

+ +

Se esse conselho parece vago (“Como vou saber se eu tenho uma boa razão para capturar a exceção?”), é porque de fato é. Explorar esse tema mais a fundo iria além do escopo desse post, , mas ler o excelente artigo do Eric Lippert chamado “Vexing Exceptions” vai aumentar e muito o seu entendimento sobre exceções.

+ +

Usar StringBuilder Demais

+

Você já deve ter visto o filme: depois de ler em algum lugar que concatenar strings usando + é ineficiente, nosso intrépido desenvolvedor resolve tomar pra si a tarefa hercúlea de mudar cada concatenação de string no projeto para o uso de StringBuilder.

+ +

A justificativa para isso, claro, é que System.String é imutável. Então, cada vez que você “muda” a string, você na verdade está criando uma instância nova na memória, o que pode prejudicar o desempenho da aplicação.

+ +

Mas adivinha só. O compilador é bem esperto. Digamos que você tenha a seguinte linha:

+ +
	string a = "Hello " + "World";
+ +

Isso vai ser no fim das contas traduzido para:

+ +
	string a = "Hello World";
+ +

A regra geral é: tudo bem usar concatenação simples se você sabe o número de strings a anexar em tempo de compilação. Do contrário, o uso de StringBuilder provavelmente faz mais sentido.

+ +

Lógico, alguns cenários não são tão claros assim. O único conselho que faz sentido dar aqui é: faça seu dever de casa. Quando estiver com dúvida, pesquise e faça benchmark sem dó.

+ +

Eu termino com mais uma dica sensata do Eric Lippert:

+ +
+

Unnecessary code changes are expensive and dangerous; don’t make performance-based changes unless you’ve identified a performance problem.

+
+ +

Existe Solução?

+

Eu diria que é justo supor que pessoas com menos experiência são mais propensas a cometer erros devido à programação cargo cult. Mas desenvolvedor nenhum está realmente a salvo, independentemente de seu nível de conhecimento ou experiência.

+ +

Nós somos apenas humanos no fim das contas. Cansaço, prazos, vieses cognitivos e (para ser realmente honesto) a preguiça eventual pode transformar até o melhor de nós em um programador cargo cult.

+ +

Infelizmente, não há uma maneira 100% garantida de impedir isso de acontecer. Mesmo assim, aqui vão algumas medidas que você pode tomar para, ao menos, diminuir as chances.

+ +

Vamos ver algumas delas.

+ +

Use Revisão de Código/Programação em Par

+

A primeira medida que você pode tomar para evitar o cargo cult é simplesmente ter uma segunda pessoa olhando seu código. Os benefícios de ter uma outra pessoa revisando cada linha de código antes que ela chegue em produção não podem ser subestimados. E embora revisão de código e programação em par não são exatamente equivalentes, ambas as práticas podem lhe trazer esse benefício.

+ +

Sempre Teste Suas Hipóteses

+

Escreva testes de unidade (e outros tipos de testes também). Monitore sua aplicação em produção. Se algo não está tendo um bom desempenho, faça benchmarks exaustivos. Não faça só suposições. Testar as suas hipóteses pode trazer insights valiosos e salvar a sua pele naqueles momentos em que a sua intuição não for certeira.

+ +

Leia Código de Outras Pessoas

+

Ler código escrito por outras pessoas é uma ótima maneira de aprender. É uma ferramenta perfeita para comparar suas ideias e suposições contra o que outros desenvolvedores estão fazendo, expondo você a novos conceitos que podem lhe forçar a ganhar um entendimento maior dos problemas que está tentando resolver.

+ +

Na era do GitHub, não tem muita desculpa para não fazer isso.

+ +

Aprenda Com Suas Ferramentas

+

Existe um número enorme de ferramentas que podem ajudar sua equipe com a qualidade do seu código. Aqui vai a dica principal: você não deve só usar essas ferramentas. Você deve também aprender com elas. Se você usa NDepend, leia sobre suas regras. Tente entender a justificativa por trás de cada uma delas. Quais são os princípios e boas práticas que guiaram seus autores durante a criação delas?

+ +

A mesma dica vale para outros tipos de ferramentas, e até para os warnings que o compilador lhe mostra.

+ +

Ciência da Computação, Não Superstição da Computação

+

Embora ninguém seja imune à programação cargo cult, nós devemos nos esforçar para superá-la. Há sabedoria na nossa área à nossa disposição, acumulada lentamente ao longo de mais de 7 década. Vamos usá-la. Vamos entender melhor nossas ferramentas e nossa profissão e escrever software de qualidade.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/cinco-niveis-codigo-legivel.html b/pt/cinco-niveis-codigo-legivel.html new file mode 100644 index 00000000..6c0ac562 --- /dev/null +++ b/pt/cinco-niveis-codigo-legivel.html @@ -0,0 +1,701 @@ + + + + + + + + Os Cinco Níveis de Código Legível | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Os Cinco Níveis de Código Legível

+ +
+ +
+

+ +

Foto por Greyson Joralemon no site Unsplash

+ +

Recentemente, tenho pensado bastante sobre a legibilidade do código. O que significa para um trecho de código ser legível? É possível definir a legibilidade de forma objetiva? Deveríamos tentar fazer isso?

+ +

Essas são algumas das perguntas sobre as quais tenho pensado e, nesta publicação, apresento minhas respostas na tentativa de iniciar uma conversa sobre legibilidade.

+ +

Aqui está a versão TL;DR: sim, acredito que definir objetivamente a legibilidade do código é possível e desejável e, neste artigo, sugiro um modelo para avaliar a legibilidade.

+ +

A Importância de Uma Definição de Legibilidade de Código

+ +

A legibilidade sempre vai ser um pouco subjetiva e, até certo ponto, essa subjetividade é inofensiva. Entretanto, ela pode causar problemas em alguns cenários.

+ +

Se estivermos trabalhando em uma equipe, é importante definir pelo menos algumas diretrizes objetivas em relação à legibilidade do código, e isso se deve às revisões de código (code reviews). Se o time não conseguir chegar a um consenso sobre o que é código legível, o feedback dos reviews fica parecendo arbitrário.

+ +

Em resumo: as equipes precisam de convenções. Uma equipe deve ter uma visão sobre o que constitui um código bom e legível.

+ +

Um Framework Para Pensar Sobre a Legibilidade Do Código: Níveis

+ +

Há pouco tempo, comecei a pensar na legibilidade do código em termos de níveis. Os níveis representam preocupações específicas com relação à legibilidade e são ordenados em termos de prioridade.

+ +

Ou seja, o nível 1 representa as coisas mais básicas que você precisa resolver primeiro, antes de avançar para os níveis mais altos. Arrume o básico e depois vá para o avançado. Tipo a hierarquia de necessidades de Maslow, mas para código.

+ +

Você vai ver alguns exemplos de código, em C#. Mas o que vou mostrar aqui se aplica a qualquer linguagem, a menos que eu diga explicitamente o contrário.

+ +

Sem mais delongas, aqui estão os cinco níveis de código legível.

+ +

Nível 1: Seu Código Faz O Mínimo Necessário

+ +

(Sim, nível um. Por favor, não me enche com isso de que “os programadores começam a contar no zero”).

+ +

O nível 1 de código legível refere-se ao código que faz o mínimo necessário. Pense em diretrizes simples de legibilidade, como:

+ + + +

Não é difícil aprender esses tipos de práticas recomendadas. Você pode aprender a maioria delas por meio da experiência, ouvindo o feedback de desenvolvedores mais experientes durante as revisões de código ou lendo livros e até mesmo publicações em blogs como os listados acima.

+ +

Nível 2: Seu Código é Idiomático

+ +

Considere a seguinte classe C#:

+ +
public class Person
+{
+    private string _name;
+    private int _age;
+
+    public Person(string name, int age)
+    {
+        _name = name;
+        _age = age;
+    }
+
+    public void SetName(string name)
+    {
+        _name = name;
+    }
+
+    public string GetName() => _name;
+
+    public void SetAge(int age)
+    {
+        _age = age;
+    }
+
+    public int GetAge => _age;
+}
+
+ +

Não há nada de errado com a classe acima, pelo menos não tecnicamente. O compilador a compila sem problemas e a classe funciona como deveria.

+ +

Entretanto, se você tem pelo menos alguma experiência com o C#, notou algo estranho quando viu o código: os métodos getter e setter. A equipe de desenvolvimento do C# transformou os conceitos de getters e setters em um “cidadão de primeira classe” da linguagem desde o início, por meio do conceito de propriedades. Se não houver lógica adicional envolvida na definição e obtenção de valores, o programador poderá usar propriedades autoimplementadas com um resultado conciso (nem mesmo os campos privados precisam mais ser declarados explicitamente):

+ +
public class Person
+{
+    public Person(string name, int age)
+    {
+        Name = nome;
+        Age = idade;
+    }
+
+    public string Name { get; set; }
+    public int Age { get; set; }
+}
+
+ +

Tudo isso quer dizer que, para ser legível, um determinado trecho de código precisa ser idiomático para a linguagem em que está sendo escrito. Se estiver escrevendo em C#, siga os padrões de codificação e as convenções da linguagem. O mesmo se aplica a Java, JavaScript e qualquer outra linguagem.

+ +

A comunidade Python tem um conceito maravilhoso para descrever o código Python que segue os padrões e as filosofias da linguagem: “pythônico”. Um trecho de código Python pode funcionar, mas se não for pythônico, os engenheiros experientes em Python acharão o código difícil de trabalhar.

+ +

Por que escrever um código idiomático é importante para a legibilidade? Quando você olha para um código - em qualquer linguagem - que não se parece com o que deveria ser, de acordo com o modelo mental que você tem dessa linguagem, fica mais difícil acompanhar o código.

+ +

O código não idiomático aumenta a complexidade cognitiva de uma base de código. Isso dificulta a integração de desenvolvedores que estejam familiarizados com os padrões e expressões idiomáticas da linguagem. Se você tiver um projeto open source, o excesso de idiossincrasias no código pode afastar possíveis colaboradores.

+ +

É claro que o oposto de tudo isso é verdadeiro.

+ +

Nível 3: Seu Código Revela a Intenção Por Meio Do Uso Tático Da Tipagem

+ +

Como o título sugere, este item, diferentemente dos dois anteriores, só se aplica a linguagens estaticamente tipadas - ou, talvez, dinamicamente tipadas que apresentem algum tipo de anotação de tipo opcional.

+ +

Vamos começar com um exemplo simples:

+ +
Canvas.DrawLine(5);
+
+ +

Não leve em consideração o número mágico, que por si só já é um problema. Considere que você sabe que o método DrawLine tem um único parâmetro, length. A linha poderia ter se tornado um pouco mais legível com o uso de um argumento nomeado,, mas mesmo isso não resolveria o maior problema: qual é a unidade de medida?

+ +

Além de prejudicar a legibilidade, esse problema abre a possibilidade de bugs, devido a uma incompatibilidade de unidades - uma parte do código “pensa” que a unidade é centímetros, enquanto outras podem acreditar que é polegadas.

+ +

O que estou defendendo em vez disso? Bem, use a tipagem a seu favor. Aqui, uma boa solução seria criar um value object chamado, digamos, Length. Esse tipo teria vários métodos factory com o nome de unidades de medida específicas, e seu construtor seria privado. Então, daria para mudar o exemplo anterior para isso:

+ +
Canvas.DrawLine(Length.FromCentimeters(5));
+
+ +

Outro exemplo seria o uso do tipo TimeSpan para expressar durações, em vez de usar valores primitivos ou usar a classe Uri em vez de apenas strings.

+ +

Talvez você esteja pensando que tudo isso é simplesmente uma forma complicada de dizer “evite a obsessão primitiva”. Também, mas tem mais coisas.

+ +

Para ilustrar meu ponto de vista, vou compartilhar outro exemplo - talvez um pouco forçado, admito. Digamos que você esteja resolvendo um problema que exija o uso de uma pilha. Nesse caso, nada o impede de usar a classe List<T> como uma pilha, certo?

+ +
    +
  • O método Add seria seu substituto para a funcionalidade push.
  • +
  • Para a funcionalidade pop, você usaria uma combinação de obter o último elemento da lista por meio de seu indexador e, em seguida, usar o método RemoveAt para excluir o item.
  • +
+ +

A solução acima, apesar de ser um pouco complicada, funcionaria. Mas eu o encorajaria fortemente a usar a classe Stack<T> normal. O uso do tipo mais específico tornaria o código imediatamente mais legível para qualquer pessoa que saiba o que é uma pilha. Isso faria com que o código revelasse sua intenção.

+ +

Resumindo: a menos que você tenha um motivo justificável para não fazer isso, sempre prefira o tipo que representa melhor o conceito ou a funcionalidade de que você precisa. Isso não apenas tornará seu código mais robusto, mas também revelará melhor sua intenção.

+ +

Nível 4: Seu Código Não Mistura Níveis de Abstração

+ +

Seu código não deve misturar mais de um nível de abstração. O código que está na parte de “Regras de negócios” da sua base de código não deve mexer com o código que está na parte de “Preocupações de IO”, para dar um exemplo.

+ +

Por que isso é um problema? Veja a função a seguir:

+ +
public static double CalculateAverageTemperature(string filePath)
+{
+    List<ClimaticReading> readings = new();
+
+    try
+    {
+        using var reader = new StreamReader(filePath);
+        while (!reader.EndOfStream)
+        {
+            var line = reader.ReadLine();
+            var values = line?.Split(',') ?? Array.Empty<string>();
+
+            if (values.Length < 2)
+                continue;
+            
+            if (DateTime.TryParse(values[0], out DateTime date) &&
+                double.TryParse(
+                    values[1],
+                    NumberStyles.Float,
+                    CultureInfo.InvariantCulture,
+                    out double temperature))
+            {
+                var reading = new ClimaticReading
+                {
+                    Date = data,
+                    Temperature = temperatura
+                };
+                readings.Add(reading);
+            }
+        }
+    }
+    catch (Exception ex)
+    {
+        throw new InvalidOperationException($"Erro ao ler o arquivo CSV: {ex.Message}");
+    }
+
+    if (readings.Count < 3)
+    {
+        throw new InvalidOperationException("Deve haver pelo menos 3 leituras para calcular a média.");
+    }
+
+    readings = readings.OrderBy(leitura => leitura.Temperatura).ToList();
+
+    readings.RemoveAt(0);
+    readings.RemoveAt(readings.Count - 1);
+
+    double sum = readings.Sum(reading => reading.Temperature);
+    double average = sum / readings.Count;
+
+    return average;
+}
+
+ +

A função lê e analisa um arquivo .CSV que contém leituras climáticas. As linhas que não têm os dois valores esperados (data e temperatura) são descartadas. Em seguida, ela classifica as leituras, remove os valores mais altos e mais baixos e, por fim, calcula e retorna a média dos valores restantes.

+ +

Essa função mistura pelo menos dois níveis de abstração:

+ +
    +
  • O nível de “lógica de domínio”, ou seja, a parte que faz o cálculo
  • +
  • O nível baixo: leitura e parsing do arquivo .CSV.
  • +
+ +

Você poderia até argumentar que há três níveis, já que o nível baixo pode ser dividido em dois: manipulação do sistema de arquivos e parsing de arquivos.

+ +

Essa função de exemplo não é a coisa mais difícil de ler no mundo, mas certamente é mais difícil do que deveria ser. Ela mistura lógica de domínio com IO. Ela mistura lógica de domínio com tratamento de erros de IO e até mesmo parsing. Uma solução melhor seria ter um método que obtivesse uma coleção de ClimaticReading e calculasse e retornasse a média.

+ +

Em outras palavras, uma solução melhor e mais elegante seria ter uma função pura. Esse novo método, além de ser mais legível, seria mais robusto, menos propenso a erros e também determinístico, ou seja, sempre retornaria os mesmos resultados para a mesma entrada, tornando-o intrinsecamente testável por testes de unidade.

+ +

Nível 5: Seu Código Fala a Linguagem Do Negócio

+ +

Você atingiu o nível 5 quando escreve um código que fala a linguagem do negócio. Quando você usa termos que são os mesmos que os especialistas no domínio usam.

+ +

Em outras palavras: sim, estou praticamente defendendo a mesma coisa que os programadores pragmáticos chamam de “programar mais próximo do domínio”, ou que Eric Evans chamou de linguagem ubíqua em seu clássico “Domain-Driven Design: Tackling Complexity in the Heart of Software”.

+ +

Se o seu código usa termos não ortodoxos em vez de termos do setor, isso dificulta a integração quando você traz novas pessoas que estão familiarizadas com o negócio, mas são novas na base de código. Se o código usar um jargão diferente do que os stakeholders usam, a comunicação se tornará mais cansativa, pois exigirá que você faça um mapeamento constante entre os conceitos apenas para conseguir acompanhar o que está acontecendo.

+ +

O nível 5 é, de certa forma, uma consequência lógica do nível 4. Se você separar cuidadosamente as preocupações da sua aplicação, certificando-se de que o código de alto nível não se misture com o código de baixo nível, a tendência é que o código de alto nível fique cada vez mais próximo do domínio em termos de nomenclatura.

+ +

Dê um “Level Up” Na Legibilidade Do Seu Código

+ +

A maioria dos programadores concorda que a legibilidade do código é vital. Mas e quanto a concordar com a aparência de um “código legível”? Aí é outra história.

+ +

Como eu disse anteriormente, acho que um nível de subjetividade quando se trata de legibilidade é inevitável e inofensivo. Entretanto, no contexto de um time, deve haver pelo menos algum consenso sobre o que é um código legível. Caso contrário, as revisões de código se tornam exercícios de futilidade e o moral da equipe despenca.

+ +

Acredito que nosso setor se beneficiaria de uma forma mais objetiva de pensar sobre a legibilidade. Nesta publicação, dei minha pequena contribuição, na forma de um checklist de legibilidade, em ordem de prioridade.

+ +

Mas, novamente: a ideia desta publicação não é dar uma resposta definitiva, mas iniciar uma conversa. Você acha que os modelos de “níveis” não fazem sentido? Ou talvez queira compartilhar seus próprios níveis? Convido-o a compartilhar sua opinião por meio de um comentário ou a me enviar um e-mail (meu endereço está na página sobre).

+ +

_Agradecimentos especiais a Mark Seemann, Pedro Barbosa e Peter Morlion por lerem e darem feedback em rascunhos deste post.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/como-aprender-ingles-parte-1.html b/pt/como-aprender-ingles-parte-1.html new file mode 100644 index 00000000..83b49b25 --- /dev/null +++ b/pt/como-aprender-ingles-parte-1.html @@ -0,0 +1,620 @@ + + + + + + + + Como aprender inglês: Um guia para desenvolvedores | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Como aprender inglês: Um guia para desenvolvedores

+ +
+ +
+

+ +

Parte 1: Não faça o que todo mundo faz. +

+ +

Esta é a primeira parte de uma série de dois posts. Veja a segunda parte.

+ +

Há quase dois anos, publiquei um post sobre um tema que costuma gerar discussões acaloradas na comunidade de desenvolvimento brasileira: usar português ou inglês para nomear classes, variáveis, e demais artefatos no código. Aliás, este artigo continua sendo o que eu mais gostei de escrever até hoje.

+ +

Minha opinião atual continua praticamente a mesma da época. Prefiro que você leia o post completo, mas aqui vai a versão resumida: tente usar inglês o máximo possível, porém vão existir situações nas quais o português faz mais sentido. Decida de acordo com as características do seu projeto e equipe.

+ +

Outra coisa que ainda não mudou é a minha opinião de que quem trabalha desenvolvendo software definitivamente deve aprender inglês. +Se você tem uma lista de coisas para estudar, remova Kotlin/programação funcional/framework javascript da moda do topo da lista e coloque inglês no lugar.

+ +

I mean it.

+ +

O que pretendo fazer agora é compartilhar minha experiência ao aprender inglês de maneira autodidata, dando dicas para que a sua jornada seja mais fácil e rápida que a minha.

+ +

Este será um guia em duas partes. Nesta primeira parte, vou falar sobre os principais motivos que, em minha visão, dificultam o aprendizado das pessoas.

+ +

Mas talvez você ainda precise de convencimento sobre a importância do inglês. Se este é seu caso, a próxima seção é para você.

+ +

Por que você deve aprender inglês (SPOILER: não é para “ganhar mais”)

+ +

Quando o assunto é o aprendizado de inglês, uma das razões mais citadas é o aumento de renda. Embora existam estudos que sugerem aumento de salário para quem domina o idioma, este não deveria ser o seu maior (ou único) motivador.

+ +

Outro argumento bastante usado é de que o inglês torna mais fácil conseguir um emprego. Intuitivamente, parece fazer sentido, embora eu desconheça algum estudo demonstrando isso (fique a vontade para postar um link nos comentários, caso conheça). Como evidência anedótica, acredito que todos nós conhecemos muitas pessoas que são profissionais competentes e não dominam o idioma. Quanto a isso, pode se tranquilizar: sabendo programar minimamente bem, você vai conseguir um emprego mesmo sem saber inglês (excluindo-se, obviamente, empresas no exterior ou cargos em empresas brasileiras que requerem comunicação com pessoas de fora). Poderíamos argumentar sobre a qualidade desses empregos, ou o salário que você poderá conseguir, mas não pretendo entrar neste mérito por enquanto.

+ +

Certo, mas… e aí? O que sobra? Colocando da maneira mais simples possível: você deve aprender inglês porque é útil.

+ +

O inglês como língua franca

+ +

O inglês é, para todos os efeitos, a língua franca da tecnologia. E isto facilita muitas coisas.

+ +

Um exemplo: eu gosto muito do blog do Mark Seeman e fico feliz por ele escrever em inglês, mesmo sendo da Dinamarca. Também aprendi bastante coisa com seu livro sobre injeção de dependência. Até onde eu sei, este livro nunca foi traduzido para português, apesar da primeira edição ter sido lançada em 2011 (a segunda edição está prevista para janeiro de 2018).

+ +

O criador do Ruby On Rails, David Heinemeier Hansson, também é dinamarquês, o que não o impede de postar em inglês com frequência.

+ +

Como estamos no assunto de aprender um idioma, você deve conhecer um aplicativo chamado Duolingo. Pois bem, o fundador e CEO do Duolingo (e também do reCaptcha) é o pesquisador Luís von Ahn, da Guatemala. Embora de vez em quando poste algo em espanhol, o inglês é usado na maioria das comunicações dele nas redes sociais.

+ +

Por último mas não menos importante, vou citar o brasileiro Zeno Rocha, referência no desenvolvimento front-end e que se comunica principalmente em inglês no seu site e diversas mídias sociais.

+ +

Vamos falar um pouco de Open Source agora. Recentemente eu comecei a contribuir com um projeto chamado Noda Time. Se você der uma olhada na área de discussão do projeto, verá que todas elas são em inglês, apesar de haver contribuidores de diversas países (Brasil, Estados Unidos, Inglaterra e Rússia, só para citar alguns).

+ +

Poderia ficar aqui o dia citando exemplos, mas você pegou a ideia. Seria impraticável todos aprenderem os idiomas de todos. Consolidar em apenas um idioma é a solução óbvia.

+ +

O inglês como facilitador do aprendizado

+ +

Acho que não é difícil convencer alguém de que, pelo menos na área de desenvolvimento de software, há muito mais material em inglês que em outros idiomas. Aliás, eu arriscaria que isto também é verdade para outras áreas.

+ +

Uma forma relativamente fácil de demonstrar isso é fazer uma busca no Google ou Youtube em português e depois em inglês, com os mesmos termos, e comparar o número de resultados retornados.

+ +

Outro site cuja diferença entre as versões em inglês e português é gritante é a famosa Wikipédia. Por exemplo, compare o artigo sobre o algoritmo de ordenação BubbleSort em português com a versão em inglês. Nem precisa falar muita coisa, certo?

+ +

É claro que estes são apenas exemplos bobos, usando uma “metodologia” que não tem nada de científica, mas eu acredito que é suficiente. Também não estou de forma alguma afirmando que não existe conteúdo de qualidade em português - eu sei que existe. Aliás, a própria existência deste blog é prova de que acredito na importância do conteúdo em português.

+ +

Mas é inegável que é mais fácil encontrar material em qualidade e quantidade em inglês. Não apenas na forma de tutoriais e blog posts, mas também em livros; assim como o já citado Dependency Injection in .Net, do Mark Seeman, existem muitos outros livros que nunca foram traduzidos para o nosso idioma. Alguns livros são traduzidos, eventualmente, mas a qualidade da tradução muitas vezes deixa a desejar.

+ +

E quem consegue entender o inglês falado? Esta pessoa já tem muito mais vantagens, pois pode assistir palestras no Youtube, cursos no Pluralsight e similares, ouvir a excelentes podcasts de tecnologia, e muito mais.

+ +

Por que as pessoas não aprendem inglês?

+

Não é raro vermos matérias retratando o péssimo desempenho do Brasil nos rankings de proficiência no inglês.

+ +

Ao mesmo tempo, redes de escolas de idiomas são negociadas por bilhões.

+ +

Embora muitas pessoas tentem aprender inglês, poucas conseguem. Por quê?

+ +

Há pessoas que têm a resposta na ponta da língua para isso:

+ +
    +
  • “Precisa começar a estudar na infância”.
  • +
  • “Precisa ter muito dinheiro”.
  • +
  • “Precisa morar fora/fazer intercâmbio”.
  • +
  • “Precisa ter uma inteligência muito acima da média”.
  • +
+ +

Eu acredito que estas pessoas estão erradas. Embora essas coisas ajudem, nenhuma delas é essencial.

+ +

Vou agora falar sobre o que eu considero os motivos principais que impedem as pessoas de aprender inglês.

+ +

Excesso de foco em gramática em detrimento de todo o resto

+

Durante a faculdade, havia um colega que sempre me pedia ajuda nas provas de inglês, apesar dele ter estudado SETE anos em uma escola de idiomas famosa. E eu sempre comentava: “Cara, mas não te ensinaram isso no curso?” E sua resposta, invariavelmente, era: “Ah, eles não passavam muito vocabulário, era mais gramática).

+ +

Agora pense. E se esse meu amigo fosse abordado por um americano na rua perguntando “Excuse me? How do I get to the nearest subway station?”? O que ele iria fazer? Abrir um livro de gramática? Recitar a lista de verbos regulares e irregulares?

+ +

Falta de prática

+

Qualquer pessoa que já estudou algum instrumento musical sabe que não basta frequentar as aulas; é preciso praticar em casa, de acordo com o plano de estudos recebido. Fazer exercícios, treinar escalas, praticar percepção musical, todos os dias.

+ +

Músico tocando violino

+ +

É claro que a necessidade de praticar não se aplica somente à música, mas também aos esportes, à programação e muitas outras áreas.

+ +

Agora, quando o assunto é inglês, algumas pessoas parecem pensar que elas vão aprender por osmose, por contágio, algo assim. Que basta ficar perto do(a) professor(a) por uma (ou na melhor das hipóteses, duas) horas e depois ir embora para casa e não ter nenhum contato com o idioma por uma semana e vão aprender assim mesmo.

+ +

Sorry to break it to you, mas não vão.

+ +

Não integrar o áudio ao aprendizado (ou integrá-lo tardiamente)

+

Este é um problema comum na área de TI. Inclusive, eu cometi este erro em uma etapa do meu aprendizado. Como precisamos constantemente ler textos técnicos em inglês, como manuais e documentações, muitos de nós conseguem ter um domínio razoável do inglês escrito ao longo dos anos.

+ +

O problema é quando chega a hora de falar, principalmente por conta da pronúncia do inglês, que é totalmente não intuitiva para nós falantes de português.

+ +

+ +

Na maioria das vezes, sem ter a referência da pronúncia correta, a pessoa acaba “aportuguesando” a pronúncia da palavra. Quantas pessoas você conhece que pronunciam 4Shared como “Quatro Xarédi”, ou algo do tipo?

+ +

Outro problema é que a pronúncia do inglês é bastante “imprevisível”. É perigoso você assumir que existem regrinhas infalíveis para a pronúncia e sair aplicando. Você pode até acertar algumas vezes, mas vai errar muitas outras. Veja as três palavras a seguir:

+ +
    +
  • Book
  • +
  • Door
  • +
  • Blood
  • +
+ +

Agora ouça a pronúncia de cada uma:

+ +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ +

É provável que você tenha se surpreendido com a pronúncia de pelo menos uma delas.

+ +

Vamos a mais um exemplo. Desta vez, uma palavra que você conhece e usa com frequência: Query. Você sabe a pronúncia desta palavra? Tem certeza? Se você acha que rima com very, então errou:

+ +
    +
  • + +
  • +
+ +

Resumidamente, pessoas que só tiveram contato com inglês escrito vão inevitavelmente internalizar pronúncias erradas devido à falta de exposição a áudios com as pronúncias corretas, o que acarretará em dificuldades na conversação.

+ +

O que fazer então?

+ +

Basicamente, o contrário do que foi listado acima. Colocando em uma frase, seria algo do tipo:

+ +
+

Estude/pratique consistentemente (de preferência todos os dias), utilizando uma estratégia de estudos que integre o uso de áudio desde o início, e não privilegia a gramática em detrimento de todas as outras áreas.

+
+ +

Sim, é um pouco abstrato, eu admito. Corrigiremos isso no próximo post, no qual eu vou contar a história do meu aprendizado no inglês, detalhando meus erros e acertos, para que sua jornada seja menos longa que a minha.

+ +

Thanks for reading! See you next time!

+ + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/como-aprender-ingles-parte-2.html b/pt/como-aprender-ingles-parte-2.html new file mode 100644 index 00000000..c7ec2c39 --- /dev/null +++ b/pt/como-aprender-ingles-parte-2.html @@ -0,0 +1,672 @@ + + + + + + + + Como aprender inglês: Um guia para desenvolvedores, Parte 2 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Como aprender inglês: Um guia para desenvolvedores, Parte 2

+ +
+ +
+

+ +

Parte 2: Pratique diariamente. Áudio em primeiro lugar. +

+ +

No post anterior eu expliquei quais são, na minha opinião, os principais erros que as pessoas cometem ao tentar aprender inglês.

+ +

Agora chegou a hora de fazer o oposto: vou detalhar o que você deve fazer para aprender inglês da forma correta, gastando pouco e se divertindo no processo.

+ +

Antes, um disclaimer

+ +

Apenas para deixar claro. Eu não sou de forma alguma uma autoridade em aprendizado de idiomas. Não sou formado em Linguística ou algo do tipo. Não tenho credenciais.

+ +

Também não estou fazendo promessas mágicas, do tipo “fique fluente em três meses”. Desconfie de qualquer um que venda esse tipo de coisa. Aprender inglês é mais fácil do que a maioria das pessoas pensam, mas ainda sim leva tempo e demanda esforço.

+ +

Este post e o anterior têm o objetivo de compartilhar a minha experiência no aprendizado do inglês, detalhando o que funcionou ou não +para mim. Também é minha intenção que você aprenda com meus erros, de modo que sua jornada não precise demorar tanto quanto a minha.

+ +

Se eu aprendi inglês, você também pode

+ +

Eu nunca fiz curso de inglês em escola particular. Com exceção de uma vez que fui à Wizard da minha cidade entregar currículo para o +cargo de professor de informática, eu nunca entrei em uma escola de inglês. Também estudei em escola pública a vida toda. Nunca fiz intercâmbio (aliás, nunca saí do país). Durante a maior parte da vida, não tive computador e internet em casa. Smartphone? Só aos 22 anos.

+ +

E eu tenho confiança para dizer que o meu inglês é melhor que várias pessoas que conheço que tiveram uma ou mais dessas oportunidades. +Sei que corro o risco de soar arrogante dizendo este tipo de coisa, mas garanto que esta não é a intenção. Muito pelo contrário, +estou tentando usar meu exemplo pessoal para tentar derrubar alguns mitos.

+ +

Não, não precisa sair do país para aprender inglês. Não, não precisa estudar em escola de inglês famosa. Não, não precisa ter muito +dinheiro.

+ +

Tudo isso é nice to have, não must have. Se você tiver oportunidade de fazer intercâmbio, então é claro que você deve ir. Se você teve a oportunidade de estudar inglês desde cedo, meus parabéns. Se você tem muito dinheiro…bora dividir um pouco? ;)

+ +

Apenas não use a falta de uma ou mais destas coisas como desculpa para não se dedicar.

+ +

Minha jornada com o inglês

+ +

Se eu tivesse que listar de forma resumida o meu trajeto no inglês, seria algo assim:

+ +
    +
  • Fase informal +
      +
    • Vários anos de contato contínuo, porém limitado, com o inglês escrito.
    • +
    • Exposição ao inglês falado por meio de filmes e músicas.
    • +
    +
  • +
  • Fase formal +
      +
    • Leitura de dicas de vocabulário e expressões
    • +
    • Prática consistente de listening
    • +
    • Conversação com professor nativo
    • +
    +
  • +
+ +

Vou agora expandir esses tópicos e contar em detalhes a história do meu aprendizado em inglês.

+ +

A “fase informal”

+

Eu sempre gostei e tive vontade de aprender inglês. Mas minha família não tinha condições de pagar um curso; eu também não tinha videogame, videocassete (sim, você não leu errado) ou outras amenidades que poderiam de alguma forma me dar mais exposição ao inglês.

+ +

Computador só em sonho. Naquela época (meados dos anos 90) o custo de um computador era proibitivo para a maior parcela da população (que era exatamente a minha parcela).

+ +

Para piorar, nesta época não havia aulas de inglês para ensino fundamental antes da quinta série, pelo menos no ensino público. +Atualmente parece que as crianças recebem aulas de inglês desde a pré-escola. Antes tarde que nunca, certo?

+ +

Sendo assim, minha exposição ao inglês era rara e em doses minúsculas. Por exemplo, eu lia tudo em inglês que encontrava em embalagens e manuais de instruções de aparelhos que meus pais compravam; eu lia as coisas em inglês nos próprios aparelhos; eu mudava o idioma do menu da TV para inglês (e espanhol também) só para ver como era.

+ +

A TV era outra fonte de pequenos momentos de contato com o inglês, através de filmes e desenhos. Sim, eu assistia tudo dublado, claro (TV a cabo? O que é isso?). Mas ainda sim oportunidades surgiam; o exemplo típico é quando aparecia algo escrito em inglês no filme/desenho (letreiro de loja, rótulo de algum produto, sinal de trânsito, título do episódio) e o locutor falava em português a tradução.

+ +

Vitrine de loja com o sinal dizendo "Sorry, we're closed"

+ +

Foi em 2001, mas eu me lembro bem como estava ansioso para o início da quinta série. Finalmente iria ter aulas de inglês!

+ +

Imagine o grau da minha decepção quando as aulas de fato começaram.

+ +

Não quero causar polêmica mas acredito que não é segredo nenhum que as aulas de inglês do ensino público…deixam a desejar.

+ +

Seria injusto (e mentiroso) dizer que eu não aprendi algo. Eu aprendi os dias da semana, os meses do ano, os números (até um certo ponto), o básico do verbo to be. Tudo isso, claro, com uma pronúncia que passava longe da correta, mas depois vou voltar a esse assunto.

+ +

Em algum momento eu comprei um minidicionário de inglês, que embora fosse bem limitado, tinha uma feature muito útil: na frente de cada entrada do dicionário, havia a pronúncia “aportuguesada” da palavra.

+ +

Algo assim:

+ +

Página do dicionário de inglês

+ +

Isso me ajudou a aprender a pronúncia aproximada de várias palavras, e ver que elas eram bem diferentes do que eu imaginava (e do que muitas pessoas pronunciavam).

+ +

Minha exposição ao inglês ia lentamente crescendo. Acho que foi mais ou menos nesta época que eu finalmente ganhei um video-game: o lendário Polystation!

+ +

Não era o que eu realmente queria, claro, mas ainda sim me proporcionou muitas horas de diversão e um pouco mais de aprendizado.

+ +

Foi por volta de 2004 que eu finalmente realizei outro sonho: comprei um aparelho de DVD. \o/

+ +

Eu privilegiava alugar filmes mais antigos, que eram mais baratos que os lançamentos. E ainda assim, eu alugava relativamente poucos filmes, às vezes só um. Então, eu queria aproveitar ao máximo: eu assistia dublado, depois novamente legendado, via todos os materiais extras disponíveis, como documentários, cenas excluídas, comentários de diretor, este tipo de coisa. Um ponto importante é que o material extra era apenas legendado, o que me forçava a assistir com legendas, mesmo não gostando muito na época.

+ +

Com cerca de 14, 15 anos, uma nova paixão surgiu na minha vida: a música (ou para ser específico, o rock). Mais aprendizado veio na forma de tradução das letras das músicas nos encartes dos CD’s.

+ +

Vários CD's e DVD's de Rock

+ +

No final de 2006 eu consegui meu primeiro estágio na área da informática. Depois de algum tempo (provavelmente no começo do ano seguinte) comprei meu primeiro computador: um Positivo, com configurações risíveis. Mas era um sonho que eu tive por boa parte da minha vida e finalmente havia conseguido realizá-lo.

+ +

Eu continuava não tendo acesso à internet, porém. Sinceramente não lembro bem a razão; deve ter sido uma mistura de custo proibitivo e falta de cobertura em nosso bairro, provavelmente. Mas eu tinha acesso à internet no próprio estágio, então eu aproveitava os momentos livres para ler, principalmente artigos na Wikipédia.

+ +

Lá para meados de 2007 finalmente consegui ter acesso à internet em minha casa, por meio de um provedor local, via rádio. Era uma conexão bem precária, com a velocidade apenas um pouco maior do que internet discada, mas já era alguma coisa.

+ +

Interessante salientar que nesta época minha leitura já era boa; eu conseguia entender com facilidade a maior parte dos textos que me propunha a ler. Todos os anos de exposição contínua ao inglês, ainda que limitada, estavam dando fruto.

+ +

A fase “formal”

+

Aprendendo a estudar inglês

+ +

Em 2010, eu iniciei o bacharelado em Ciência da Computação. Também comecei a fazer estágio em uma pequena firma de desenvolvimento de software da cidade.

+ +

Nesta época, eu já tinha criado vários hábitos para ampliar meu contato com o inglês. Por exemplo, eu só assistia filmes e séries com áudio E legenda em inglês. Passei a usar o inglês quando fazia anotações. Mudei o idioma do sistema operacional para inglês. E assim por diante.

+ +

No entanto, eu ainda não estava satisfeito. Foi quando resolvi realmente estudar inglês, com método, com um plano de estudos diário, coisa que eu não havia feito até então. E é esta a razão da divisão entre fase formal e fase informal no nome dos tópicos.

+ +

Até então, eu nunca tinha tentado falar inglês. Eu estava satisfeito em conseguir ler razoavelmente bem, mas a conversação, por algum motivo, não me interessava. Talvez eu achasse que estivesse além da minha capacidade ou algo assim. Sinceramente, não me lembro.

+ +

Foi nesta época que eu comecei a acompanhar sites de dicas de aprendizado de inglês (no fim deste post vou listar vários). Esses sites me apresentaram à noção de praticar o listening, ou seja, ouvir o áudio em inglês. Eu já era fã de podcasts, principalmente voltados a filmes, quadrinhos, games, esse tipo de coisa. Então, foi um passo natural passar a ouvir podcasts de aprendizado de inglês.

+ +

Podcasts!

+ +

O primeiro podcast que passei a consumir regularmente foi o ESL Podcast. Eu ouvia os episódios durante o horário do almoço, acompanhando a transcrição. O texto geralmente consistia de um diálogo entre dois personagens. Os leitores liam bem devagar e de maneira bem articulada, de modo que era fácil de entender o que eles estavam dizendo.

+ +

Não demorou muito tempo na verdade para que eu desse o próximo passo na minha evolução: passei a conseguir entender 100% do áudio sem as transcrições.

+ +

Eu diria que esse é um passo decisivo no progresso do seu aprendizado. Não depender de transcrições te dá uma liberdade sem precedentes para praticar o listening. Você pode ouvir:

+
    +
  • fazendo exercícios;
  • +
  • indo ou vindo do trabalho;
  • +
  • na fila ou sala de espera do banco/correio/dentista/etc;
  • +
  • lavando a louça, limpando a casa ou fazendo outro tipo de trabalho manual.
  • +
+ +

Em resumo, ouvir sem depender da transcrição deixa suas mãos livres, o que te permite integrar o inglês na sua rotina, ocupando intervalos de tempo que em outra situação seriam desperdiçados.

+ +

Toda essa prática surtiu efeito e a minha compreensão do inglês falado foi melhorando consideravelmente. Aos poucos, eu fui abandonando os podcasts de “aprendizado de inglês” e passei apenas a ouvir podcasts de assuntos variados (inclusive de programação).

+ +

Toda essa prática surtiu efeito e a minha compreensão do inglês falado aumentou consideravelmente. Só faltava uma coisa: como arrumar alguém para conversar?

+ +

Skype to the rescue

+ +

Por volta de 2014, se não me engano, eu vim a saber de um americano chamado Blake Wind que dava aulas de inglês por Skype, e cobrava mais barato que muitos outros professores da época.

+ +

Fiz diversas aulas com o Blake em 2014 e 2015, e depois de um tempo parei devido à alta do dólar. Desde então, faço aulas esporadicamente quando sinto que preciso de prática em algum ponto específico.

+ +

Roadmap

+ +

Se eu tivesse que aprender inglês novamente hoje - ou aprender outro idioma - como eu faria? É basicamente disso que esta seção se trata. Vou usar a minha experiência e os erros cometidos como base para criar um “roteiro” para você seguir.

+ +

Aprender o básico

+ +

Assim como uma casa precisa de um alicerce, você necessita de uma base de conhecimentos sobre a qual construir seu aprendizado. Como fazer isso?

+ +

Duolingo

+

Algo que não existia na minha época que teria ajudado muito é o Duolingo. Eu estou atualmente usando esse aplicativo para estudar Espanhol e Francês, e eu posso dizer que ele funciona caso seu objetivo seja avançar do zero até um conhecimento básico.

+ +

Você não vai sair falando inglês apenas com ele, mas você vai conseguir praticar as quatro habilidades. Você vai conseguir construir um vocabulário, aprendendo não apenas palavras soltas mas também frases comuns e expressões, e integrando o áudio e a pronúncia correta desde o início, o que é fundamental.

+ +

Estude com o Duolingo todo dia, até terminar o curso. Após isso, continue reforçando os pontos nos quais não estiver tão bem.

+ +

Curso Inglês Online

+

Depois do Duolingo, eu recomendo o curso básico do site Inglês Online, da Ana Luiza. O curso é pago, mas é um valor que considero acessível e vale muito a pena.

+ +

Prática diária do listening

+ +

O próximo passo é integrar o áudio no seu dia-a-dia. Como já disse anteriormente, a situação ideal é chegar ao ponto de não precisar mais de transcrições, pois assim você terá liberdade para ouvir inglês praticamente em qualquer situação que sobrar um tempo.

+ +

Chegar até esse ponto vai demandar um certo trabalho, no entanto. Para isso, eu sugiro a leitura da série de artigos “Como Falar Inglês - As Dicas Essenciais”, escrita pela Ana Luiza do site Inglês Online. É uma série um pouco extensa, mas que detalha passo a passo como evoluir no listening, inclusive com fontes de áudio adequados para cada nível do aprendizado.

+ +

Não esqueça das outras áreas

+ +

O listening deve ser o protagonista da sua estratégia de aprendizado. O que não significa que as outras habilidades devem ser negligenciadas.

+ +

Aqui vão algumas estratégias para deixá-las em dia:

+ +

Reading

+ +

Favoreça o inglês na leitura de qualquer material. Favoreça sempre a Wikipédia em inglês, assim como documentação de linguagens ou frameworks. Siga pessoas influentes da área no Twitter; leia seus blogs e quaisquer outras publicações. Além de praticar o seu inglês, você vai estar antenado(a) com o que acontece de importante na área.

+ +

Writing

+ +

Invente oportunidades para escrever em inglês. Crie um blog. Comece um diário. Encontre algum projeto Open Source que você ache interessante (de preferência, algo que você usa) e se envolva! Entre no chat do projeto no Gitter; procure as issues no GitHub e participe das discussões; puxe assunto no Twitter com alguma daquelas pessoas influentes que você seguiu no passo anterior. Talvez você se surpreenda com a frequência com que elas respondem!

+ +

#### Speaking +Fale sozinho. Sim, estou falando sério. Experimente gravar todo dia um vídeo (ou áudio) curto, de até um minuto, no qual você fala sobre seu dia (ou qualquer assunto).

+ +

Outra dica interessante é ler em voz alta. Encontre um texto, de preferência sobre um assunto que ache interessante, e leia em voz alta. Melhor ainda é gravar a sua leitura e depois pedir a opinião de uma pessoa que saiba inglês.

+ +

DICA IMPORTANTE: jamais tente adivinhar a pronúncia de uma palavra. Quando encontrar uma palavra que você jamais ouviu, ao invés de tentar pronunciá-la, ouça sua pronúncia correta antes. Uma ótima ferramenta para isso é o site Forvo.

+ +

Falar sozinho e ler em voz alta sejam técnicas úteis, mas têm uma limitação importante e óbvia: a falta de interação com outra pessoa. Para resolver isso, temos sites de language exchange, como o italki.

+ +

Finalmente, aulas com professores nativos sempre é uma opção, caso esteja dentro das suas possibilidades.

+ +

Aprender inglês é possível. O que você está esperando?

+ +

Espero ter conseguido, através da minha história, mostrar que aprender inglês é possível sim, ainda que haja dificuldades. O meu aprendizado foi longo e inconsistente, por não ter tido as facilidades que existem hoje em dia.

+ +

Para te ajudar ainda mais, eu criei uma página com recursos para estudar inglês online. Vou mantê-la atualizada constantemente.

+ +

Agradeço pelo seu tempo, e estou à disposição caso precise de mais alguma ajuda. A área de comentários está aí para isso.

+ +

See you later!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/como-escolher-bons-nomes/index.html b/pt/como-escolher-bons-nomes/index.html new file mode 100644 index 00000000..4f08fc1b --- /dev/null +++ b/pt/como-escolher-bons-nomes/index.html @@ -0,0 +1,595 @@ + + + + + + + + Dez dicas para lhe ajudar a escolher bons nomes | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Dez dicas para lhe ajudar a escolher bons nomes

+ +
+ +
+

+ +
+

Só existem duas coisas difíceis em Ciência da Computação: invalidação de cache e escolher nomes das coisas.

+ +

Phil Karlton

+
+ +

Você quer escrever um código muito bom? Código limpo, entendível, legível? Existem várias habilidades que você precisa adquirir. Mas eu diria que no topo da lista está “Escolher bons nomes”. +

+ +

Escolher ótimos nomes para suas classes, métodos, variáveis e demais coisas do tipo é essencial. Um nome bem escolhido muitas vezes é a diferença entre código bom e horrível.

+ +

Mas o que é exatamente um bom nome? Apesar de existirem algumas diretrizes bem aceitas, eu devo dizer que não existe exatamente um consenso. (E é assim com muitos tópicos em nossa área, eu diria).

+ +

Então, hoje eu vou falar sobre algumas convenções e princípios que eu uso quando estou codificando. É meio que uma mistura do que eu aprendi na faculdade, estudando por conta própria e trabalhando como um desenvolvedor profissional. Essas convenções e princípios têm sido úteis para mim, então eu espero que sejam úteis para você também.

+ +

Algumas das dicas que vou mostrar vêm do livro “Código Limpo”, escrito por Robert C. Martin (mais conhecido com Uncle Bob). É um dos meus livros de programação favoritos, e eu escreverei uma resenha dele em breve. Fique ligado!

+ +

0. Use nomes auto-explicativos

+ +

O quê sua variável/classe/sei-lá-o-quê faz? Como ela deve ser usada? Escolha um nome que responda a essas perguntas.

+ +

Algumas pessoas têm essa ideia esquisita de que nomes mais curtos são sempre melhores. Eu não entendo isso. Elas estão tentando economizar o teclado ou algo assim?

+ +

Digamos que ao ler um código você se depara com isso:

+ +
    int d; // dias para fim do prazo
+ +

Você poderia argumentar que o código está bom assim. O significado da variável está perfeitamento expresso no comentário. Ótimo, mas lembre-se que a variável vai provavelmente ser utilizada em outros pontos, longe da declaração e do comentário.

+ +

Então…não seria melhor se livrar do comentário e usar o texto do comentário como o nome da variável?

+ +
    int diasParaFimDoPrazo;
+ +

1. Use abreviações apenas quando elas são amplamente conhecidas

+ +

Seria loucura nomear uma variável “UniformeResourceLocatorServico” em vez de “UrlServico”. Qualquer desenvolvedor sabe o que uma url é. A mesma coisa com Ftp, UI, IO, e por aí vai. Ou seja, tudo bem usar abreviações nos seus nomes, mas só quando elas são bem conhecidas. Seria contra-produtivo não fazer assim.

+ +

A propósito. Quando eu digo “amplamente conhecidas”, não estou querendo dizer conhecidas no mundo todo, ou mesmo no país todo. É claro que você pode e deve usar abreviações que são comuns no domínio do seu negócio. Em geral é considerado uma boa prática codificar o mais próximo possível da linguagem do cliente. Então, se os outros desenvolvedores e as pessoas de negócio se sentem confortáveis usando as abreviações, não tem problema nenhum utilizá-las.

+ +

2. Escolha clareza ao invés de brevidade

+ +

Isso é parecido com o primeiro ponto. Todo o resto se mantendo igual, nomes mais curtos são melhores. Mas um dia você terá que escolher entre clareza e brevidade. Quando esse dia chegar, escolha a clareza. Seis meses depois, quando você tiver que revisitar aquele código, você vai agradecer a si mesmo.

+ +

3. Use convenções amplamente aceitas (na maior parte do tempo

+ +

Existem poucos pontos no livro “Código Limpo” com os quais eu não concordo. Um deles é a recomendação do Uncle Bob para não começar nomes de interfaces com uma letra “I” maiúscula. Ele argumenta que essa prática é um resquício da Notação Húngara e portanto deveria desaparecer. Mesmo eu entendendo a porque ele pensa dessa forma, vou continuar a nomear minhas interfaces com um “I” no começo.

+ +

Por que? A razão é muito simples: essa é uma convenção bem aceita e utilizada na comunidade .Net. Quando você vai contra uma convenção estabelecida, você corre o risco de alienar desenvolvedores que estão acostumados com essa convenção, como potenciais novos membros da equipe ou contribuidores de projetos open-source.

+ +

A minha opinião é que se deve abandonar uma convenção extremamente bem aceita apenas quando os benefícios de fazer isso são muito maiores que os custos. E eu não acredito que esse seja o caso aqui.

+ +

4. Não use notação húngara

+ +

Talvez você tenha ouvido falar de notação húngara, talvez não. Mas eu aposto que você já viu, ou talvez já tenha até mesmo usado, mesmo que o nome não seja familiar.

+ +

Então, o que é essa notação? Nossa amiga Wikipédia veio dar uma mãozinha aqui:

+ +
+

Notação húngara é uma convenção de nomeação de identificadores em programação de computadores, na qual o nome de uma variável ou função indica seu tipo ou uso pretendido.

+ +

Wikipedia: Hungarian Notation, em tradução livre

+
+ +

Em resumo, notação húngara é colocar o tipo da variável no seu nome. Se eu tenho uma variável do tipo int, que vou usar pra guardar a idade de um estudante, eu poderia nomeá-la iIdadeEstudante ou intIdadeEstudante. Do mesmo modo, uma variável string que armaze a descrição de um produto poderia ser chamada sDescricaoProduto, ou até mesmo strDescricaoProduto.

+ +

E por que isso é ruim? Aqui estão algumas razões:

+ +
    +
  • Primeiro, é inútil. Se a sua variável tem um nome auto-explicativo (veja item #0), ela já vai te dar uma boa noção do seu tipo. Se você acha uma variável chamada “nomeProduto”, você acharia que ela é um número de ponto flutuante? Além disso, a maioria das IDEs modernas conseguem te mostrar não apenas o tipo da variável, mas também se ela é uma variável local, membro de instância ou parâmetro de método, e até quantas vezes ele foi referenciada no código da aplicação.
  • +
  • Pode causar confusões. Pessoas cometem erros, e é perfeitamente possível mudar o tipo da variável e esquecer de mudar o nome. Então agora você tem uma variável que o nome começa com “int”, mas ela é na verdade um long.
  • +
  • Faz com que os nomes fiquem mais difíceis de pronunciar, e isso pode dificultar discussões sobre o código e a arquitetura da sua aplicação.
  • +
+ +

5. Respeite o estilo de codificação da linguagem, framework, ou projeto

+ +

Desenvolvedores C# tendem a utilizar CamelCase para nomear variáveis locais, membros de instância e parâmetros de métodos, como em nomeProduto. Já em Ruby o estilo recomendado é o snake_case. A mesma variável ficaria: nome_produto.

+ +

Frameworks, bibliotecas e projetos open-source podem ter suas próprias diretrizes e padrões também.

+ +

Seria bobagem lutar contra padrões estabelecidos, por causa do seu próprio gosto e preferência. Se você está desenvolvendo em Ruby, escreva da maneira que a comunidade Ruby espera. O mesmo vale pra Java, C#, PHP, qualquer linguagem/ecossistema.

+ +

É como diz o ditado: “Quando estiver em Roma, faça como os romanos”.

+ +

6. Nomes de métodos devem começar com um verbo

+ +

Essa dica é bem curta. Métodos são geralmente ações que um objeto pode realizar. Assim, seus nomes deveriam começar com um verbo que indica qual é essa ação, e.g. ImprimirRelatorio(), ExibirPoligono(IPoligono poligono).

+ +

7. Nomes de classes devem ser substantivos

+ +

Da mesma forma, nomes de classes deveriam ser substantivos, como Produto, Cliente, Estudante, e assim por diante. Tente evitar termos genéricos como Manager, porque eles não adicionam nenhum valor.

+ +

8. Nomes de propriedades devem ser substantivos, adjetivos ou frases adjetivas

+ +

Propriedades devem ser nomeadas com substantivos (Nome), frases adjetivas ou adjetivos (como no caso de propriedades do tipo Boolean, e.g. Finalizado ou EstaFinalizado).

+ +

Ainda com relação a propriedades booleanas, você pode usar os prefixos Is, Can ou Get, caso isso facilite o entendimento da propriedade.

+ +

Abrindo um parênteses. Aqui entramos mais uma vez naquela velha discussão sobre português x inglês. Muita gente vai dizer que misturar português e inglês como em IsValido é algo horrível e que jamais deveria ser feito. Outros vão argumentar que o uso de Is é um idioma facilmente reconhecível por qualquer programador e que tentar aportuguesá-lo como em EValido ou EhValido é bem pior. É uma discussão que dá pano pra manga. Clique aqui para saber minha opinião a respeito.

+ +

9. Use nomes pronunciáveis e passíveis de busca

+ +

Se esforce para escolher nomes que são pronunciáveis. Quando você escolhe um nome que é difícil ou impossível de ser pronunciado, você desencoraja a discussão sobre o código, o que nunca é uma boa coisa.

+ +

Do mesmo jeito, evite nomes com uma letra só. Entre outras razões, você vai sofrer bastante quando tiver que fazer uma busca por eles! Nomes de uma letra só são bons apenas para variáveis de controle em laços de repetição e em expressões lambda. E ainda assim, só quando o escopo é bem curto.

+ +

Conclusão

+ +

Escolher nomes não é uma tarefa fácil. Um nome precisa expressar propósito, intenção, significado. Ele não precisa ser necessariamente “esperto”, mas tem situações na qual um pouco de esperteza vai ser necessário.

+ +

Um nome deveria expressar claramente o propósito da entidade nomeada. Mas existem coisas que são muito complexas por sua própria natureza, o que torna difícil encontrar um nome que expressa seu propósito de forma simples e clara.

+ +

Às vezes, a dificuldade que você tem ao escolher um nome é sintomas de outro problema, tal como uma arquitetura ruim. Se você não consegue se decidir entre cinco possíveis nomes para uma classe, talvez ela esteja violando o Princípio da Responsabilidade Única (ela está tentando fazer mais de uma coisa).

+ +

Por outro lado, se você se sente inclinado a nomear uma dúzia de classes com o mesmo nome…talvez elas deveriam ser uma classe só.

+ +

No fim das contas, escolha de nomes tem a ver com comunicação. E eu acho que é por isso que é uma tarefa tão difícil. Convenhamos: nós, desenvolvedores de software, não somos famosos por nossas habilidades de comunicação.

+ +

Em “Código Limpo”, no final do capítulo sobre escolher bons nomes, Uncle Bob fala:

+ +
+

O mais difícil sobre escolher bons nomes é a necessidade de se possuir boas habilidades de descrição e um histórico cultural compartilhado. Essa é uma questão de aprender, e não técnica, gerencial ou empresarial. Como consequência, muitas pessoas nessa área não aprendem essa tarefa muito bem.

+
+ +

Não seja igual a maioria das pessoas na nossa área. Trabalhe dure para aprender a criar bons nomes. Você vai se agradecer no futuro.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/compartilhe-o-que-voce-aprende/index.html b/pt/compartilhe-o-que-voce-aprende/index.html new file mode 100644 index 00000000..285ee1d9 --- /dev/null +++ b/pt/compartilhe-o-que-voce-aprende/index.html @@ -0,0 +1,516 @@ + + + + + + + + Compartilhe o que você aprende | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Compartilhe o que você aprende

+ +
+ +
+

+ +

Compartilhe o que você sabe. Escreva um blog. Responda uma pergunta no Stack Overflow. Abra a fonte do seu código. Cria conteúdo! Na nossa área, esse conselho aparece com muita frequência, em diversas formas .

+ +

E com razão, eu diria. Quantas horas de trabalho você já poupou graças a um post em algum blog? Ou a uma resposta bem feita no Stack Overflow? +

+ +

Quantas vezes uma biblioteca/ferramenta/app open-source salvou você de ter que codificar aquela funcionalidade do zero? Se eu fosse adivinhar a resposta pra cada uma dessas perguntas, provavelmente diria: muitas.

+ +

O desenvolvedor Rafael Rosa Fu falou um pouco sobre alguns dos benefícios da criação de conteúdo em um post no site do Fabio Akita:

+ +
+
    +
  • Aprendizado. praticar novas habilidades é importante para fixá-las, ao escrever sobre o que aprendemos estamos reforçando e expandindo nosso conhecimento ao sermos “forçados” a explicá-lo de forma que possa ser consumido por outras pessoas.
  • +
  • Memória - não sei você, mas minha memória é igual a de um peixinho dourado, e tenho certeza que não sou exceção. Escreva sobre aquele conceito complicado ou deixe a receita para o procedimento esporádico e quando precisar se lembrar dele abra seu blog ou procure no Google e vai encontrar suas próprias palavras para lembrá-lo.
  • +
  • Portfólio - especialmente útil para quem está começando na carreira, blog posts são úteis como parte de um portfólio de conhecimento que pode ser encontrado por um possível empregador ou usado como referência durante uma entrevista, agindo como um complemento ao tempo de carreira, além de ser um bom gancho para conversas durante entevistas. […]
  • +
+
+ +

Jeff Atwood (co-foundador do Stack Overflow e do Discourse) diss que iniciar seu blog “foi a coisa mais importante que já fiz em toda a minha carreira”. Então, parece razoável dizer que se nós encorajarmos mais e mais pessoas a compartilhar seus conhecimentos e experiências, toda a comunidade ganha, certo?

+ +

Nesse artigo publicado em 2012 pela Smashing Magazine, Louis Lazaris dá conselhos sobre como começar a publicar: publique as coisas que você aprende, não tenha medo de cometer erros, esteja aberto à colaboração de seus leitores.

+ +

Parece fácil, não é?

+ +

Quando a dúvida chega

+ +

Eu tive bastante receio antes de começar esse blog. Eu quero dizer, como poderia ser de outra forma? Todos esses blogueiros bem estabelecidos, eles têm anos ou mesmo décadas de experiência. Eles palestram em vários países. Eles lançam livros, têm podcasts, eles criaram empresas bem-sucedidas ou talvez até alguma tecnologia usada por milhões de pessoas. Resumindo, eles têm uma página “Sobre Mim” bem impressionante. Caramba, alguns deles já têm até mesmo artigo na wikipédia sobre eles. Esses são os rockstars.

+ +

E eu? Eu sou só um cara, dois anos depois de terminar a faculdade, tentando aprender e desenvolver minha carreia. Será que eu realmente tenho alguma coisa de valor para oferecer? Será que vou ser capaz de ajudar alguém? Ou vou ser só mais um, aumentando ainda mais o ruído da internet?

+ +

Eu penso que todas essas são questões relevantes. A web é um lugar ridiculamente enorme. Você poderia compartilhar conteúdo por anos, talvez sua vida toda, sem ser notado, sem receber nenhum feedback.

+ +

De vez em quando eu faço uma pesquisa no Google sobre algum assunto e acabo caindo em um blog com um design bacana e posts muito bem escritos. Eu começo a olhar os posts, e noto que a maioria deles (às vezes, todos eles) não tem nenhum comentário. Às vezes, também reparo que o último post foi escrito há dois ou três anos. Eles desistiram.

+ +

E apesar disso ser triste e desencorajador, não deixa de ser apenas um fato da vida. Talvez seu blog vai atingir uma grande audiência, talvez não.

+ +

Por que eu criei esse blog, afinal de contas?

+ +

Talvez a seção anterior tenha lhe dado a impressão de que eu sou cético com relação aos benefícios da criação de conteúdo. E talvez eu realmente seja, um pouco. Mas eu não vou deixar que isso me impeça. Eu acredito na importância de contribuir com a comunidade.

+ +

Se lembra daquela resposta no Stack Overflow que salvou seu emprego? Então, adivinha: alguém “perdeu” o tempo para escrever aquela resposta, de graça, e para postá-la na internet, de graça, pra que toda a internet veja, pra sempre. Isso não é incrível? Eu penso que parte da beleza da nossa profissão é o fato de que há tantas pessoas dispostas a compartilhar conhecimento de graça. A sacrificar seu tempo livre para conseguir construir alguma coisa. Milagres como GitHub, Stack Overflow, Wikipédia, só se tornam possíveis graças a essas pessoas. E eu quero ser parte disso.

+ +

Claro, você poderia argumentar que essas pessoas fazem esse tipo de coisa movidas pelos seus próprios motivos egoistas. É, talvez sim, mas o ponto é: no fim das contas, isso não importa nem um pouco. +Resultados importam. Se a usuária MariaDaSilva escreveu aquela resposta no Stack Overflow só pra ganhar alguns pontinhos de reputação, por mim está ótimo. Eu quero apenas a resolução do meu problema.

+ +

Então é isso. Para usar uma metáfora do mundo dos torrents, eu cansei de ser apenas um parasita. É hora de semear também.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/configuracao-dotnet.html b/pt/configuracao-dotnet.html new file mode 100644 index 00000000..4aa2bc4c --- /dev/null +++ b/pt/configuracao-dotnet.html @@ -0,0 +1,1354 @@ + + + + + + + + [Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

[Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET

+ +
+ +
+

+ +
+
+ ℹ️ + NOTA +
+
+ +

Este post é uma tradução, cuja publicação foi autorizada pelo autor. Caso tenha interesse, leia o artigo original, em inglês..

+ +

Eu decidi não traduzir as imagens, pois achei que seria muito trabalhoso. Portanto, as figuras que você verá são as mesmas do artigo original, com as informações nelas em inglês.

+ +

Em respeito ao autor, procurei deixar o artigo o mais próximo possível do original: mantive call to actions que o autor faz para suas palestras e conteúdos, e também mantive um pedido de contribução financeira ao final do artigo.

+ +

A partir do índice, inicia-se o artigo de autoria de Sander ten Brinke. Após a conclusão do artigo, eu volto com algumas palavras antes de finalizar. Boa leitura!

+ + +
+
+ +

Índice

+ + + +
+
+ ℹ️ + Info +
+
+ +

Este post é um complemento da minha palestra Keep it secret, keep it safe with .NET! Se você não puder assistir a uma sessão dessa palestra, poderá ler este post em vez disso! Dessa forma, o maior número possível de pessoas poderá aprender sobre o sistema de configuração do .NET e como manter os segredos em segurança!

+ +

Minha palestra oferece algumas informações mais detalhadas, portanto, se quiser saber mais, dê uma olhada na minha página Speaking para ver quando e onde darei essa palestra novamente! Você também pode entrar em contato se quiser que eu dê essa palestra em seu evento!

+ +
+
+ +

Introdução

+ +

Se você já escreve código há algum tempo, provavelmente já usou configuração de alguma forma. Pense em feature flags, configurações de log, configurações de autenticação etc. Talvez você tenha usado um arquivo de configuração com algumas configurações para o seu aplicativo ou talvez tenha usado variáveis de ambiente. Talvez você tenha usado ambos!

+ +

Também é provável que você tenha interagido com segredos, que também considero parte de um sistema de configuração. Pense em strings de conexão e chaves de API. Elas devem ser sempre seguras!

+ +

A configuração no .NET mudou radicalmente desde a introdução do .NET Core. Já se foi o tempo em que se usavam vários arquivos Web.config e agora temos um sistema muito mais flexível. No entanto, um sistema flexível também pode ser um sistema complexo. É por isso que eu quis criar uma palestra e uma publicação no blog em que você aprenderá como funciona o sistema de configuração do .NET e como usá-lo de forma otimizada. Você também aprenderá a manter seus segredos seguros, tanto localmente quanto em produção, usando o poder da nuvem do Azure!

+ +
+
+ ℹ️ + Info +
+
+ +

Este post contém tudo que você precisa saber sobre configuração e gerenciamento de segredos no .NET. Ela não aborda todos os detalhes, mas abrange tudo o que acredito que um desenvolvedor .NET tem que saber. Considere-o um guia de bolso útil que você pode usar ou enviar a outras pessoas quando elas tiverem dúvidas sobre configuração e gerenciamento de segredos no .NET.

+ +

Acho que esta post é muito útil porque são necessárias múltiplas horas para encontrar e ler completamente a documentação da Microsoft sobre esses tópicos. Se quiser saber mais, você encontrará links para a documentação oficial no final do post.

+ +
+
+ +

Vamos começar!

+ +

Configuração no .NET

+ +

O sistema de configuração do .NET é muito flexível! Você pode usar vários provedores de configuração, sendo que cada um deles pode ter um formato de configuração diferente:

+ +

Uma imagem que mostra uma visão geral do sistema de configuração do .NET com a interface IConfiguration e vários provedores

+ +

Uma visão geral do sistema de configuração do .NET.
+Extraído da documentação oficial

+ +

Outras fontes podem ser arquivos como .xml, .ini e muito mais. Você pode até mesmo conectar seu sistema de configuração à nuvem, o que faremos mais adiante!

+ +

O Básico

+ +

Como você pode ver, toda a sua configuração pode ser acessada usando a interface IConfiguration. Com isso, você pode recuperar seus valores de uma maneira fortemente tipada. Um exemplo:

+ +
public IConfiguration Configuration { get; set; }
+
+public string GetApiKey()
+{
+    // GetValue<> permite que você passe o tipo de retorno
+    string method1 = Configuration.GetValue<string>(ApiKey); 
+
+    // A variante do indexador sempre retorna uma string
+    string method2 = Configuration[ApiKey]; 
+
+    return method1;
+}
+ +

Você perceberá que não estamos especificando qual provedor deve ser usado para recuperar a ApiKey. Isso ocorre porque isso não deveria importar; a IConfiguration esconde toda essa complexidade de nós e, portanto, cria flexibilidade. O sistema de configuração decide qual provedor usar com base na ordem dos provedores. Falaremos mais sobre isso mais tarde!

+ +

Acesso a dados estruturados

+ +

Um recurso muito avançado do sistema de configuração do .NET é o fato de ele oferecer suporte a dados estruturados. Isso é muito útil porque permite que você agrupe valores de configuração relacionados. Todos os provedores oferecem suporte a dados estruturados, mas se você já trabalhou com um projeto ASP.NET Core, provavelmente reconhecerá o mais comum, que é appsettings.json. O JSON a seguir é um exemplo de um arquivo desse tipo:

+ +
{
+  “Logging": {
+    “LogLevel": {
+      “Default” (Padrão): “Informações”,
+      “Microsoft.AspNetCore": “Warning”
+    }
+  },
+  “AllowedHosts": “*”,
+
+  “ConnectionStrings": {
+    “Banco de dados": “CONNECTIONSTRING_HERE”
+  },
+
+  “Features” (Recursos): {
+    “EnableNewUI": false
+  }
+}
+
+ +

Você pode imaginar o objeto raiz e as seções Logging, ConnectionStrings e Features como “dados estruturados”.

+ +

Para interagir com essas seções no .NET, você pode usar o código a seguir.

+ +
+
+ ⚠️ + Aviso +
+
+ +

O código a seguir não é a melhor maneira de interagir com dados estruturados! Falaremos sobre maneiras melhores (usando o padrão Options) mais adiante.

+ +
+
+ +
public IConfiguration Configuration { get; set; }
+
+// ...
+
+public IConfigurationSection GetFeaturesSection()
+{
+    // GetSection retorna nulo quando a seção não pode ser encontrada
+    var method1 = Configuration.GetSection(Features);
+
+    // GetRequiredSection dispara uma exceção quando a seção não pode ser encontrada.
+    // SEMPRE prefira esse método ao GetSection para evitar bugs desagradáveis!
+    var method2 = Configuration.GetRequiredSection(Features);
+
+    return method2;
+}
+
+public bool GetEnableNewUI()
+{
+    return Configuration.GetValue<bool>(Features:EnableNewUI);
+}
+ +

A IConfigurationSection fornece a mesma API que a IConfiguration, portanto, você pode chamar featuresSection.GetValue<bool>(“EnableNewUI”) para obter o valor dessa seção. Também é possível acessar diretamente um valor de configuração que existe dentro de uma seção usando um :, que pode ser visto em uso no método GetEnableNewUI.

+ +
+
+ ℹ️ + Info +
+
+ +

Os dados estruturados não se limitam aos arquivos JSON. Todos os provedores são compatíveis com eles, embora a sintaxe para especificar uma seção possa ser diferente. Por exemplo, para fornecer um valor para EnableNewUI usando uma variável de ambiente, você terá que criar uma chamada Features__EnableNewUI.

+ +
+
+ +

Como tudo isso funciona?

+ +

Estamos usando IConfiguration em alguns exemplos. Você deve estar se perguntando como tudo isso funciona nos bastidores; como criar uma instância de IConfiguration e como configurá-la? Vamos dar uma olhada!

+ +

Para criar uma instância de IConfiguration, você precisará usar a classe ConfigurationBuilder (ou outra classe que implemente IConfigurationBuilder). Essa classe usa o padrão Builder para que você possa adicionar vários provedores. No final, você chama Build() e acaba com um IConfigurationRoot. É a mesma coisa que IConfiguration, mas também tem uma lista de todos os provedores que você adicionou. Você nunca deve usar o IConfigurationRoot diretamente, pois não deve acessar os provedores por baixo do pano. Um exemplo:

+ +
var builder = new ConfigurationBuilder();
+
+builder.AddJsonFile(sharedsettings.json);
+builder.AddJsonFile(appsettings.json);
+builder.AddEnvironmentVariables();
+// E assim por diante...
+
+IConfigurationRoot configuration = builder.Build();
+ +

A ordem desses provedores é muito importante porque se trata de um sistema em camadas. Dê uma olhada na imagem a seguir:

+ +

Uma imagem que mostra a importância da ordem dos provedores de configuração

+ +

Uma visão geral da importância da ordem dos provedores de configuração.
+ASP.NET Core in Action, Second Edition (Permissão concedida pelo autor Andrew Lock)

+ +

Imagine que sharedsettings.json tenha um valor para todos os valores de configuração usados pelo aplicativo. O appsettings.json e as Variáveis de ambiente contêm um subconjunto desses valores. Como o provedor para as variáveis de ambiente foi adicionado por último, ele tem a prioridade mais alta. Portanto, se você quiser recuperar um valor de configuração chamado ApiKey, o sistema examinará primeiro as variáveis de ambiente. Se ele existir, será retornado, mesmo que outros provedores também contenham um valor para ApiKey. No entanto, se as variáveis de ambiente não contiverem um valor para ApiKey, ele passará para o provedor que foi adicionado antes dele e pesquisará lá, e assim por diante.

+ +

Os valores default

+ +

Talvez você esteja um pouco confuso neste ponto. Eu certamente estava quando aprendi sobre o IConfigurationBuilder e a importância dessas camadas. Por quê? Bem, percebi que estava usando o IConfiguration em muitos projetos, mas nunca tinha ouvido falar do IConfigurationBuilder antes. Então, como eu poderia estar usando o IConfiguration?

+ +

Isso funciona porque, se você trabalhar em um aplicativo .NET que usa um Host, ele definirá todo um sistema de configuração para você por padrão! Por exemplo, projetos ASP.NET Core e workers services usam um Host, portanto, na maioria dos projetos, isso será feito para você! Agora vamos dar uma olhada em como isso funciona.

+ +

Em um aplicativo ASP.NET Core padrão, o seguinte é configurado para você.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProvedorExemploNotas
appsettings.json{ “Key”: “default value” } 
appsettings.{ENVIRONMENT}.json{ “Key”: “development value” } 
user secrets (desenvolvimento)dotnet user-secrets set “key” “development value”Também pode ser definido em IDEs. Mais sobre isso posteriormente.
Variáveis de ambientePowershell: setx key “valor do ambiente”
Bash: export key=‘valor do ambiente’
Também pode ser definido em IDEs. Muito popular em implantações do Docker/Kubernetes.
Argumentos da linha de comandodotnet run –key “important value”Também pode ser definido nos IDEs.
+ +

O item no topo tem a prioridade mais baixa. Portanto, se você chamar Configuration[“key”], obterá como resultado important value, mesmo que o User Secrets também forneça um valor.

+ +
+
+ ℹ️ + Info +
+
+ +

O provedor User secrets só é adicionado quando o Environment é definido como Development. Os ambientes serão tratados a seguir. Os user secrets são tratados em profundidade mais adiante.

+ +
+
+ +

O Visual Studio (e outros IDEs, como o JetBrains Rider) oferecem suporte à configuração de variáveis de ambiente/argumentos de linha de comando em seu IDE quando você acessa as propriedades do projeto. No entanto, aconselho contra o uso disso durante o desenvolvimento. Eu nunca uso variáveis de ambiente ou argumentos de linha de comando durante o desenvolvimento porque é mais difícil editá-los do que simplesmente abrir um arquivo. Armazená-los em appsettings.Development.json (que será abordado a seguir) é mais conveniente para você e seus colegas.

+ +

Configuração e Ambientes

+ +

O provedor appsettings.{ENVIRONMENT}.json é um pouco diferente dos outros provedores. Isso ocorre porque ele depende do ambiente do aplicativo. O ambiente atual do aplicativo é lido a partir do valor da variável de ambiente DOTNET_ENVIRONMENT ou ASPNETCORE_ENVIRONMENT. Se o seu projeto não for um projeto ASP.NET Core, o aplicativo verificará apenas DOTNET_ENVIRONMENT. Os projetos ASP.NET Core retornam para DOTNET_ENVIRONMENT quando ASPNETCORE_ENVIRONMENT não existe.

+ +

O ambiente será considerado como Production quando essas variáveis de ambiente não existirem.

+ +

Quando você cria um projeto ASP.NET Core, um arquivo chamado launchSettings.json será criado na pasta Properties. Aqui, você pode ver que a variável de ambiente ASPNETCORE_ENVIRONMENT está definida como Development:

+ +
{
+  // Muitos outros detalhes foram removidos desse arquivo para fins de brevidade
+  “$schema": “https://json.schemastore.org/launchsettings.json”,
+  “profiles": {
+    “MY_PROJECT": {
+      “commandName": “MY_PROJECT”,
+      “applicationUrl": “https://localhost:7237;http://localhost:5292”,
+      “environmentVariables": {
+        “ASPNETCORE_ENVIRONMENT": “Development”
+      }
+    }
+  }
+}
+
+
+ +

O resultado do sistema de configuração trabalhando em conjunto com o ambiente do aplicativo resulta em um recurso muito poderoso, pois permite que você crie arquivos de configuração diferentes para cada ambiente.

+ +

Você pode armazenar valores padrão em appsettings.json e substituí-los em appsettings.Development.json, appsettings.Test.json, appsettings.Staging.json e appsettings.Production.json.

+ +

Por exemplo, digamos que você tenha terminado o novo design de uma página de checkout de uma loja virtual. Ele ainda precisa ser testado e revisado por outras pessoas em um ambiente de teste, mas ainda não deve entrar em produção. Esse parece ser um caso de uso perfeito para feature flags! Você poderia criar um feature flag chamado EnableNewCheckoutUI e defini-lo como false em appsettings.json como o valor padrão. Em seguida, você pode substituir esses valores em appsettings.Development.json e appsettings.Test.json para que eles sejam ativados somente lá:

+ +
// appsettings.json
+{
+  “FeatureFlags": {
+    “EnableNewCheckoutUI": false
+  }
+}
+
+// appsettings.Development.json e appsettings.Test.json
+{
+  “FeatureFlags": {
+    “EnableNewCheckoutUI": true
+  }
+}
+
+
+ +

Você não está limitado aos nomes de ambiente mencionados acima; eles são apenas os padrões que o .NET usa. Se quiser usar um nome diferente, configure a variável de ambiente ASPNETCORE_ENVIRONMENT com o nome de sua escolha e crie um arquivo appsettings.ENV_NAME.json correspondente. A única outra coisa que você precisa fazer é garantir que o ambiente em que você executa seu aplicativo tenha ASPNETCORE_ENVIRONMENT ou DOTNET_ENVIRONMENT definido com o valor correto.

+ +

Tratando a Configuração Como Código

+ +

Anteriormente, elogiei o sistema de configuração do .NET e o IConfiguration por serem flexíveis e ricos em recursos. Falei sobre seu suporte a dados estruturados e sobre a recuperação de valores de uma hierarquia de configuração mais profunda. Mas você sabia que pode fazer muito mais com dados estruturados?

+ +

Digamos que nosso aplicativo se comunique com uma API externa usando HTTP. Para isso, precisamos de um ApiUrl, ApiKey e talvez queiramos configurar um TimeoutInMilliseconds. Do ponto de vista do código, talvez queiramos armazenar esses valores em uma classe (ou record) porque eles pertencem um ao outro:

+ +
public class ExternalApiSettings
+{
+    public string ApiUrl { get; set; }
+    public string ApiKey { get; set; }
+    public int TimeoutInMilliseconds { get; set; }
+}
+ +

Em seguida, teríamos uma classe ExternalApiClient que usa a configuração e a classe que acabamos de criar:

+ +
public class ExternalApiClient
+{
+    private readonly IConfiguration _configuration;
+
+    public Foo(IConfiguration configuration)
+    {
+        _configuration = configuration;
+    }
+
+    public void CallExternalApi()
+    {
+        IConfigurationSection externalApiSettingsSection = _configuration.GetRequiredSection(ExternalApiSettings);
+        
+        // Método 1 (Get<TType>() obtém os valores dessa seção e os mapeia em uma nova instância da classe fornecida)
+        ExternalApiSettings settings1 = externalApiSettingsSection.Get<ExternalApiSettings>(); 
+
+        // Método 2 (Bind() espera uma instância existente de um tipo e mapeará os valores para essa instância existente)
+        ExternalApiSettings settings2 = new();
+        _configuration.GetRequiredSection(ExternalApiSettings).Bind(settings2);
+
+        // Faça algo com essas configurações aqui...
+    }
+}
+ +

Isso parece bem legal, certo? Em vez de realizar 3 chamadas para obter cada propriedade de configuração relacionada à API individualmente, podemos mapeá-las em um objeto fortemente tipado. Agora podemos tratar nossa configuração como código! Poderíamos até criar métodos em nossa classe ExternalApiSettings para torná-la ainda mais poderosa!

+ +

No entanto, há algumas desvantagens importantes nessa abordagem.

+ +

Desvantagens

+ +
    +
  • A primeira desvantagem é que o nosso ExternalApiClient requer uma instância de IConfiguration para funcionar. Essa é uma dependência muito grande e um grande desperdício, considerando que ele usa apenas 3 valores de configuração! Além disso, essa classe agora pode acessar outros valores de configuração, como uma string de conexão a um banco de dados, configurações de registro, feature flags etc., mesmo que não precise dessas informações.
  • +
  • A segunda desvantagem é que essa classe está violando o princípio da responsabilidade única. Ela não é responsável apenas por chamar a API externa, mas também por interagir com o sistema de configuração para poder chamar essa API externa.
  • +
  • Como essa classe interage diretamente com o sistema de configuração, ela depende de sua estrutura e, portanto, está fortemente acoplada. Qualquer alteração na seção de configuração ExternalApiSettings (como o nome ou os nomes de seus filhos) causaria problemas em tempo de execução.
  • +
+ +

Então, o que podemos fazer em relação a isso? Reescrevê-la em Rust 🦀? Não, podemos usar o options pattern!

+ +

Options Pattern

+ +

O options pattern (“padrão de opções”) permite que você faça um uso ainda melhor do sistema de configuração do .NET 🚀! Ele permite a você desacoplar seu aplicativo do sistema de configuração e adiciona muitos recursos poderosos a esse sistema, como:

+ +
    +
  • Injeção de dependência
  • +
  • Validação
  • +
  • Diferentes tempos de vida de configuração
  • +
  • E muito mais!
  • +
+ +

Para começar a usar o options pattern de forma eficaz, é necessário criar classes/records das suas seções de configuração. Já fizemos isso no exemplo anterior, portanto, vamos continuar com ele:

+ +
public class ExternalApiSettings
+{
+    public string ApiUrl { get; set; }
+    public string ApiKey { get; set; }
+    public int TimeoutInMilliseconds { get; set; }
+}
+ +

Injeção de dependência

+ +

O options pattern funciona muito bem com a injeção de dependência! Para isso, basta registrar sua classe/record de opções na coleção de serviços. Dependendo do seu projeto, o ponto de entrada para isso pode ser o método Startup.cs -> ConfigureServices(IServiceCollection services) ou em algum lugar em seu Program.cs.

+ +
services.Configure<ExternalApiSettings>(configuration); // Passe em uma instância existente de IConfiguration
+ +

Isso adicionará uma instância de IOptions<ExternalApiSettings> ao seu contêiner de injeção de dependência. Para ver os benefícios dessa abordagem, vamos dar uma olhada em como poderíamos melhorar nosso ExternalApiClient de antes:

+ +
public class ExternalApiClient
+{
+    private readonly ExternalApiSettings _externalApiSettings;
+
+    public ExternalApiClient(IOptions<ExternalApiSettings> options)
+    {
+        // Importante: o padrão Options é “preguiçoso”. Isso significa que as opções são mapeadas somente quando você as solicita chamando .Value!
+        // Isso é feito apenas uma vez, portanto, você não precisa se preocupar com o desempenho.
+        _externalApiSettings = options.Value;
+    }
+
+    public void CallExternalApi()
+    {
+        // Faz algo com essas configurações aqui...
+    }
+}
+ +

Isso eliminou todas as desvantagens de antes! Nosso ExternalApiClient não tem mais uma dependência do IConfiguration e não está mais acoplado ao sistema de configuração. Ele também não precisa mais se preocupar com a estrutura do sistema de configuração.

+ +

Você pode argumentar que temos uma dependência indireta do sistema de configuração por causa da chamada .Configure<>(configuration) de antes, mas você não é obrigado a usar esse método para configurar suas opções. Você pode criar uma instância de IOptions<T> usando Microsoft.Extensions.Options.Options.Create() se precisar criar uma instância manualmente, e pode passar quaisquer dados que desejar. Você pode até mesmo criar opções com base em outras dependências usando o método Configure<TDep1,...>() do OptionsBuilder, que será discutido a seguir.

+ +
+
+ ℹ️ + Info +
+
+ +

Talvez você se pergunte por que precisamos envolver nossa classe de configurações com uma interface IOptions<>. Isso ocorre porque ela permite que você use alguns recursos mais avançados sobre os quais falaremos a seguir.

+ +
+
+ +

Validação

+ +

Meu recurso favorito do sistema de configuração do .NET é a facilidade com que é possível validar sua configuração! Acredito que essa seja uma das partes mais importantes de qualquer aplicativo, e não vejo que ela seja usada com frequência. O motivo pelo qual acredito que a configuração é uma das partes mais importantes de qualquer aplicativo é porque ela abriga definições muito importantes do seu aplicativo.

+ +

Um aplicativo configurado incorretamente pode ter resultados desastrosos. Na pior das hipóteses, imagine que o seu ambiente de teste esteja se conectando acidentalmente aos recursos do ambiente de produção. Agora imagine que você testaria uma função de exclusão em massa e acidentalmente excluiria todos os seus dados de produção. Isso seria um desastre!

+ +

É por isso que queremos validar nossa configuração. Se o nosso aplicativo for iniciado com um sistema de configuração incorreto, queremos sair imediatamente.

+ +

Então, como configuramos isso? É mais fácil do que você imagina. Eu gosto de usar Data Annotations para minhas validações de opções quando não preciso de regras de validação complexas, portanto, vamos modificar nosso ExternalApiSettings desta forma:

+ +
public class ExternalApiSettings
+{
+    [Required] // Se o ApiUrl não estiver definido, a configuração é inválida
+    public string ApiUrl { get; set; }
+
+    [Required] // Se a ApiKey não for definida, a configuração será inválida
+    public string ApiKey { get; set; }
+
+    [Range(1, 1_000_00)] // Se o TimeoutInMilliseconds não for definido (o padrão é 0) ou for maior que 100000, a configuração será inválida
+    public int TimeoutInMilliseconds { get; set; }
+}
+ +

Agora, vamos alterar a forma como registramos essas opções no contêiner de injeção de dependência:

+ +
services
+    .AddOptions<ExternalApiSettings>()
+    .BindConfiguration(ExternalApiSettings)
+    .ValidateDataAnnotations() // Lança uma OptionsValidationException se a configuração for inválida
+    .ValidateOnStart(); // Altamente recomendado!
+ +

Em vez de usar Configure<TType>(configuration), agora usamos AddOptions<TType>(). Isso retorna um OptionsBuilder e nos permite usar alguns métodos poderosos.

+ +
    +
  1. O primeiro que usamos é o BindConfiguration(). Esse método recupera o IConfiguration do contêiner de injeção de dependência e vincula a seção que passamos. Isso é útil porque não precisamos mais passar manualmente nossa configuração.
  2. +
  3. Em seguida, chamamos ValidateDataAnnotations(). Isso validará nossa seção de configuração com base nos atributos que definimos nas propriedades. +
      +
    1. Observação: você precisa instalar o pacote nuget Microsoft.Extensions.Options.DataAnnotations se não tiver esse método disponível.
    2. +
    +
  4. +
  5. Por fim, chamamos ValidateOnStart(). Essa etapa é muito importante! Por padrão, suas opções só serão validadas quando você chamar .Value nelas em algum lugar, como em uma classe onde elas são injetadas. Isso significa que seu aplicativo NÃO lançaria um erro e sairia na inicialização quando sua configuração fosse inválida! O ValidateOnStart() validará sua configuração depois que o aplicativo terminar de se inicializar.
  6. +
+ +

Você também pode validar seu código de muitas outras maneiras. Você pode usar a interface IValidatableOptions<> para implementar uma lógica de validação complexa ou pode chamar Validate(Func<TOptions, bool> validation) para escrever uma lógica de validação personalizada como parte do construtor de opções. Você pode até mesmo integrá-lo ao FluentValidation!

+ +

Tempos de vida da configuração

+ +

Por fim, gostaria de falar sobre o tempo de vida do padrão Options. O IOptions<T> é um singleton. Isso significa que, se um de seus provedores de configuração for atualizado em tempo de execução, as opções não serão atualizadas. Isso ocorre porque as opções são mapeadas apenas uma vez quando você chama .Value sobre elas.

+ +

Isso pode ser considerado positivo, pois significa que seu aplicativo não mudará repentinamente de comportamento quando a configuração for alterada. No entanto, você também pode dizer que isso é ruim porque talvez não queira ter que fazer deploy ou reiniciar o aplicativo quando alterar a configuração. Nesse caso, é melhor usar IOptionsSnapshot<T> ou IOptionsMonitor<T>.

+ +

Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor

+ +

Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor

+ +

IOptionsSnapshot

+ +

Em vez de injetar IOptions<T> em uma de suas classes, você pode injetar IOptionsSnapshot<T>. Isso recarregará esse tipo específico de opções a cada scope. Um escopo no .NET é um termo abstrato. Um escopo pode ser uma solicitação HTTP, por exemplo. Portanto, para cada solicitação HTTP, ele recarregaria as opções e elas permaneceriam consistentes para toda a solicitação. Isso significa que, se você alterar sua configuração, ela só será atualizada em uma nova solicitação.

+ +
+
+ ⚠️ + Aviso +
+
+ +

Usar IOptionsSnapshot<T> pode causar desempenho ruim.

+ +
+
+ +

IOptionsMonitor

+ +

O IOptionsMonitor<T> não funciona com escopos. Em vez disso, você precisa chamar .CurrentValue (em vez de .Value) para recuperar a versão atual. No entanto, é preciso ter cuidado com a forma como você acessa a sua configuração! Imagine um cenário em que sua configuração é alterada no meio de uma solicitação HTTP. Chamar .CurrentValue no início e no final de uma solicitação resultaria em valores diferentes, o que cria um risco de sincronização. Você pode registrar uma chamada de retorno usando OnChange() para ser notificado sobre esses eventos.

+ +

Essa interface é mais útil em um cenário de trabalho em segundo plano que é instanciado apenas uma vez, mas que se beneficiaria da capacidade de lidar com alterações de configuração.

+ +

Gerenciamento de segredos durante o desenvolvimento

+ +

Se você vai tirar alguma conclusão dEste post, que seja a seguinte:

+ +
+
+ + Importante +
+
+ +

Nunca armazene segredos em seu repositório git! Considere o uso de uma ferramenta de verificação de código como GitHub Advanced Security, GitHub Advanced Security for Azure DevOps ou GitGuardian para evitar que segredos sejam vazados.

+ +
+
+ +

Se você armazenar segredos em seu repositório git e o repositório for comprometido, seus segredos também serão comprometidos. Acho que não preciso explicar por que isso é ruim. Então, como podemos evitar que isso aconteça com o .NET?

+ +

Usando o provedor de configuração de user secrets (segredos de usuário).

+ +

O provedor de configuração de user secrets

+ +

Mencionei o provedor de configuração de user secrets anteriormente. Esse provedor de configuração foi criado para desenvolvimento local somente. Ele permite que você armazene segredos em seu computador local sem precisar se preocupar com o risco de eles serem versionados no repositório git, pois são armazenados em um local diferente:

+ +
    +
  • Windows: %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json
  • +
  • Mac e Linux: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
  • +
+ +

Esse arquivo é muito semelhante ao provedor appsettings.json. Basta inserir JSON nele e você poderá acessá-lo com o sistema de configuração do .NET. Quando seu aplicativo for iniciado e sua variável de ambiente ASPNETCORE_ENVIRONMENT ou DOTNET_ENVIRONMENT estiver definida como Development, ele carregará automaticamente o provedor de configuração de user secrets desde que seu projeto esteja configurado para usar esse provedor.

+ +
+
+ ⚠️ + Aviso +
+
+ +

Mesmo que esse provedor tenha o nome “secret”, esteja avisado! O conteúdo do arquivo secrets.json não é criptografado. Se você trabalha em um ambiente em que armazenar segredos na própria máquina é arriscado, considere usar um armazenamento de segredos externo como o Azure KeyVault durante o desenvolvimento.

+ +
+
+ +

Esse provedor de configuração pode ser acessado usando a CLI ou seu IDE favorito. Talvez seja necessário instalar o pacote Microsoft.Extensions.Configuration.UserSecrets caso você não use um Host ou tenha uma configuração personalizada.

+ +

Usando User Secrets

+ +

CLI

+ +

Você pode usar o dotnet cli para interagir com user-secrets abrindo um terminal no diretório em que reside o *.csproj do seu projeto.

+ +
# Necessário apenas quando as user-secrets ainda não foram inicializadas
+dotnet user-secrets init
+
+# Você pode usar dados estruturados usando dois pontos (:) para separar as chaves
+dotnet user-secrets set “ConnectionStrings:Database” “Data Source=...”
+dotnet user-secrets set “AdminPassword” “hunter2”
+# Outros comandos como “list”, “remove” e “clear” também estão disponíveis
+
+
+ +

Visual Studio

+ +

Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione Manage User Secrets. Um arquivo secrets.json será aberto, no qual você poderá inserir seus segredos.

+ +

Visual Studio Code

+ +

Instale a extensão .NET Core User Secrets Visual Studio Code. Em seguida, você pode clicar com o botão direito do mouse em um arquivo *.csproj e selecionar Manage User Secrets. Um arquivo secrets.json será aberto, no qual você poderá inserir seus segredos.

+ +

JetBrains Rider

+ +

Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione Tools > Manage User Secrets. Um arquivo secrets.json será aberto, no qual você poderá inserir seus segredos.

+ +

Configurando um projeto que usa user-secrets

+ +

Uma desvantagem de usar segredos de usuário durante o desenvolvimento é que, se o seu projeto exigir alguns segredos para ser executado, será necessário executar algumas etapas de configuração após a clonagem do projeto. Tenho duas recomendações para lidar com isso:

+ +
    +
  • Você pode criar um script que recupere os segredos do seu local de armazenamento de segredos e, em seguida, armazene-os em user-secrets, canalizando esses valores para dotnet user-secrets set. Agora você só precisa executar esse script uma vez após clonar o projeto e pronto!
  • +
  • Como alternativa, recomendo atualizar seu README.MD incluindo instruções de configuração que informem ao usuário quais user-secrets devem ser definidos e de onde obter esses valores. Sinta-se à vontade para criar um link para Este post se quiser explicar o que são user-secrets 😉.
  • +
+ +

Meu modelo para gerenciamento de configuração

+ +

Agora que abordamos os conceitos básicos e o uso avançado do sistema de configuração do .NET e como incorporar o gerenciamento de segredos locais, gostaria de mostrar minha “configuração” para o gerenciamento de configuração em um projeto .NET. Quando crio um novo projeto .NET, uso a seguinte configuração:

+ +

appsettings.json

+ +

O sistema de configuração do .NET permite que você seja muito flexível com todos os diferentes provedores. Isso é ótimo, mas também pode causar confusão quando seu aplicativo estiver usando valores de configuração que você não esperava ou quando não conseguir descobrir de onde vem um valor de configuração específico.

+ +
+
+ 💡 + Dica +
+
+ +

Use o método IConfigurationRoot.GetDebugView() quando estiver tendo problemas com os valores de configuração. Para fazer isso, obtenha uma instância IConfiguration, converta-a em IConfigurationRoot e inspecione o resultado de GetDebugView().

+ +

Para obter mais informações, consulte o fantástico post de Andrew Lock sobre isso.

+ +
+
+ +

Eu uso appsettings.json para armazenar um modelo de todos os valores de configuração que meu projeto usa e de onde os valores são recuperados. Esse arquivo também pode conter valores reais quando o arquivo appsettings.json é o único provedor para esse valor de configuração. Gosto muito dessa configuração porque ela me permite ver todos os valores de configuração que meu projeto usa em um só lugar.

+ +
{
+  “Logging": {
+    “LogLevel": {
+      “Default” (Padrão): “Informações”,
+      “Microsoft.AspNetCore": “Warning”
+    }
+  },
+
+  “ConnectionStrings": {
+    “Database”: “<from-azure-keyvault>” // O Azure Key Vault será discutido na próxima seção
+  },
+
+  “ExternalApiSettings": {
+    “ApiUrl": “<from-environment-variables>”,
+    “ApiKey": “<from-azure-keyvault>”,
+    “TimeoutInMilliseconds": 5000
+  }
+}
+
+
+ +

appsettings.Development.json

+ +

A seguir, temos o arquivo appsettings.Development.json. Esse arquivo pode conter valores de configuração que substituem os valores do appsettings.json, como configurações de registro. Além disso, esse arquivo nunca deve conter segredos! Em vez disso, ele faz referência ao provedor de configuração de user secrets. Isso torna menos provável que as pessoas insiram segredos nesse arquivo, pois elas são levadas a usar o provedor de configuração de user secrets.

+ +
{
+  “Logging": {
+    “LogLevel": {
+      “Default”: “Debug”, // As configurações de log são 100% de preferência pessoal, fique à vontade para usar o que quiser
+      “Microsoft.AspNetCore": “Warning”
+    }
+  },
+
+  “ConnectionStrings": {
+    “Database”: “<from-user-secrets>” // Cada desenvolvedor pode usar sua própria string de conexão de banco de dados local
+  },
+
+  “ExternalApiSettings": {
+    “ApiUrl": “dev.externalapi.example.com”,
+    “ApiKey": “<from-user-secrets>”
+    // Não forneço um valor para TimeoutInMilliseconds porque não tenho problemas com o valor de appsettings.json
+  }
+}
+
+
+ +

User Secrets

+ +

Por fim, uso o provedor de configuração user secrets para armazenar segredos locais e substituir a configuração não secreta que não quero enviar para o repositório git, como alterar as configurações de log no caso de precisar me aprofundar em um bug. Se eu alterasse esses valores de configuração no arquivo appsettings.Development.json, teria que me lembrar de reverter essas alterações antes de fazer o commit do meu código. Ao usar o provedor de configuração de user secrets, não preciso me preocupar com isso.

+ +
{
+  “Logging": {
+    “LogLevel": {
+      “Microsoft.AspNetCore": “Information”
+    }
+  },
+
+  “ConnectionStrings": {
+    “Database”: “Data Source=...”
+  },
+
+  “ExternalApiSettings": {
+    “ApiKey": “abc123def456ghi7”
+  }
+}
+
+
+ +
+
+ + Pergunta +
+
+ +

Como é a sua configuração? O que você acha da minha? Deixe sua opinião nos comentários abaixo!

+ +
+
+ +

Usando o Azure para armazenar a configuração

+ +

Agora que sabemos como armazenar a configuração e os segredos localmente, é hora de falar sobre a execução de seus aplicativos em ambientes reais. Há muitas maneiras diferentes de configurar a configuração e o gerenciamento de segredos para ambientes não locais, portanto, tudo se resume a conhecer as vantagens e desvantagens dessas abordagens e escolher o que funciona melhor para você. Neste post, você aprenderá a usar o Azure para armazenar sua configuração e seus segredos com segurança.

+ +
+
+ ℹ️ + Info +
+
+ +

Embora esta seção seja sobre o Azure, os conceitos também se aplicam a outros provedores de nuvem. O equivalente do Azure App Configuration no AWS é chamado de AWS Systems Manager Parameter Store. O Azure Key Vault tem um equivalente no AWS chamado AWS Secrets Manager e o equivalente do Google é chamado Google Secret Manager.

+ +

Se quiser hospedar seu gerenciamento de segredos por conta própria, dê uma olhada em Hashicorp Vault.

+ + +
+
+ +

Armazenamento de segredos no Azure Key Vault

+ +

Como dissemos anteriormente, não é possível usar o provedor de configuração User Secrets em ambientes não locais. Portanto, temos que encontrar uma maneira diferente de armazenar nossos segredos quando estivermos implantando nossos aplicativos. O Azure Key Vault é um ótimo serviço para armazenar segredos, chaves e certificados de forma barata, fácil e segura.

+ +

No início deste post, mencionei que é possível conectar o sistema de configuração do .NET à nuvem, o que é possível com o Key Vault. Essa é uma ótima abordagem para o gerenciamento de segredos porque você pode simplesmente tratar o Key Vault como um provedor de configuração e não precisa mais fazer coisas complicadas no pipeline de lançamento.

+ +

Para adicioná-lo como um provedor de configuração, instale os pacotes Azure.Extensions.AspNetCore.Configuration.Secrets e Azure.Identity. Em seguida, você só precisará adicionar algumas linhas de código ao seu Program.cs quando criar uma API mínima, por exemplo:

+ +
using Azure.Identity;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Host.ConfigureAppConfiguration((context, config) =>
+{
+    if (!context.HostingEnvironment.IsDevelopment())
+    {
+        var keyVaultUrl = new Uri(context.Configuration.GetValue<string>(KeyVaultUrl));
+        config.AddAzureKeyVault(keyVaultUrl, new ManagedIdentityCredential()); // Há outras opções de credenciais disponíveis. As Managed Identities serão abordadas em breve!
+    }
+});
+ +

O Key Vault agora é adicionado como o provedor final e, portanto, tem a prioridade mais alta. Portanto, mesmo que outros provedores tenham um valor configurado para um segredo, o Key Vault será usado em seu lugar!

+ +
+
+ ℹ️ + Info +
+
+ +

Os segredos estruturados devem ser armazenados no Key Vault com 2 traços (--) em vez de 2 sublinhados ou dois pontos devido a limitações de nomenclatura. Por exemplo, ExternalApiSettings--ApiKey em vez de ExternalApiSettings:ApiKey ou ExternalApiSettings__ApiKey.

+ +
+
+ +

Usando o Key Vault durante o desenvolvimento local

+ +

Anteriormente neste post, mencionei brevemente que você pode estar em um cenário em que não é possível armazenar segredos em seu computador por motivos de segurança, por exemplo. Nesse caso, usar o Key Vault durante o desenvolvimento local resolveria esse problema. Você pode pegar o exemplo de código da seção anterior e modificá-lo da seguinte forma:

+ +
using Azure.Identity;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Host.ConfigureAppConfiguration((context, config) =>
+{
+    var keyVaultUrl = new Uri(context.Configuration.GetValue<string>(KeyVaultUrl));
+    config.AddAzureKeyVault(keyVaultUrl, new DefaultAzureCredential()); // Esses tipos de credenciais serão abordados a seguir!
+});
+ +

Agora, seu aplicativo sempre se conectará ao Key Vault, mesmo durante o desenvolvimento. O resultado é que você não precisa mais armazenar segredos em seu computador, pois eles são sempre recuperados do Key Vault. Uma desvantagem dessa abordagem é que você sempre precisa de uma conexão com a Internet para se conectar à nuvem!

+ +
+
+ ℹ️ + Info +
+
+ +

Devido aos benefícios que essa solução traz, considere o uso dessa abordagem mesmo em cenários em que o armazenamento de segredos localmente seria aceitável. Um grande benefício dessa abordagem é que você pode simplesmente clonar um projeto e, desde que tenha as permissões corretas, pode executá-lo sem precisar configurar nenhum segredo em sua máquina, pois eles são simplesmente recuperados da nuvem!

+ +
+
+ +

Conectando-se ao Azure com identidades gerenciadas

+ +

Nos exemplos de código anteriores, você viu alguns tipos estranhos de credenciais: ManagedIdentityCredential e DefaultAzureCredential. Antes de discutirmos isso, considere o seguinte:

+ +

Queremos nos conectar a um provedor de armazenamento seguro de segredos para obter segredos com os quais executar nosso aplicativo. Para nos conectarmos a esse provedor, precisaremos passar algumas credenciais para que o provedor possa autorizar nossa solicitação. Mas essas credenciais também são segredos, então onde as armazenamos? Poderíamos armazená-las em outro provedor de configuração, mas isso não anula todo o propósito de ter um provedor secreto? Se essas credenciais vazassem, alguém poderia acessar nossos segredos de qualquer forma! Para resumir, estamos lidando com um problema de galinha e ovo.

+ +

Felizmente, algumas pessoas inteligentes da Microsoft descobriram isso! Para o desenvolvimento local, você pode usar o DefaultAzureCredential para se comunicar com os serviços do Azure. Esse tipo de credencial tentará se autenticar usando vários métodos, como a conta da Microsoft com a qual você está conectado ao seu IDE, suas credenciais da CLI do Azure (az) e muito mais.

+ +

Uma visão geral de como a Identidade do Azure funciona

+ +

A Identidade do Azure usa vários métodos para autenticar a conta do Azure de um desenvolvedor.

+ +

Para ambientes de produção, a Microsoft recomenda Managed Identities para autenticar com recursos do Azure. As identidades gerenciadas são um recurso do Microsoft Entra (anteriormente conhecido como Azure Active Directory) que permite criar uma identidade para seu aplicativo no Microsoft Entra. Essa identidade pode ser usada para autenticação em outros serviços do Azure, como o Key Vault. A vantagem dessa abordagem é que você não precisa mais armazenar nenhuma credencial no aplicativo, pois a identidade é gerenciada pelo Azure AD.

+ +

Um diagrama de como as Identidades Gerenciadas funcionam.</br>

+ +
+
+ ℹ️ + Info +
+
+ +

As Managed Identities podem ser bastante difíceis de entender em um primeiro momento. Dê uma olhada na parte inferior do post para ver alguns links com mais informações sobre Managed Identities.

+ +
+
+ +

Armazenamento da configuração na Configuração de Aplicativo do Azure

+ +

Por último, mas não menos importante, quero falar sobre a oferta de nuvem do Azure para gerenciamento de configuração. Enquanto o Azure Key Vault abrange o gerenciamento de segredos, o Azure App configuration é uma oferta de SaaS que o ajudará a gerenciar sua configuração. Esses dois serviços funcionam muito bem juntos quando você vincula o Azure App Configuration ao Azure Key Vault. Se optar por usar esse serviço, você só precisará adicionar o Azure App Configuration como um provedor de configuração e, em seguida, poderá usar o sistema de configuração do .NET para acessar todas as suas configurações E segredos da nuvem!

+ +

Ele também tem muitos outros recursos, portanto, vale a pena dar uma olhada!

+ +
+
+ ℹ️ + Info +
+
+ +

Considere a possibilidade de usar identidades gerenciadas para acessar a Configuração de Aplicativos para aumentar a segurança!

+ + +
+
+ +

Finalizando

+ +

Você chegou até o fim! Este post levou muito tempo para ser escrito, e estou feliz por finalmente ter sido concluído! Abaixo, você encontrará mais informações se quiser saber mais sobre os conceitos que abordei neste post. Se você tiver alguma dúvida, fique à vontade para deixar um comentário abaixo. Se quiser saber quando e onde darei a versão de palestra deste post, confira minha página Speaking.

+ + + +

Mencionei que o post é um complemento de uma de minhas sessões. Essa sessão contém várias demonstrações que mostram os conceitos discutidos nEste post. Você pode encontrar as demonstrações aqui.

+ + + + + +
+ +

Você gostou deste post? Faça uma doção para o autor original em https://ko-fi.com/stenbrinke.nl

+ +

Carlos de volta

+ +

Carlos Schults de volta aqui. Espero que tenham gostado bastante do post, e sugiro que o coloquem nos favoritos para ser um recurso útil de consulta toda vez que surgir alguma dúvida referente ao gerenciamento de secrets e configuração.

+ +

Agradeço a Sander ten Brinke, autor do artigo original, que gentilmente me autorizou a traduzí-lo. O blog dele é fantástico, tem muitos artigos extremamente bem escritos sobre diversos tópicos relacionados a .NET. Para quem sabe inglês, recomendo fortemente a visita.

+ +

Gostaria de agradecer também a Andrew Lock, o autor do livro ASP.NET Core in Action, por ter concedido autorização para reproduzir uma imagem de seu livro.

+ +

A você que leu o artigo - todo ou apenas uma parte — deixo também um agradecimento e um pedido: me dê seu feedback. É extremamente importante saber se as pessoas gostam desse tipo de conteúdo, pois me motiva a continuar produzindo.

+ +

Até a próxima!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/csharp-expressoes-regulares.html b/pt/csharp-expressoes-regulares.html new file mode 100644 index 00000000..e548cf51 --- /dev/null +++ b/pt/csharp-expressoes-regulares.html @@ -0,0 +1,722 @@ + + + + + + + + C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos

+ +
+ +
+

+NOTA: Eu originalmente escrevi esse post para o blog da empresa Stackify. Você pode ler o artigo original, em inglês, no site deles.

+ +

A manipulação de texto é uma das tarefas mais comuns na programação, sendo que praticamente todas as principais linguagens de programação oferecem suporte a regex (expressão regular) por meio de suas bibliotecas padrão. O C# não é exceção, portanto, hoje trazemos a você um guia de regex do C#.

+ +

Você aprenderá o que são expressões regulares, por que você deseja usá-las e como começar de uma maneira abrangente e acessível. Dessa forma, você poderá começar a usar expressões regulares para resolver problemas reais o mais rápido possível.

+ +

Prepare-se para sua jornada de aprendizado de regex, que começa agora!

+ +

O Que é Regex?

+

Uma expressão regular (também chamadas de regex, abreviação para regular expression) é uma expressão que contém um ou vários caracteres que expressam um determinado padrão no texto. Se isso parecer um pouco vago, um exemplo vai ajudar. Considere uma data no seguinte formato:

+ +
28-JUL-2023
+
+ +

Usando um regex, podemos expressar esse formato da seguinte forma:

+ +
[0-9]{2}-[A-Z]{3}-[0-9]{4}
+
+ +

Observe que a expressão regular acima expressa um padrão com:

+ +
    +
  • dois dígitos numéricos seguidos de um hífen
  • +
  • três letras maiúsculas seguidas de um hífen
  • +
  • mais quatro números
  • +
+ +

Você saberá mais sobre o significado de cada parte de uma regex em um minuto. Por enquanto, lembre-se de que a regex acima não sabe nada sobre datas. Acontece que conseguimos criar uma expressão regular que corresponde ao padrão ou ao formato da data. Todos os itens a seguir correspondem a essa regex, mesmo que não sejam datas válidas:

+ +
32-ABC-7894
+30-FEV-1978
+00-AAA-9999
+
+ +

Existe Regex no C#?

+ +

Sim, é claro. Mas isso não vem da própria linguagem. Em vez disso, o suporte a regex vem da .NET’s BCL (Base Class Library), que é essencialmente a biblioteca padrão do C#.

+ +

Por Que Usar Regex em C#?

+ +

Como você viu, regex é algo a ser usado para expressar um padrão que pode corresponder a um determinado texto.

+ +

Na prática, todos os usos de regex em C# ou em outras linguagens se resumem a três motivos: validação, manipulação e extração.

+ +

Validação

+ +

Um caso de uso incrivelmente comum para regex é a validação de dados. Por exemplo, digamos que você tenha um formulário da Web e queira garantir que um determinado campo só aceite entradas em um formato específico. Como resolver isso? O Regex vem em seu socorro.

+ +

Manipulação

+ +

Às vezes, você precisa alterar informações dentro do texto. Vamos voltar ao exemplo anterior. Imagine que, por motivos de compliance, você precise remover todos os números de telefone desse corpo de texto e substituí-los pela palavra “REDACTED”. Novamente, as expressões regulares seriam perfeitas para essa situação.

+ +

É interessante notar que as linguagens de programação não são as únicas a usar expressões regulares para resolver problemas. Até mesmo os editores de texto, como o Notepad++, oferecem recursos de localizar e substituir com o auxílio de expressões regulares.

+ +

Extração

+ +

Digamos que você tenha uma quantidade considerável de texto. Esse texto contém números de telefone que você precisa extrair. Você conhece o formato desses números e o fato de que eles estão dentro do texto, mas esse é o limite do seu conhecimento.

+ +

Como você faria para extrair essas informações? Um regex C# bem feito certamente seria útil nessa situação.

+ +

Como usar o Regex em C#: Primeiros passos na prática

+ +

O C# é uma linguagem orientada a objetos, portanto, não é de surpreender que você use uma classe para trabalhar com regex no C#. Mais especificamente, a classe de que estou falando é apropriadamente chamada de Regex e reside no namespace System.Text.RegularExpressions.

+ +

C# Regex: Um exemplo de validação

+ +

Vamos começar com um exemplo simples de validação sobre como usar regex para validar se várias cadeias de caracteres correspondem a um determinado padrão. A primeira etapa é adicionar a seguinte instrução using ao seu código:

+ +
using System.Text.RegularExpressions;
+ +

Agora, vamos criar um array de strings e preenchê-la com alguns valores:

+ +
var candidates = new[]
+{
+    "28-JUL-2023",
+    "whatever",
+    "89-ABC-1234",
+    "11-JUN-2022",
+    "11-JUN-2022, uma data e outras coisas",
+    "Isso certamente não é uma data"
+};
+ +

Por fim, percorreremos os valores e usaremos o método estático IsMatch da classe Regex para verificar qual das cadeias de caracteres corresponde ao padrão desejado:

+ +
var pattern = "[0-9]{2}-[A-Z]{3}-[0-9]{4}";
+foreach (var c in candidates)
+{
+    if (Regex.IsMatch(c, pattern))
+    {
+        Console.WriteLine($"A string '{c}' corresponde ao padrão '{pattern}'");
+    }
+}
+ +

Antes de prosseguir, vamos detalhar o padrão parte por parte:

+ +
    +
  • [0-9]{2}: A primeira parte significa “Corresponde exatamente a dois caracteres, que devem ser dígitos de 0 a 9”.
  • +
  • -: Esse caractere corresponde exatamente a um hífen.
  • +
  • [A-Z]{3}: Aqui, a expressão diz: “Vamos corresponder exatamente a três caracteres, que podem ser qualquer uma das letras de A a Z.”
  • +
  • -: Isso corresponde a outro hífen
  • +
  • [0-9]{4}: Isso já deve ser fácil de entender, certo? Exatamente quatro números.
  • +
+ +

Agora, vamos executar o código e ver o que obtemos:

+ +
A string '28-JUL-2023' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+A string '89-ABC-1234' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+A cadeia de caracteres '11-JUN-2022' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+A cadeia de caracteres '11-JUN-2022, a date plus other stuff' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
+
+ +

Os três primeiros resultados provavelmente não o surpreenderam. Eu até incluí algo que não é uma data, mas que corresponde ao padrão que estamos usando para realmente enfatizar que as expressões regulares tratam de padrões e formas e não de qualquer semântica dos dados que estamos procurando.

+ +

Entretanto, o quarto resultado pode tê-lo surpreendido. O texto de fato começa com dados que correspondem ao padrão que estamos procurando, mas depois tem algum texto adicional. E mesmo assim, essa string correspondeu!

+ +

A explicação para esse comportamento é simples e está explicada para nós no summary do método IsMatch:

+ +
Indica se a expressão regular especificada encontra uma correspondência na cadeia de caracteres de entrada especificada.
+
+ +

A expressão regular de fato encontrou uma correspondência na string de entrada especificada (“11-JUN-2022, a date plus other stuff”), e é por isso que foi considerada uma correspondência.

+ +

Mas e se quiséssemos uma correspondência exata? Nesse caso, seria necessário alterar o padrão, adicionando um acento circunflexo (“^”) ao início do padrão e um cifrão (“$”) ao seu final. Em outras palavras, veja como o padrão deve ficar agora:

+ +
var pattern = "^[0-9]{2}-[A-Z]{3}-[0-9]{4}$";
+ +

Se executarmos o código agora, ele exibirá apenas as cadeias de caracteres que são uma correspondência exata com o padrão:

+ +
A string '28-JUL-2023' corresponde ao padrão '^[0-9]{2}-[A-Z]{3}-[0-9]{4}
+
+ +

C# Regex: Um exemplo de manipulação

+ +

Considere que você tem um texto que contém dados sensíveis do usuário. Devido a questões de privacidade/compliance, você deseja excluir esses dados. Felizmente para você, é muito fácil usar uma regex para isso.

+ +

Vamos começar criando uma matriz contendo nomes e números de telefone de pessoas fictícias:

+ +
var contacts = new[] {
+    "Emily Johnson,(555) 123-4567",
+    "Benjamin Williams,(555) 987-6543",
+    "Olivia Davis,(555) 222-3333",
+    "Alexander Smith,(555) 444-5555",
+    "Sophia Brown,(555) 777-8888",
+    "William Anderson,(555) 111-2222",
+    "Ava Martinez,(555) 666-7777",
+    "James Thompson,(555) 888-9999",
+    "Isabella Wilson,(555) 333-4444",
+    "Michael Taylor,(555) 777-1111"
+};
+ +

Em seguida, vamos criar o padrão para corresponder aos números de telefone:

+ +
var pattern = @"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}";
+ +

O padrão acima é um pouco mais complexo do que os que usamos anteriormente, mas ainda é simples. No entanto, há alguns elementos novos:

+ +
    +
  • A barra invertida (\): Precisamos dela aqui para escapar dos parênteses de abertura e fechamento, que é um caractere com significado em uma expressão regular. Nesse caso, queremos de fato corresponder a um caractere “(“, portanto, precisamos escapar dele.
  • +
  • O caractere \s: corresponde a um único espaço.
  • +
+ +

Por fim, vamos percorrer essa matriz e, para cada item, usar o método Regex.Replace para gerar uma nova string na qual o número de telefone é substituído por todos os zeros:

+ +
foreach (var contact in contacts)
+{
+    Console.WriteLine(
+        Regex.Replace(contact, pattern, "(000) 000-0000"));
+}
+ +

Usar o método estático Replace é fácil. Embora ele tenha várias sobrecargas, a que usamos recebe apenas três argumentos:

+ +
    +
  • a string de entrada
  • +
  • o padrão que você deseja corresponder
  • +
  • a string de substituição
  • +
+ +

Depois de executar o código, eis o resultado que obtemos:

+ +
Emily Johnson,(000) 000-0000
+Benjamin Williams,(000) 000-0000
+Olivia Davis,(000) 000-0000
+Alexander Smith,(000) 000-0000
+Sophia Brown,(000) 000-0000
+William Anderson,(000) 000-0000
+Ava Martinez,(000) 000-0000
+James Thompson,(000) 000-0000
+Isabella Wilson,(000) 000-0000
+Michael Taylor,(000) 000-0000
+
+ +

C# Regex: Um exemplo de extração

+ +

Para o nosso último exemplo, vamos extrair dados de uma string usando uma expressão regular. Vamos começar convertendo o array do exemplo anterior em uma única string:

+ +
var contacts =
+    "Emily Johnson+(555) 123-4567" +
+    "\nBenjamin Williams+(555) 987-6543" +
+    "\nOlivia Davis+(555) 222-3333" +
+    "\nAlexander Smith+(555) 444-5555" +
+    "\nSophia Brown+(555) 777-8888" +
+    "\nWilliam Anderson+(555) 111-2222" +
+    "\nAva Martinez+(555) 666-7777" +
+    "\nJames Thompson+(555) 888-9999" +
+    "\nIsabella Wilson+(555) 333-4444" +
+    "\nMichael Taylor+(555) 777-1111";
+ +

Em seguida, definimos o padrão novamente (o mesmo) e usamos o método estático Matches para obter todas as correspondências da string:

+ +
var pattern = @"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}";
+MatchCollection matches = Regex.Matches(contacts, pattern);
+ +

A classe MatchCollection contém todas as cadeias de caracteres que corresponderam ao padrão que fornecemos ao método. Esse objeto é enumerável, portanto, podemos fazer um loop sobre ele com um foreach:

+ +
Console.WriteLine("Aqui estão os números de telefone extraídos:");
+foreach (Match match in matches)
+{
+    Console.WriteLine(match.Value);
+}
+ +

E, finalmente, nossos resultados:

+ +
Aqui estão os números de telefone extraídos:
+(555) 123-4567
+(555) 987-6543
+(555) 222-3333
+(555) 444-5555
+(555) 777-8888
+(555) 111-2222
+(555) 666-7777
+(555) 888-9999
+(555) 333-4444
+(555) 777-1111
+ +

C# Regex: Uma Ferramenta Indispensável

+ +

Como dissemos na introdução, a manipulação de texto é um elemento básico da programação, e as expressões regulares facilitam essa tarefa. Neste guia de regex em C#, você aprendeu o que são expressões regulares, seus cenários de uso mais comuns e como começar a usar expressões regulares em C#.

+ +

Antes de ir embora, algumas dicas:

+ + + +

Por fim, se quiser saber mais sobre o C# em geral, o blog da Stackify está repleto de recursos úteis. Como sugestão, dê uma olhada em os prós e contras dos 3 principais frameworks de teste de unidade para C#, como capturar exceções e localizar erros de aplicativos em C# e como funciona a reflexão em C#.

+ +

Obrigado pela leitura!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/escrevendo-codigo-bom/index.html b/pt/escrevendo-codigo-bom/index.html new file mode 100644 index 00000000..614ee5d6 --- /dev/null +++ b/pt/escrevendo-codigo-bom/index.html @@ -0,0 +1,561 @@ + + + + + + + + Escrevendo código bom: como reduzir a carga cognitiva do seu código | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Escrevendo código bom: como reduzir a carga cognitiva do seu código

+ +
+ +
+

+ +

NOTA: O artigo a seguir foi originalmente escrito por Christian Maioli M., que gentilmente me autorizou a fazer esta tradução. Caso seja do seu interesse, confira o artigo original.

+ + +
+

+ +

Baixo número de bugs, boa performance, facilidade de modificação. Código bem feito gera alto impacto, e talvez seja a maior razão por trás da existência do famoso desenvolvedor “10x”. E ainda assim, apesar de sua importância, código bom escapa a novos desenvolvedores. A literatura nessa área geralmente consistente de coleções de dicas desconexas. Como um novo desenvolvedor vai simplesmente memorizar isso tudo? “Code Complete“, o maior expoente nesta matéria, é um livro de 960 páginas!

+ +

Eu acredito que é possível construir um framework mental simples que pode ser usado com qualquer linguagem ou biblioteca e que vai resultar em código de boa qualidade por padrão. Há cinco conceitos principais sobre os quais vou falar aqui. Basta mantê-los em mente e escrever código de boa qualidade será moleza.

+ +

Update: Mia Li fez a gentileza de disponibilizar uma tradução deste artigo para o Chinês aqui.

+ +

Mantenha suas peculiaridades pessoais de fora

+ +

Você lê um artigo que explode a sua mente com truques novos. Agora você vai escrever código “esperto” e todos os seus colegas ficarão impressionados.

+ +

O problema é que as pessoas só querem corrigir seus bugs e ir em frente. Seu truquezinho esperto é, com frequência, pouco mais que uma distração. Como eu falei em “Applying neuroscience to software development“, quando as pessoas têm que digerir seu código, as “pilhas mentais” enchem depressa e se torna difícil fazer progresso.

+ +

+ +
Não personalize seu trabalho em maneiras que irão precisar de explicações. + +Tradução do comentário: Isso era útil na linguagem C para evitar escrever acidentalmente "variable = null". Atualmente, isso apenas confundiria a maioria das pessoas, com pouco benefício.
+

 

+ +

Não codifique “do seu jeito”. Apenas siga a padronização de código. Este tipo de coisa é um problema já resolvido. Torne seu código previsível e fácil de ler codificando da maneira que as pessoas esperam.

+ +

Dividir para conquistar

+ +

Código complexo frequentemente pode ser clarificado por meio da modularização, e existem mais maneiras de se fazer isso do que apenas criando mais funções. Gravar o resultado de longas condicionais em uma variável ou duas é uma grande maneira de modularizar sem o overhead de chamar uma função. Isso irá inclusive lhe permitir compô-las em condicionais maiores, ou reutilizar o resultado em algum outro lugar.

+ +

A abordagem ao se dividir um problema deve ser tornar cada seção o mais focada possível, afetando apenas estado local, sem misturar com assuntos irrelevantes, e se possível sem nenhum efeito colateral. Linguagens de programação e bibliotecas muitas vezes têm seus próprios problemas, e abstraí-los pode ajudar a fazer com que seu código cuide apenas dos assuntos dele. O Princípio da Responsabilidade Única é outro exemplo de como código focado e localizado resulta em bom design.

+ +

+ +
Eu gosto de utilizar variáveis para compartimentar lógica. +Tradução do comentário: Isso pode ser uma boa maneira para modularizar sem o peso excessivo de chamadas de funções
+

 

+ +

TDD, além de trazer seus próprios benefícios quando feito corretamente, tem feitos com que as pessoas apliquem certos princípios que anteriormente não eram tão populares. Código sem estado era desprezado como lento e desnecessário (ver: maior parte de código antigo em C/C++), e agora todos estão falando sobre funções puras. Mesmo que você não use TDD, você deveria aprender seus princípios. Trabalhar sob novos paradigmas transformará você em um desenvolvedor resiliente.

+ +

Torne seu código discreto e processável

+ +

Seu computador e suas ferramentas podem sofrer tanto quanto você para lidar com seu código, e existe alguma correlação entre o número de pré-processadores e mutações você precisa aplicar e o quão bagunçado o seu código é.

+ +

Vamos deixar de lado os possíveis benefícios destas ferramentas de build adicional por um momento. A probabilidade é de que elas requerem que você use linguagens de domínio específica como templates customizados, ou estruturas de dados dinâmicas e complexas como hash tables. A sua IDE provavelmente não será boa em lidar com tais coisas, e a localização de trechos relevantes do código se tornará mais difícil.

+ +

Evite usar extensões de linguagens e bibliotecas que não trabalham bem com sua IDE. O impacto que eles terão na sua produtividade bate de longe o pequeno benefício de uma configuração mais fácil ou a economia de algumas poucas teclas com uma sintaxe mais concisa.

+ +

+ +
+O uso de Service Locator é um exemplo de design que resulta em integração ruim com a maioria das IDEs. +Tradução do comentário: Uso de string mágicas fará com que seja impossível para sua IDE acompanhar seu código. +
+

 

+ +

Outra maneira de manter a parte “integrada” da sua IDE relevante é evitar código mágico. A maioria das linguagens disponibilizam maneiras para que você escreva código mais dinâmico. Abusar tais features utilizando strings mágicas, índices de arrays mágicos e funcionalidades de templates customizados irá resultar em uma base de código mais desconectada. Geralmente qualquer feature que apenas um humano sabe o significado vai levar você para essa caminho, e é uma estrada difícil de se escapar, porque se a sua IDE não entende o código, quaisquer funcionalidades de refatoração que possua serão inúteis quando você quiser mudar para uma arquitetura mais estática.

+ +

Torne seu código legível

+ +

Trabalhe no sentido de ter uma arquitetura previsível. Seus colegas de time terão mais facilidade em localizar as coisas, e isso vai reduzir bastante o tempo necessário para concluir as tarefas. Assim que vocês estiverem de acordo sobre uma estrutura arquitetural geral para seu projeto, torne óbvia a localização dos principais elementos. Usa MVC? Coloque models, views e controllers em suas próprias pastas, não três níveis abaixo ou espalhados em vários lugares.

+ +

Eu falei sobre modularização. Também é possível existir modularização em excesso, o que geralmente torna seu código mais difícil de localizar. Sua IDE pode oferecer alguma ajuda, mas às vezes você estará dividido entre fazer com que sua IDE ignore uma pasta de biblioteca ou outro terceiro devido a ela conter muito código irrelevante, ou mantê-la indexada e lidar com o problema manualmente. É um beco sem saída. Tente utilizar menos bibliotecas escolhendo aquelas que resolvem tantas necessidades quantas forem possível.

+ +

Bibliotecas e ferramentas também podem ser uma barreira a novos desenvolvedores. Eu recentemente fiz um projeto usando EcmaScript 7 (babel), apenas para depois perceber que nosso desenvolvedor júnior estava tendo problemas para entender o que tudo aquilo significava. Uma penalidade pesada para a produtividade do time. Eu subestimei o potencial daquilo de sobrecarregar uma pessoa que está só começando. Não use ferramentas que ainda são difíceis demais de aprender. Espere por uma época melhor.

+ +

+
Código real de um makefile que escrevi. Desenvolvedores juniores não conseguem lidar com o uso excessivo de novas ferramentas.
+

 

+ +

Torne seu código fácil de digerir

+ +

Se você chegou até aqui, eu tenho boas notícias: esta é provavelmente a parte mais importante. A escolha de bons nomes é sabidamente um dos maiores problemas no desenvolvimento de software. Ferramentas de build provavelmente não vão causar nenhuma melhora aqui, e a razão é que computadores não podem realmente saber o raciocínio que houve por trás de uma solução.

+ +

Você precisa documentar o porquê. Nomes de variáveis e funções relevantes e contextuais são uma ótima maneira de se fazer isso. Nomes que transmitem propósito podem até reduzir a necessidade de documentação.

+ +

O uso de prefixos em nomes é uma boa maneira de adicionar sentido a eles. É uma prática que costumava ser popular, e eu penso que o mau uso foi o motivo dela não continuar a ser usada. Sistemas de prefixos como notação húngara inicialmente tinham a intenção de adicionar sentido, mas com o tempo eles acabaram sendo usado em maneiras menos contextuais, tais como para adicionar informação de tipo.

+ +

+
Interfaces fluentes tem sido abusadas frequentemente em tempos recentes.
+

Tradução do comentário: Use nomes que transmitam propósito, não tome vantagem da linguagem apenas para parecer inteligente

+ +

Finalmente, sempre há algo a ser dito sobre manter a complexidade ciclomática baixa. Isso significa manter o número de ramificações condicionais tão baixo quanto for possível. Cada ramificação adicional não apenas adiciona mais indentação e prejudica a legibilidade, mas, mais importante que isso, aumenta o número de elementos aos quais você precisa estar atento.

+ +

Conclusão e mais leituras

+ +

Estes são cinco conceitos simples e abrangentes, e o meu objetivo aqui foi tornar seu aprendizado mais fácil ao lhe dar caixas nas quais colocar todas as suas ideias sobre organização de código.

+ +

Pratique focar nesses aspectos ao programar para solidifica-los. Se você ainda não leu, eu realmente recomendo Code Complete. Ele vem com um grande número de exemplos e disseca quase todas as situações que você pode vir a encontrar.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/funcionalidades-csharp-7-parte-2.html b/pt/funcionalidades-csharp-7-parte-2.html new file mode 100644 index 00000000..2f73e1cc --- /dev/null +++ b/pt/funcionalidades-csharp-7-parte-2.html @@ -0,0 +1,623 @@ + + + + + + + + Funcionalidades do C# 7 que vale a pena conhecer - Parte 2 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Funcionalidades do C# 7 que vale a pena conhecer - Parte 2

+ +
+ +
+

+ +

Neste artigo, vamos continuar a ver algumas das features mais interessantes do C# 7. +

+ +

Na primeira parte da série, nós falamos sobre algumas das novas features do C#, a saber: melhorias em literais, variáveis de saída, mais membros “expression-bodied” e throw expressions.

+ +

Hoje nós veremos: Tuplas e Funções locais. Mas antes de continuarmos, quero deixar meu agradecimento ao amigo Gunter Italiano Ribeiro, que gentilmente revisou este artigo.

+ +

Tuplas

+ +

Alguma vez você já teve a necessidade de escrever um método que retornasse mais de um valor? Provavelmente sim. Nas versões anteriores do C#, havia algumas opções disponíveis. Você poderia usar um parâmetro de saída (out), ou talvez criar um tipo específico, mas cada uma dessas opções tem seus próprios problemas. Parâmetros de saída podem complicar um pouco o design; criar um tipo para cada uma dessas situações pode ocasionar um overhead desnecessário, se tudo que você quer é só uma maneira de retornar dois valores, principalmente em um contexto privado.

+ +

No C# 7.0 você tem uma nova opção, utilizando tuple types e tuple literals. Com esta funcionalidade você pode facilmente declarar um método que retorna mais de um valor. Vamos ver um exemplo:

+ + + +

Você é provavelmente familiar com o padrão TryXXX, usado por exemplo no tipo System.Int32. Estes tipos de métodos geralmente utilizam um parâmetro de saída (out) para retornar o valor resultante (ou o valor default do tipo, no caso da operação de parsing não for bem sucedida.

+ +

O exemplo acima contém um método TryParse na classe ZipCode. Observe a assinatura do método.

+ +

Quando você escreve mais de um tipo desta forma na declaração do método, você está usando um tuple type. Não se preocupe, você vai se acostumar.

+ +

Logo no início do método, nós passamos o texto recebido para um método privado que realizada a validação propriamente dita e retorna um valor lógico.

+ +

Depois da validação, nós retornamos um tuple literal, que consiste em uma nova instância da classe ZipCode e o flag indicando se a operação de parsing foi bem sucedida.

+ +

Legal, mas e o outro lado? Como o chamador da função lida com este tipo de retorno? Vamos ver:

+ + + +

Se você colocar o cursor sobre o nome da variável, você verá seu tipo descrito, não surpreendentemente, como (ZipCode, bool).

+ +

+ +

Você pode acessar cada elemento da tupla utilizando zipParsingResult.Item1, zipParsingResult.Item2, e assim por diante.

+ + + +

Entretanto, você não é obrigado a usar os nomes padrão dos elementos. Você pode usar nomes mais descritivos:

+ + + +

O código que chama o método torna-se mais legível:

+ + + +

Há ainda outra maneira de acessar os elementos de uma tupla. Utilizando uma funcionalidade chamada Desconstrução, você pode facilmente quebrar os componentes de uma tupla em variáveis.

+ +

Você pode declarar as variáveis usando seus tipos

+ + + +

É claro que inferência de tipo também funciona aqui, e neste caso você tem duas opções: usar a palavra-chave var para cada variável, ou usá-la uma vez só para todas as variáveis, colocando-a fora dos parênteses.

+ + + +

Você não precisa realmente declarar as variáveis no momento da desconstrução, porém. É perfeitamente válido desconstruir uma tupla em variáveis já declaradas.

+ +

Algumas notas

+ +

Tuplas são Tipos de Valor. A igualdade nas tuplas é implementada da maneira que você provavelmente esperaria: duas tuplas são iguais se seus valores são iguais e elas retornam o mesmo HashCode. O nome dos elementos não é relevante.

+ + + +

A atribuição também funciona da maneira que você provavelmente espera. Contato que elas sejam atribuíveis, duas tuplas podem ser atribuídas uma a outra facilmente. Assim como no caso anterior, nomes dos elementos não importam.

+ + + +

Atualmente, para que esta funcionalidade funcione, você precisa instalar um pacote do nuget chamado “System.ValueTuple”. No Visual Studio, vá para Ferramentas > Gerenciador de pacotes do NuGet > Console do Gerenciador de Pacotes.

+ +

A janela do Console do Gerenciador de Pacotes será exibida. Digite (ou copie e cole) Install-Package System.ValueTuple e pressione ENTER.

+ +

Mas e o tipo System.Tuple?

+ +

Você talvez esteja se perguntando: qual a razão de tanto barulho sobre tuplas, já que o .Net Framework tem o tipo de referência System.Tuple desde a versão 4.0? Por que não continuamos com o tipo mais antigo?

+ +

Bem, esta resposta no Stack Overflow explica muito bem (em inglês), então eu vou tentar resumir aqui.

+ +

Primeiramente, conforme já mencionado, o tipo mais antigo é um tipo de referência, e o novo tipo é um tipo de valor, com todas as implicações usuais que isso traz.

+ +

Mas as diferenças realmente importantes têm a ver com conveniência e legibilidade. Ao usar System.Tuple não há desconstrução; você só pode acessar os elementos usando os nomes padrão (Item1, Item2, etc), o que pode prejudicar a leitura e interpretação do código.

+ +

Funções Locais

+ +

Resumidamente, uma função local é exatamente o que o nome sugere: uma função que pode ser declarada dentro de outra.

+ + + +

Como você notou, a função interna consegue acessar os valores disponíveis para a função mais externa.

+ +

É claro que o exemplo acima é deliberadamente simples; em produção, você provavelmente escreveria o código em Log() dentro do próprio método exterior.

+ +

Você também poderia utilizar um delegate:

+ + + +

Pelo visto, tudo que podemos fazer com funções locais já é possível de ser feito com métodos privados ou delegates. Será que precisamos mesmo desta feature?

+ +

Giovani Bassi nos mostra algumas razões para utilizar funções locais:

+ +
+ +
    +
  • Sintaxe consistente com a já utilizada em métodos;
  • +
  • Não há necessidade de criar um delegate, ou referenciar Func, Action, ou algo parecido;
  • +
  • Lambdas e delegates causam alocações extras, funções locais não;
  • +
  • Ref e out são permitidos;
  • +
  • Tipos genéricos são permitidos;
  • +
  • É possível referenciar funções ainda não declaradas.
  • +
+
+ +

É claro que você poderia simplesmente usar um método privado. Mas a função local tem essa característica interessante de não ser acessível em nenhum outro lugar na classe, de maneira que não pode ser chamada acidentalmente.

+ +

Mads Torgersen nos mostra uma situação para a qual funções locais são a solução perfeita:

+ +
+

As an example, methods implemented as iterators commonly need a non-iterator wrapper method for eagerly checking the arguments at the time of the call. (The iterator itself doesn’t start running until MoveNext is called). Local functions are perfect for this scenario:

+
+ +

Em tradução livre:

+ +
+

Como exemplo, é comum que métodos implementados como iteradores necessitem de um wraper sem iterador para checar os argumentos imediatamente na hora da chamada. (O iterador em si não começa a rodar até que MoveNext seja chamado). Funções locais são perfeitas para este cenário:

+
+ + + +

Você poderia transformar a função Iterator() acima em um método privado, mas seria: 1) redundante e pouco elegante, pois iria requerer repetir a mesma assinatura e argumentos da função externa; e 2) menos seguro, pois outra parte do código poderia chamar o método sem fazer a validação.

+ +

Conclusão

+ +

Falamos hoje sobre Tuplas e Funções Locais, duas novas features do C# que, à primeira vista, podem até parecer “inofensivas”, mas que têm potencial para mudar o código que escrevemos de maneiras interessantes.

+ +

Com relação às funções locais, admito que, a princípio, não gostei. Ou melhor dizendo: não fui capaz de ver utilidade. Depois de pesquisar um pouco mais, entendi que funções locais têm sim seus casos de uso.

+ +

Com as tuplas a história é diferente. Acredito que quase todo desenvolvedor C# com alguma experiência já desejou poder retornar mais de um valor de um método e se frustrou com as opções disponíveis. Agora com as tuplas finalmente temos uma solução elegante, fácil de usar e que melhora a legibilidade do código.

+ +

Nem tudo são flores, infelizmente. Alguns desenvolvedores já expressaram preocupações com essas features. Por exemplo, as funções locais podem incentivar a proliferação de métodos gigantescos.

+ +

As tuplas, por sua vez, podem ser exageradamente utilizadas em situações que requerem objetos, tornando o código mais procedural.

+ +

Minha opinião com relação à isso é simples: toda e qualquer feature pode ser abusada. Cada a nós, profissionais, e às nossas equipe, exercermos o senso crítico na hora de utilizar essas (e outras) funcionalidades. Aliás, conforme mencionei no meu artigo sobre métodos privados, revisão de código e/ou programação em par são de ótima ajuda em momentos como esse.

+ +

Obrigado pela leitura, e até a próxima.

+ +

Referências

+ + + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/funcionalidades-csharp-7/index.html b/pt/funcionalidades-csharp-7/index.html new file mode 100644 index 00000000..37aa64a8 --- /dev/null +++ b/pt/funcionalidades-csharp-7/index.html @@ -0,0 +1,557 @@ + + + + + + + + Funcionalidades do C# 7 que vale a pena conhecer - Parte 1 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Funcionalidades do C# 7 que vale a pena conhecer - Parte 1

+ +
+ +
+

+ +

C# 7 está finalmente entre nós. Hora de conhecer algumas de suas features. +

+ +

No meu último post eu escrevi sobre algumas das funcionalidades mais interessantes (para mim, pelo menos) do C# 6. Visual Studio 2017 e C# 7 foram oficialmente lançados no dia seguinte, então eu acredito que agora é o momento perfeito para batermos um papo sobre a nova versão da linguagem.

+ +

Eu acho que é justo dizer que, em sua sétima versão, o C# continua a tendência iniciada na versão anterior. Ao invés de adicionar novas capacidades radicalmente novas na linguagem, o time de design escolheu incluir funcionalidades que podem tornar seu código mais limpo e simples.

+ +

Nesta versão, eles expandiram certas funcionalidades que tiveram sua estreia na versão 6. Parece até que o C# 6 foi um tipo de ensaio para algumas das features; agora que os projetistas da linguagem sabem que elas foram bem recebidas, eles podem levá-las para seu próximo nível.

+ +

Então, sem mais delongas, vamos começar.

+ +

Separadores de dígitos e literais binários

+ +

Dê uma olhada no código a seguir:

+ + + +

Para que servem os underscores? Legibilidade, essa é a resposta.

+ +

Números compridos podem ficar bem difíceis de serem lidos. Para lidar com esse problema, C# 7 permite que você use o _ como separador de dígito.

+ +

Os separadores não fazem nenhuma diferença no valor do número. Você pode colocá-los em qualquer lugar no número, e em qualquer quantidade.

+ +

E caso você esteja se perguntando, você não está restrito a usar os separadores com números inteiros apenas; eles também funcionam com os outros tipos numéricos.

+ +

A nova versão do C# também introduz literais binários, como visto na terceira linha do exemplo anterior. Se você precisar escrever um valor binário, basta colocar 0b no começo do número, e é isso!

+ +

Variáveis ‘Out’

+ +

Em versões anteriores do C#, trabalhar com variáveis out era um pouco inconveniente. Você tinha que separar a declaração da variável e seu uso em dois passos.

+ +

Agora, é possível já declarar a variável na lista de argumentos:

+ + + +

Algumas coisas importantes para se ter em mente:

+ +
    +
  • Apesar de eu ter explicitamente escrito o nome do tipo na declaração, isso não é sempre necessário. Eu poderia ter usado var e funcionaria do mesmo jeito.
  • +
  • Você talvez tenha pensado que a variável iria sair de escopo depois do bloco do if. Este não é o caso. A variável continua sendo acessada normalmente até que saia do seu escopo normal.
  • +
+ + + +

(Mais) Membros “Expression-bodied”

+ +

No começo deste post, eu disso que C# 7 expande algumas features do seu antecessor, lembra? Bom, este é um destes casos.

+ +

No post anterior, nós vimos que o C# 6 nos trouxe membros “Expression-bodied”, que é uma maneira mais legal e mais curta de declarar membros de classe, usando a sintaxe das expressões lambda.

+ +

Porém, você só podia utilizar essa funcionalidade com métodos, propriedades somente leitura e indexadores.

+ +

C# 7 muda o jogo. Agora também é permitido ter construtores, destrutores e propriedades de escrita que usam essa feature.

+ + + +

Expressões “throw”

+ +

Esta é bem simples. Considere o código a seguir:

+ + + +

Foram 9 linhas de código para apenas uma atribuição. E a maioria dessas linhas nem estão fazendo a atribuição em si; elas são apenas uma cláusula de guarda. Claro, elas são importantes, mas tendem a poluir o seu código. E se tivesse um outro jeito?

+ +

Agora tem.

+ +

Nas versões anteriores, throw era uma declaração. Agora, é uma expressão, o que nos permite disparar exceções em lugares como a segunda parte do operador “Null Coalescing” e em expressões condicionais.

+ +

Usando a throw expression, o exemplo acima fica simples assim:

+ + + +

Claro, não há nada nos impedindo de transformar o construtor em um “membro com corpo de expressão”:

+ + + +

Conclusão

+ +

Neste post, nós vimos algumas das novas features da sétima versão do C#. Isto foi apenas a primeira parte. Mais partes virão, nas quais eu planejo abordar todas (ou, ao menos, a maioria) das novas funcionalidades.

+ +

Como eu disse antes, C# 7 meio que continua o caminho iniciado no 6. O time de projetistas não saiu incluindo umas features novas e loucas apenas por colocar; em vez disso, eles cuidadosamente selecionaram aquelas que mais nos ajudariam a melhorar a qualidade do nosso código.

+ +

Tendo dito isso, eu realmente considero essa versão um pouco menos…tímida - por falta de palavra melhor - que a anterior. Algumas das funcionalidades que não mencionei hoje mostram que a linguagem está sendo levada à novas e interessantes direções, e eu penso que temos uma viagem bastante interessante à nossa frente.

+ +

Obrigado por ter lido até aqui, e fique ligado(a) para a parte 2!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/funcionalidades-csharp8/index.html b/pt/funcionalidades-csharp8/index.html new file mode 100644 index 00000000..a1769432 --- /dev/null +++ b/pt/funcionalidades-csharp8/index.html @@ -0,0 +1,647 @@ + + + + + + + + Funcionalidades do C# 8.0: Um Vislumbre do Futuro | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Funcionalidades do C# 8.0: Um Vislumbre do Futuro

+ +
+ +
+

+ +

C# 8.0 está chegando e vai trazer algumas funcionalidades muito interessantes. Vamos dar uma olhada no que o futuro reserva. +

+ +

NOTA: Eu escrevi este post originalmente para o blog da NDepend. Você pode clicar aqui para ler o artigo original no site deles, em inglês. Enquanto estiver por lá, baixe e experimente o NDepend.

+ +

Faz quase 20 anos desde que a Microsoft lançou a primeira versão da linguagem C#. De suas origens - quando muitos injustamente a consideravam uma mera cópia do Java - até agora, C# teve uma evolução notável.

+ +

Hoje em dia, o C# frequentemente aparece em listas das linguagens mais usadas e mais amadas. Você pode usá-lo para desenvolver aplicações para PC, dispositivos móveis e Web; você pode escrever código que será executado em todos os principais sistemas operacionais. Ou você pode entrar na onda da Internet das Coisas e escrever código para tornar sua casa inteligente. Nós vivemos em tempos interessantes para ser um desenvolvedor C#.

+ +

Se o presente já é animador, e o futuro? Será que é possível termos um vislumbre do que o futuro reserva para a linguagem?

+ +

É claro que sim. A Microsoft tem desenvolvido o C# de maneira transparante já faz um bom tempo. Você pode acessar o repositório do GitHub para ler (e participar, por que não?) nas discussões.

+ +

Hoje, nó abordaremos três propostas de funcionalidades para o C# 8.0: extension everything, implementações default em interfaces, e tipos de referência nuláveis.

+ +

Extension Everything

+ +

Extension everything - em tradução livre seria algo como “extensão em tudo” - é provavelmente a menos controversa das três propostas e também, de certa forma, a menos desenvolvida. Então eu achei que ela daria um bom ponto de partida.

+ +

Você provavelmente conhece métodos de extensão, introduzidos no C# 3.0, em 2017. Embora seja possível abusá-los, não há como negar que métodos de extensão, quando usados sabiamente, podem ser uma incrível adição ao kit de ferramentas do desenvolvedor C# - isso sem mencionar que eles são essenciais para o LINQ.

+ +

Porém, em algum momento você deve ter se perguntado: por que apenas métodos de extensão? E você não estaria só. Propriedades de extensão, por exemplo, tem sido um desejo dos desenvolvedores C# por muito tempo, como mostra esta questão de 2009 no Stack Overflow ou este tópico em um fórum de 2007(!).

+ +

Mas agora parece que a espera está finalmente chegando ao fim. Segundo Mads Torgersen, o program manager do time de design do C#, um estagiário da Microsoft propôs uma nova sintaxe para métodos de extensão que também possibilitará “outras coisas de extensão”.

+ +

Vamos ver o código

+ +

Se eu fosse você estaria ansioso para ver algum código Logo abaixo temos um exemplo de um método de extensão, utilizando a sintaxe atual:

+ + + +

Nada surpreendente aqui, certo? Na sintaxe original, um método de extensão é apenas um método estático em uma classe estática, com a palavra-chave this antes do primeiro parâmetro.

+ +

O problema é que esta sintaxe apenas funciona para métodos (e como poderia ser de outra forma, já que falar de “primeiro parâmetro” de uma propriedade nem sequer faz sentido).

+ +

É aqui que extension everything entra. A proposta apresenta é uma nova declaração de tipo chamada de “extension”:

+ + + +

O código acima é um exemplo; na data em que escrevo este post, o time do C# ainda não havia chegado à uma sintaxe definitiva.

+ +

Enfim, o exemplo mostra a criação de uma classe de extensão para o tipo int. Então nós declaramos uma propriedade do jeito que estamos acostumados, e é isso.

+ +

Agora o código chamador pode usar a propriedade normalmente:

+ + + +

Essa nova funcionalidade deverá suportar métodos, propriedades, operadores e membros estáticos, pelo menos no início; suporte a eventos e construtores pode ser adicionado posteriormente.

+ +

Você não será capaz de criar estado adicional para a instância original, i.e. criar um campo privado na classe de extensão. De acordo com Torgersen, isso iria requerer uma complexidade indesejada para rastrear o valor desse novo estado.

+ +

Status atual

+ +

Você pode acompanhar o desenvolvimento da feature na sua issue no GitHub.

+ +

Implementação default em interfaces.

+ +

Eu admito que fiquei surpreso - e não muito feliz - quando ouvi sobre essa feature pela primeira vez, em uma palestra Mads Torgersen ministrou em maio, na conferência Build 2017.

+ +

“E record types?”eu pensei. “E objetos imutáveis? O que nós vamos realmente ganhar são implementações em interfaces?”

+ +

Você provavelmente pode adivinhar o que essa funcionalidade é pelo seu nome: nós seremos capazes de adicionar implementações de métodos nas interfaces. Por exemplo:

+ + + +

Em C# 8.0, o código acima seria perfeitamente legal. Uma classe implementando a interface não precisaria disponibilizar uma implementação para o método. Se alguma implementação da interface decidir, em algum momento, que a implementação padrão não atende mais suas necessidades, então ela pode fazer sua própria implementação.

+ +

Além de métodos, também será permitido adicionar implementações em indexadores, propriedades e assessores de eventos. Membros estáticos como métodos, propriedades e indexadores também serão permitidos.

+ +

Estado de instância não será permitido nas interfaces, no entanto. Você será capaz de usar campos estáticos mas não campos de instância. Como consequência disso, propriedades automáticas também não serão permitidas, já que elas declaram um campo privado implicitamente.

+ +

Casos de uso

+ +

Conforme declarado na proposta da feature, o principal caso de uso para implementações padrão nas interfaces é possibilitar que uma interface possa evoluir de maneira segura. Você vai poder adicionar novos membros à interface, contato que você forneça uma implementação padrão, clientes existentes não serão forçados à implementá-los.

+ +

Atualmente, você poderia solucionar isso com um método de extensão, mas essa abordagem tem limites: e se você depois decidisse fornecer uma versão especializada do método para uma das implementações? Boa sorte.

+ +

É aí que as implementações padrão brilham.

+ +

Outra proposta de valor importação dessa feature tem relação com os sistemas Android e iOs. Já que tanto Java e Swift oferecem implementações padrão em interfaces, pode ser complicado envelopar APIs do Android e iOs que fazem uso desta funcionalidade. Com a oitava versão do C#, será possível adaptar tais APIs de maneira mais fiel.

+ +

As interfaces vão virar classes abstratas?

+ +

Mais ou menos, mas não realmente. Como você sabe, não há herança múltipla em linguagens coo C# e Java, o que significa que não é possível herdar de mais de uma classe. Por outro lado, uma classe é (e continuará sendo) capaz de implementar várias interfaces.

+ +

Status atual

+ +

Essa funcionalidade está sendo prototipada. Você pode seguir seu desenvolvimento na issue no GitHub.

+ +

Tipos de Referência Nuláveis

+ +

“O quê?”, você talvez esteja pensando. “Não seria ‘tipos de referência não-nuláveis’?” O nome dessa funcionalidade pode realmente confundir um pouco. Vou voltar a isso mais tarde, mas antes, vamos explicar a razão de uma feature como essa ser sequer considerada.

+ +

Eu aposto que você conhece a frase “o erro de um bilhão de dólares”. Na remota possibilidade de que você não conheça, ela ser refere à referência nula, e foi criada por ninguém mais ninguém menos que Sir Tony Hoare, o próprio criador da referência nula.

+ +

Mas por que null é tão ruim?

+ +

Existem várias possíveis respostas para essa pergunta mas o maior problema é, claro, o risco da famosa null-reference exception (também conhecida como null-pointer exception na Java-lândia). Já que tudo (“tudo” no contexto do C# significa tipos os tipos de referência) pode ser nulo, você sempre corre o risco de receber uma exceção quando tenta acessar algum membro de um objeto.

+ +

Um dos piores problemas que temos aqui é que a própria linguagem não oferece uma sintaxe que permita ao autor do código expressar sua intenção. Não tem como você dizer: “Este parâmetro nunca vai ser null” ou “Essa propriedade talvez seja null às vezes, e isso é OK”.

+ +

É comum que linguagens funcionais solucionem isso oferendo um tipo que representa o conceito de um valor potencialmente ausente, geralmente chamado de Maybe ou Option.

+ +

O time de design do C# decidiu contra uma abordagem desse tipo pois, de segundo eles, seria o mesmo que adicionar um novo tipo de null à linguagem, o que poderia tornar as coisas ainda mais complexas.

+ +

Vamos retomar a questão do nome. Você talvez esteja pensando que eu entendi ao contrário. Faz sentido falar sobre tipos de valor nuláveis, já que os tipos de valor são não-nuláveis por padrão. Mas no caso dos tipos de referência, não deveria, certo? Afinal de coisas, eles sempre foram nuláveis desde o início.

+ +

O pulo do gato é o seguinte: o time de design do C# - em uma decisão com uma boa dose de controvérsia - pretende tornar não-nulabilidade o novo padrão para os tipos de referência. Interpretando assim, a “nova” coisa seriam os tipos nuláveis.

+ +

Para manter a linguagem consistente, a proposta é que seja usada a mesma sintaxe que já existe para tipos de valor nuláveis - em outras palavras, o ponto de interrogação.

+ +

Chega de falar. Vamos ver código!

+ +

Eu imagino que usar uma classe “Pessoa” como exemplo é o equivalente de tocar “Stairway to Heaven” numa loja de instrumentos musicais: originalidade zero. Mas usar um exemplo mais elaborado seria uma distração desnecessária, então me dá um desconto desta vez.

+ +

Imagine que nós temos uma classe Person com uma propriedade Age do tipo int. Então, nós escrevemos o método a seguir:

+ + + +

Apesar do código acima compilar normalmente, ele é frágil já que p pode ser null. Você provavelmente faria bem em adicionar um if para tratar essa possibilidade, mas ninguém vai lhe obrigar a fazer isso. Você está complemente livre para deixar o código da forma como está.

+ +

C# 8 promete mudar isso ao tornar tipos de referência não-nuláveis por padrão. No mesmo exemplo, tentar acessar a propriedade Age seria seguro, já que p não poderia ser null.

+ +

Caso queira que p seja nulável, aí você teria que adicionar um ponto de interrogação, como eu já mencionei antes:

+ + + +

Agora que p pode ser null, tentar acessar Age não é mais seguro: você receberá um warning ao tentar fazer isso. Quer se livrar do aviso?

+ +

Apenas faça o que você (na melhor das hipóteses)já faz hoje e cheque por nulo::

+ + + +

Assim, uma análise de fluxo será realizada; caso a linha da atribuição seja alcançada, o compilador vai saber que p não pode ser nulo e vai te deixar em paz.

+ +

Outra possibilidade:

+ + + +

Em resumo, você tem várias opções. Assim que você conseguir convencer o compilador que seu código não tem risco de disparar uma null reference exception, o aviso vai embora.

+ +

Impedindo atribuição de nulável para não-nulável

+ +

A nova versão do C# também vai impedir atribuição de uma variável nulável para uma não-nulável, então o código a seguir também vai resultar em um aviso:

+ + + +

Essa funcionalidade virá acompanhada de um novo operador chamado de null-ignoring operator. Você vai usá-lo para dizer ao compilador: “Eu sei o que estou fazendo”. Haverá situações nas quais uma variável não pode ser nula de forma alguma, mas o compilador não vai ser capaz de inferir isso.

+ +

Um exemplo desses seria o uso do método string.IsNullOrEmpty():

+ + + +

O código acima vai gerar um warning, apesar de não ser possível que bar seja nula. É aí que esse operador vai ser útil:

+ + + +

É importante lembrar que quando usar esse operador, você basicamente está dizendo ao compilador: “Confie em mim! Eu sei o que eu estou fazendo.” Então, é bom você realmente saber o que está fazendo!

+ +

E retro-compatibilidade?

+ +

Eu sei o que você deve estar pensando agora. “Isso parece legal e tal, mas não vai dar problema com um monte de código existente?”

+ +

Bom, é claro que vai. E é por isso que essa será uma alteração opt-in, ativada a nível de cada projeto.

+ +

Status atual

+ +

Esta já está com o protótipo pronto. Caso se interesse, você pode baixar, instalar, e testar um preview agora mesmo.

+ +

Assim como as outras funcionalidades, você pode se antenar com o que está acontecendo por meio da issue no GitHub.

+ +

C# tem um futuro. E vai ser incrível.

+ +

Agora você sabe um pouco mais sobre três das funcionalidades que nós provavelmente ganharemos com a próxima versão da linguagem C#.

+ +

Como você pode ver, desenvolver a linguagem é um trabalho duro. Ela precisa permanecer compatível com as milhões (bilhões) de linhas de código escritas com ela nos últimos 17 anos. Ao mesmo tempo, para continuar sendo relevante, ela precisa suprir as necessidades de desenvolvedores que estão encarando desafiados que eram inimagináveis anos atrás. E o C# precisa fazer tudo isso sem perder sua essência: ser uma linguagem orientada a objeto, fácil e acessível.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/git-bisect-intro/index.html b/pt/git-bisect-intro/index.html new file mode 100644 index 00000000..309c9221 --- /dev/null +++ b/pt/git-bisect-intro/index.html @@ -0,0 +1,759 @@ + + + + + + + + Git Bisect: Uma Introdução Para Iniciantes | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Git Bisect: Uma Introdução Para Iniciantes

+ +
+ +
+

+ +

Foto por Yancy Min on Unsplash

+ +

Se você está tentando melhorar seu git-fu, uma boa dica é aprender o git bisect. O git tem a sua quota injusta de comandos complicados, isso é verdade. A boa notícia é que, diferente desses, o git bisect é bem fácil de entender e usar, pelo menos em sua forma mais básica. A notícia ainda melhor é que ele é super útil para ajudá-lo a corrigir bugs.

+ +

Pré-requisitos

+ +

Antes de começarmos, vamos rever alguns pré-requisitos que você precisará para acompanhar o post:

+
    +
  • Ter o git instalado em sua máquina
  • +
  • Conhecer pelo menos os comandos básicos do git
  • +
  • Ter o Node.js instalado na sua máquina (mais adiante você vai usar uma aplicação exemplo fornecida por mim, e ela é escrita em JavaScript).
  • +
+ +

Tem tudo isso? Show, vamos em frente.

+ +

O que é o Git Bisect? Por que você precisa dele?

+ +

O Git bisect é um comando que permite realizar uma busca binária no seu histórico de commits. Por que fazer isso?

+ +

Aqui está um cenário comum durante o desenvolvimento. Alguém relata um bug. Você vai dar uma olhada e descobre que, duas semanas atrás, a funcionalidade estava funcionando muito bem.

+ +

Para corrigir o bug, seria útil descobrir quando exatamente ele foi introduzido. Uma vez que você conhece um commit que você tem certeza que é “bom” - isto é, que não contém o bug - você podia ir fazendo o git checkout até lá, voltando um commit de cada vez e testando para ver se a aplicação funciona.

+ +

Isso iria funcionar, mas pode potencialmente levar muito tempo, dependendo do número de commits que você teria que verificar e onde está o problema. Para aqueles que se lembram das aulas de Ciência da Computação, a abordagem descrita acima é uma busca linear, que não é a melhor maneira de procurar um valor dentro de uma lista.

+ +

Sabe o que é mais eficiente? Uma pesquisa binária. Se você tem, digamos, 50 commits que você precisa verificar, e você testa o 25º e não encontra o bug, o que isso significa? Pode ignorar os primeiros 25 commits e continuar a sua pesquisa nos 25 commits posteriores. Continue o processo, sempre dividindo pela metade, e você encontrará o erro em muito menos verificações do que seria necessário com uma busca linear.

+ +

Fazer isso manualmente seria muito chato. E é aí que o git bisect ajuda. Ele tem uma sintaxe fácil que permite que você especifique tanto um commit bom quanto um ruim, e então o git irá executar as partições binárias pra você. Em cada passo, terá de testar a sua aplicação e informar o git se esse commit é bom ou ruim. Depois, o git calcula o próximo passo, leva você até lá e o processo termina quando encontrar o culpado.

+ +

Como usar o Git Bisect na prática?

+ +

Hora de aprender a usar o git bisect na prática. Para praticar este comando, é necessário um repositório com pelo menos alguns commits, e que tenha um bug. Ia levar um tempo para você configurar um repositório assim então eu já fiz um para você - pode falar, eu sei que eu sou legal.

+ +

Obtendo a aplicação de exemplo

+

Basta clonar este repositório do GitHub e você está pronto para começar.

+ +

O repositório contém uma aplicação JavaScript que implementa algumas das regras do String Calculator Kata proposto por Roy Osherov. Aqui está o que a aplicação deve fazer:

+
    +
  • depois de executá-la, a aplicação pedirá uma lista de números, separados por vírgula;
  • +
  • o usuário fornece os números;
  • +
  • a soma dos números é apresentada.
  • +
  • Os números maiores que 1000 são ignorados. Assim, a string “1,2,1000” deve produzir o resultado 1003, mas “1,2,1001” deve resultar em 3.
  • +
  • os números negativos não devem ser permitidos. Se informar um ou mais números negativos, a aplicação deve lançar um erro com a mensagem “Negativos não permitidos”, seguido dos números negativos que foram introduzidos.
  • +
+ +

Depois de clonar o repositório, vamos testar a aplicação. Acesse sua pasta através da linha de comandos, execute node index.js e, quando lhe forem pedidos os números, digite “1,2,3” e dê enter.

+ +

Vixi, parece que deu ruim.

+ +
node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: .
+    at C:\repos\git-bisect-intro\index.js:11:11
+    at [_onLine] [as _onLine] (node:internal/readline/interface:423:7)
+    at [_line] [as _line] (node:internal/readline/interface:886:18)
+    at [_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1264:22)
+    at ReadStream.onkeypress (node:internal/readline/interface:273:20)
+    at ReadStream.emit (node:events:513:28)
+    at emitKeys (node:internal/readline/utils:357:14)
+    at emitKeys.next (<anonymous>)
+    at ReadStream.onData (node:internal/readline/emitKeypressEvents:64:36)
+    at ReadStream.emit (node:events:513:28)
+
+Node.js v18.12.1
+
+

A aplicação não funciona. Ela gera o erro “negatives not allowed” (negativos não permitidos) mesmo que nenhum negativo tenha sido inserido. Se você quiser ver a aplicação funcionando, facilitei as coisas para você: Criei uma tag chamada good-commit que faz referência a um ponto no histórico que é garantidamente bom. Basta ir até lá e verificar:

+ +

git checkout good-commit

+ +

Após executar o comando acima, é possível que você veja algumas mensagens sobre detached HEAD e outras coisas. Simplesmente ignore-as. Execute a aplicação novamente e voilá:

+ +
Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+ +

Massa, agora vamos testar a regra de que números maiores do que 1000 devem ser ignorados:

+ +
Enter a list of numbers separated by comma:
+1,2,1000, 1001
+The sum of the entered numbers is 1003.
+
+ +

Show de bola. Como esperado, o número 1000 é considerado, mas 1001 é ignorado. Para um teste final, vamos verificar a proibição de números negativos:

+ +
Enter a list of numbers separated by comma:
+1,2,3,-5,-4,-7
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -4, -7.
+
+ +

Muito bom. Agora, vamos para a próxima etapa. Mas, primeiro, execute git checkout main para retornar ao último commit.

+ +

Hora de arregaçar as mangas

+

Para começar a usar o comando git bisect, você precisa iniciar uma sessão bisect. Para isso, basta executar o comando git bisect start. Em seguida, você verá a seguinte mensagem:

+ +

status: waiting for both good and bad commits

+ +

Agora, você precisa informar ao git sobre um commit que é conhecido por ser “bom” - ou seja, não contém o bug - e um commit que contém o bug. Vamos começar com o bom:

+ +

git bisect good good-commit

+ +

Como eu disse antes, criei uma tag para apontar para um commit bom conhecido para facilitar as coisas para você. Mas você não está restrito às tags quando se trata de apontar para um commit em uma sessão de bissecção. Os nomes de branches também funcionam, assim como os SHAs dos commits e praticamente todas as referências que levam a um commit.

+ +

De qualquer forma, depois de executar o comando, você verá o seguinte: +status: waiting for bad commit, 1 good commit known

+ +

Agora é hora de apontar para um commit ruim. Tenho certeza de que você já adivinhou a sintaxe: git bisect bad <REFERENCE-TO-COMMIT>. Mas como o commit em que estamos - em outras palavras, a ponta do main - é sabidamente ruim, você pode simplesmente executar:

+ +

git bisect bad

+ +

Agora começa a diversão! O Git exibirá uma mensagem, mostrando o status da operação de bissecção. Ele lhe dirá quantas revisões restam para testar, quantas etapas seriam necessárias e para qual commit ele “transportou” você:

+ +
Bisecting: 11 revisions left to test after this (roughly 4 steps)
+[e159647d4d142c410894aaf10c1e11e2208848d7] Edit to negative rule
+
+ +

Seu trabalho agora é testar a aplicação e informar ao git se esse é um commit bom ou ruim. Então, vamos executar o node index.js e fornecer alguns números:

+
Enter a list of numbers separated by comma:
+1,2,3
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: .
+
+ +

Cortei parte da saída para ser breve, mas de qualquer forma: a aplicação não está funcionando. Então, diga isso ao git:

+ +

git bisect bad

+ +

Isso o levará a um commit diferente:

+ +
Bisecting: 5 revisions left to test after this (roughly 3 steps)
+[0b8f71999bed054d8a95d9da3be6f0c831074cd7] Update README.md - Commit 6
+
+ +

Vamos repetir o teste com node index.js:

+ +
Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+ +

Fantástico! Neste commit, a aplicação parece funcionar bem. Vamos fazer um teste diferente, usando números negativos:

+ +
Enter a list of numbers separated by comma:
+1,2,3,-5,-4,-10
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -4, -10.
+
+ +

Perfeito: ele está gerando um erro, como deveria fazer nesse cenário. Portanto, execute git bisect good para marcar esse commit como bom.

+ +
Bisecting: 2 revisions left to test after this (roughly 2 steps)
+[e6413a915c7ca92871394b01a8497c8df3fc46ae] Update README.md - Commit 9
+
+ +

Mais um commit, mais um teste:

+ +
node index.js
+Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+

Vamos testar os negativos:

+ +
node index.js
+Enter a list of numbers separated by comma:
+10,20,-5
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5.
+
+ +

Tudo parece bem, vamos marcá-lo como bom: +git bisect good

+ +

E o resultado:

+
Bisecting: 0 revisions left to test after this (roughly 1 step)
+[053207649aefdb09cd255567df673cadbe2e38e3] Restore README
+
+ +

Estamos chegando perto! Vamos testar:

+
node index.js
+Enter a list of numbers separated by comma:
+1,2,3
+The sum of the entered numbers is 6.
+
+node index.js
+Enter a list of numbers separated by comma:
+1,2,3,-5,-6
+node:internal/readline/emitKeypressEvents:74
+            throw err;
+            ^
+
+Error: Negatives not allowed: -5, -6.
+
+ +

Marcando-o como bom: git bisect good. E, tcharam!, aqui está nossa resposta:

+ +
e159647d4d142c410894aaf10c1e11e2208848d7 is the first bad commit
+commit e159647d4d142c410894aaf10c1e11e2208848d7
+Author: Carlos Schults <carlos.schults@gmail.com>
+Date:   Tue Jan 9 08:53:47 2024 -0300
+
+    Edit to negative rule
+
+ index.js | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+ +

E agora?

+

Ok, agora você sabe que o commit e159647d4d142c410894aaf10c1e11e2208848d7 foi o que introduziu o bug. O que você deve fazer agora?

+ +

Em resumo, você precisa ver os detalhes desse commit, para saber quais alterações ele faz e entender o que causou o problema. Vamos usar o comando git show para isso:

+ +

git show e159647d4d142c410894aaf10c1e11e2208848d7

+ +

Esse comando exibirá várias informações sobre o commit, incluindo autor, data e mensagem. Vou reproduzir apenas a parte que me interessa, que é a diferença:

+ +
diff --git a/index.js b/index.js
+index 5f351e0..4e65e0c 100644
+--- a/index.js
++++ b/index.js
+@@ -6,7 +6,7 @@ const readline = require('readline').createInterface({
+   readline.question('Enter a list of numbers separated by comma:\n', numbers => {
+     let integers = numbers.split(',').map(x => parseInt(x) || 0);
+     let negatives = integers.filter(x => x < 0);
+-    if (negatives.length > 0) {
++    if (negatives.length >= 0) {
+       throw new Error(`Negatives not allowed: ${negatives.join(', ')}.`);
+     }
+
+ +

E agora como uma imagem, para que você possa ver as cores:

+ +

+ +

Como você pode ver, esse commit fez uma alteração na instrução if que testa números negativos, adicionando um sinal de igual à comparação. Dessa forma, o erro será lançado independentemente do fato de o array negatives ter elementos.

+ +

Agora que você sabe como o erro foi introduzido, é muito fácil corrigi-lo. Para encerrar a sessão de bisect, execute git bisect reset. Assim, você voltará ao commit/branch onde você estava originalmente.

+ +

Uma observação sobre “bom” e “ruim”

+ +

Leitores atentos devem ter notado que, embora esse comando use termos como “bom”, “ruim” e “bug”, não há nada que o impeça de usar o git bisect para descobrir o ponto no tempo em que qualquer propriedade da base de código foi alterada. Afinal de contas, o Git não tem como saber como o seu código deveria funcionar; foi você, o tempo todo, quem o testou.

+ +

Até mesmo a documentação do comando reconhece esse fato:

+ +
+

Às vezes, você não está procurando o commit que introduziu uma quebra, mas sim um commit que causou uma alteração entre algum outro estado “antigo” e o estado “novo”. Por exemplo, você pode estar procurando o commit que introduziu uma correção específica. Ou pode estar procurando o primeiro commit em que os nomes de arquivo do código-fonte foram finalmente convertidos para o padrão de nomenclatura da sua empresa. Ou qualquer outra coisa.

+
+ +

Nesse cenário, seria estranho usar os termos “good” e “bad”. A boa notícia é que, em vez disso, você pode usar new e old: o commit novo é aquele que contém a propriedade que você está procurando, e o antigo não contém essa propriedade.

+ +

Para usar essa terminologia, basta iniciar uma sessão de bisect normalmente e, em seguida, executar git bisect old <COMMIT> para indicar o commit antigo e git bisect new <COMMIT> para indicar o novo.

+ +

Lembre-se de que você pode usar good/bad ou old/new, mas não pode misturar os dois. A qualquer momento durante uma sessão, você pode executar git bisect terms para ser lembrado dos termos que está usando.

+ +

O comando é ainda mais flexível do que isso: você pode escolher seus próprios termos! Basta iniciar uma sessão executando o seguinte:

+ +

git bisect start --term-old <term-old> --term-new <term-new>

+ +

Git Bisect: Quais Os Próximos Passos?

+ +

Não são dados estatísticos, mas, a partir de minhas observações, eu diria que o git bisect é um comando subutilizado. O que é muito triste, considerando que o git bisect é a) incrivelmente útil e b) fácil de entender e usar, pelo menos em seu caso de uso mais básico.

+ +

Se você já estiver familiarizado com os comandos mais comuns do git - ou seja, status, log, commit, add, pull, push, checkout - e quiser dar um passo adiante, aprender o git bisect é um ótimo ponto de partida.

+ +

Então, você aprendeu o básico sobre esse comando com a introdução que escrevi. Massa demais, mas o que você deve fazer a partir daqui? Tenho algumas sugestões:

+ +
    +
  • Coloque-o em prática o mais rápido possível. Mesmo que não esteja caçando bugs no momento, pense em alguma característica da sua aplicação e encontre o commit em que ela foi introduzida usando o git bisect.
  • +
  • Aprofunde-se mais no comando e procure casos de uso mais avançados. Por exemplo, é possível automatizar o git bisect para que você não precise testar manualmente a fim de separar os commits bons dos ruins!
  • +
  • Leia a documentação do git bisect. Volte a ela de tempos em tempos, e você certamente aprenderá algo novo e útil.
  • +
+ +

Isso é tudo por hoje. Espero que você tenha gostado e agradeço muito qualquer feedback. Obrigado pela leitura!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/git-criar-branch.html b/pt/git-criar-branch.html new file mode 100644 index 00000000..ae68205e --- /dev/null +++ b/pt/git-criar-branch.html @@ -0,0 +1,623 @@ + + + + + + + + Git Criar Branch: 4 Maneiras Diferentes | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Git Criar Branch: 4 Maneiras Diferentes

+ +
+ +
+

+ +

NOTA: Eu escrevi este post originalmente para o blog da Cloudbees. Você pode conferir o artigo original, em inglês, no site deles. Eu optei por deixar os exemplos de código em inglês.

+ +

Se você trabalha escrevendo software, posso dizer com segurança que você conhece o Git. A ferramenta criada por Linus Torvalds tornou-se sinônimo de controle de versão. E, sem dúvida, um dos melhores recursos do Git é a forma como ele elimina a dificuldade de ramificar (branch) e mesclar (merge). Há várias maneiras de criar uma branch (branch) no Git. Neste artigo, vamos analisar algumas delas. Então, a gente finaliza com uma reflexão sobre o modelo de branching do Git, e a ideia de branching em geral.

+ +

Criando Um Branch A Partir de Main

+ +

Você cria branches no Git, como era de se esperar, usando o comando branch. Como muitos outros comandos do Git, o branch é muito poderoso e flexível. Além de criar branches, ele também pode ser usado para listá-las e excluí-las, e você pode personalizar ainda mais o comando empregando uma ampla lista de parâmetros. Começaremos com a primeira maneira de criar uma branch. Digamos que você queira criar uma nova pasta chamada “my-app”, entrar nela e iniciar um novo repositório Git. É exatamente assim que você faria isso:

+ +
mkdir my-app
+cd my-app
+git init
+
+ +

Agora você tem um repositório Git novo e vazio. Mas repositórios vazios são chatos. Então, que tal criar um novo arquivo markdown com “Hello World!” escrito nele?

+ +
echo Hello World! > file.md
+
+ +

Se você executar git status, verá uma mensagem dizendo que o arquivo não foi rastreado:

+ +
$ git status
+On branch main
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+    file.md
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+

Arquivos não rastreados não têm graça nenhuma. Então, bora rastreá-los:

+ +
git add file.md
+
+ +

E, finalmente, vamos criar nosso primeiro commit:

+ +
git commit -m "First commit"
+
+ +

Agora temos um repositório com uma branch, que tem exatamente um commit. Isso pode não parecer a coisa mais empolgante do mundo (porque realmente não é), mas certamente é menos entediante do que ter um repositório sem nenhum commit, certo? Agora, digamos que, por qualquer motivo, você precise alterar o conteúdo do arquivo.

+ +

Mas você não está muito a fim de fazer isso. E se algo der errado e você, de alguma forma, estragar o belo e puro conteúdo do seu arquivo? (Sim, eu sei que é apenas um arquivo com “Hello World!”, mas use os maravilhosos poderes de sua imaginação e pense no arquivo como um proxy para um projeto muito mais complexo). A solução para esse dilema é, obviamente, criar uma nova branch:

+ +
git branch exp
+
+ +

Portanto, agora temos uma nova branch chamada “exp”, para experimentação. Algumas pessoas que estão acostumadas a usar sistemas de controle de versão diferentes, especialmente os centralizados, poderiam dizer que as branches têm o mesmo “conteúdo”. No entanto, isso não é totalmente exato quando se trata do Git. Pense nas branches como referências que apontam para um determinado commit.

+ +

Criando uma branch a partir de um commit

+ +

Suponha que, por qualquer motivo, desistimos do nosso experimento sem adicionar um único commit à nova branch. Vamos voltar para main e excluir a branch exp:

+ +
git checkout main
+git branch -d exp
+
+ +

Agora que voltamos a ter uma única branch, vamos adicionar alguns commits a ela, para simular o trabalho que está sendo feito:

+ +
echo a new line >> file.md
+git commit -a -m "Add a new line"
+echo yet another line >> file.md
+git commit -a -m "Add yet another line"
+echo one more line >> file.md
+git commit -a -m "Add one more line"
+echo this is the last line i promise >> file.md
+git commit -a -m "Add one last line"
+
+ +

Imagine que, depois de fazer todo esse “trabalho”, você descobre que, por qualquer motivo, precisa voltar no tempo para quando havia apenas duas linhas no arquivo e criar novas alterações a partir de então. Mas, ao mesmo tempo, você precisa preservar o progresso que já fez. Em outras palavras, você deseja criar uma branch a partir de um commit anterior. Como você faria isso? No Git, cada commit tem um identificador exclusivo. Portanto, você pode ver isso facilmente usando o comando git log. Para criar uma nova branch com base em um commit específico, basta passar seu hash como parâmetro para o comando branch:

+ +
git branch new-branch 7e4decb
+
+ +

Além disso, na maioria das vezes, você nem precisa do hash inteiro. Apenas os primeiros cinco ou seis caracteres são suficientes.

+ +

Criar Uma Branch a Partir de Uma Tag

+ +

Se você tem um pouco mais de experiência com o Git, deve estar familiarizado com o conceito de tags. Você usa tags para indicar que um determinado commit é importante ou especial de alguma forma. Por exemplo, as tags são geralmente usadas para indicar as versões de um produto. Se você está trabalhando em seu aplicativo há algum tempo e acredita que é hora de lançar a versão 1.0, o que você normalmente faz é aumentar os números de versão sempre que necessário, commitando essas alterações e, em seguida, adicionando uma tag a esse ponto específico no tempo. Para criar uma tag, você normalmente executa algo como o seguinte:

+ +
git tag -a v1.0 -m "First major version"
+
+ +

O parâmetro “-a” indica que essa será uma tag do tipo annotated. Ao contrário de uma tag lightweight, essa é um objeto Git completo, contendo informações como o nome e o e-mail do committer, o registro de data e hora e uma mensagem. Agora você tem uma tag, uma indicação de que esse ponto específico da história é especial e tem um nome.

+ +

Legal. Você pode continuar trabalhando, como de costume, criando e enviando alterações que farão parte da versão 1.1. Até que chega um relatório de bug. Alguns clientes que foram atualizados para a versão 1.0 do produto dizem que um recurso de importação não está funcionando como pretendido.

+ +

Bem, teoricamente, você poderia corrigir o bug na branch main e fazer o deploy da correção. Mas, nesse caso, os clientes receberiam recursos que possivelmente não foram testados e estão incompletos. Isso não é bom.

+ +

Então, o que você faz?

+ +

A resposta: Você cria uma nova branch a partir da tag que criou para indicar a versão principal. Você corrige o problema lá, faz o build e deploy. E, provavelmente, você deve mesclar (merge) a correção de volta à branch main depois, para que as próximas versões contenham a correção. Como você faria isso? Fácil:

+ +
git branch <NAME-OF-THE-BRANCH> <TAG>
+
+ +

Mais especificamente, usando nosso exemplo anterior:

+ +
git branch fix-bug-123 v1.0
+
+ +

Depois disso, você pode ir para sua nova branch como de costume. Ou melhor ainda, você pode fazer tudo em uma única etapa:

+ +
git checkout -b fix-bug-1234 v1.0
+
+ +

Criando uma branch no estado “DETACHED HEAD”

+ +

Alguma vez você já desejou voltar no tempo? Com o Git, isso é possível… pelo menos no que diz respeito aos arquivos em nosso repositório. Você pode, a qualquer momento, dar checkout em um commit se souber seu hash:

+ +
git checkout <SHA1>
+
+ +

Depois de executar isso, o Git mostrará uma mensagem meio esquisita:

+ +
You are in 'detached HEAD' state. You can look around, make experimental
+changes and commit them, and you can discard any commits you make in this
+state without impacting any branches by performing another checkout.
+
+ +

Em tradução livre:

+ +
Você está no estado 'detached HEAD'. Você pode dar uma olhada, fazer alterações experimentais
+experimentais e fazer o commit delas, e você pode descartar quaisquer commits que fizer nesse
+estado sem afetar nenhuma branch, executando outro checkout.
+
+ +

Quando você faz o checkout de um commit, entra em um estado especial chamado, como você pode ver, “detached HEAD”, ou “cabeça desanexada.” Embora você possa fazer commit de alterações nesse estado, esses commits não pertencem a nenhuma branch e ficarão inacessíveis assim que você mudar de branch. Mas e se você quiser manter esses commits? A resposta, sem surpresa, é usar o comando checkout novamente para criar uma nova branch:

+ +
git checkout <sha1> #now you're in detached head state
+# do some work and stage it
+git commit -m "add some work while in detached head state"
+git branch new-branch-to-keep-commits
+git checkout new-branch-to-keep-commits
+
+ +

E, é claro, agora você já sabe que pode escrever as duas últimas linhas como um único comando:

+ +
git checkout -b new-branch-to-keep-commits
+
+ +

Muito fácil, certo?

+ +

Só porque você pode… não significa que você deva

+ +

O modelo de branch do Git é um dos seus principais atrativos. Ele transforma em uma moleza o que em outros sistemas de controle de código-fonte é um processo lento e doloroso. Pode-se dizer que o Git democratizou com sucesso a ramificação.

+ +

Mas há um sério perigo. Devido ao baixo custo de trabalhar com branches no Git, alguns desenvolvedores podem cair na armadilha de trabalhar com branches de vida extremamente longa ou empregar fluxos de trabalho ou modelos de branch que atrasam a integração.

+ +

Nós, como setor, já passamos por isso. Fizemos isso. Não funciona. Em vez disso, adote fluxos de trabalho que utilizem branches de vida extremamente curta. Você terá uma sandbox segura para codificar sem medo de quebrar coisas ou desperdiçar o tempo de seus colegas de trabalho. Mas isso faz com que você se pergunte: “Como posso fazer deploy de código com recursos parcialmente concluídos?” Nesse caso, tem uma ótima alternativa: as ferramentas de feature flag.

+ +

As branches do Git são uma ferramenta poderosa. Use-as com sabedoria e não abuse. E quando não forem suficientes, empregue entrega contínua/integração contínua juntamente com ferramentas de feature flag para que suas aplicações possam chegar ao próximo nível.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/git-historico-bonito/index.html b/pt/git-historico-bonito/index.html new file mode 100644 index 00000000..940fa210 --- /dev/null +++ b/pt/git-historico-bonito/index.html @@ -0,0 +1,713 @@ + + + + + + + + Fazendo Seu Histórico Git Ficar Bonitão Com Amend e Rebase | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Fazendo Seu Histórico Git Ficar Bonitão Com Amend e Rebase

+ +
+ +
+

+ +

Foto por Yancy Min no Unsplash

+ +

Você faz parte de uma equipe de software de pequeno a médio porte e morre de inveja do histórico de commits das pessoas que trabalham com você. Elas produzem histórias limpas e bem estruturadas com mensagens de commit bem escritas. A sua, em comparação, é um desastre, cheia de descrições como “corrigir erro de digitação”, “adicionar arquivo esquecido” e assim por diante. Você queria entender como eles fazem isso.

+ +

A resposta é simples: eles trapaceiam. Seguinte: eles provavelmente cometem tantos erros quanto você, mas usam as features do Git para escondê-los. Eles então apresentam uma história mais limpa e bonita para o mundo.

+ +

Algumas ferramentas de controle de versão tratam o histórico do projeto como se fosse esta coisa super sagrada. Git não é assim. Ele lhe dá o poder de reescrever a história como você quiser. Tanto poder que você pode até se dar mal se não tiver cuidado.

+ +

Neste post, eu lhe mostrarei como usar amend e rebase interativo para fazer sua história de commits no Git ficar bonitona antes de publicá-la. Não vai ter muita teoria; eu o acompanharei através de alguns cenários comuns, mostrando como eu iria resolvê-los.

+ +

Antes de terminar, vou ensiná-lo a não atirar no seu pé com estes comandos. Como explicarei, amend e rebase são ações destrutivas, e tem situações em que você não deve executá-las.

+ +

Requisitos

+

Para acompanhar este posto, presumo que você:

+ +
    +
  • sabe trabalhar com a linha de comando
  • +
  • tem o Git instalado em sua máquina
  • +
  • conhece ao menos os comandos básicos do Git
  • +
+ +

Ao escrever este post, estou no Windows, usando a versão Git 2.38.1.windows.1* e digitando meus comandos no Git Bash. Se você estiver no Linux ou OSX, acho que tudo funcionará da mesma forma, mas eu não testei.

+ +

Definindo o VS Code como seu editor de texto predefinido

+

Apenas um último detalhe antes da gente começar pra valer. Alguns dos comandos que você verá ao longo deste post exigirão que você edite e salve um arquivo de texto. Eles fazem isso abrindo seu editor de texto padrão conforme configurado em seu arquivo de configuração Git e esperando até que você edite, salve e feche o arquivo.

+ +

Se você estiver no Windows como eu, usando o Git Bash, seu editor padrão será o Vim. Vim é um editor de texto de linha de comando, e algumas pessoas o acham intimidante. Embora aprender Vim exija algum trabalho, não é tão difícil de começar, e eu recomendaria que você investisse algum tempo para aprender pelo menos os comandos mais básicos - especialmente como sair!

+ +

Entretanto, Git permite que você escolha outros editores de texto como seu padrão. Se você tiver o Visual Studio Code instalado e quiser usá-lo, execute o seguinte comando:

+ +

git config --global core.editor "code --wait"

+ +

Reescrevendo História: 3 Cenários comuns

+

Vou mostrar alguns cenários comuns nos quais você poderá se encontrar, nos quais a reescrita da história o salvará.

+ +

Minha Mensagem de Commit Tem Um Erro

+

Você está correndo para corrigir este bug de alta prioridade. Depois de horas de depuração exaustiva, você encontra o código ofensivo, faz a correção e faz o commit da mudança.

+ +

Só então você vê que cometeu um erro de digitação. Como corrigir isso?

+ +

Vamos começar criando um repositório para que você possa praticar:

+ +

git init

+ +

Agora, vamos adicionar um novo arquivo e commitar:

+ +
touch file.txt
+git add file.txt
+git commit -m "fix async request in getUsers() functino"`
+
+ +

Execute git log--oneline para ver sua mensagem de commit. Você verá algo como isto:

+ +

+ +

Preste atenção no identificador do commit, e talvez até mesmo anote-o em algum lugar; será importante mais tarde. (O seu será diferente do meu).

+ +

De qualquer forma, sua mensagem tem um erro. Como você a corrige?

+ +

Basta executar o comando git commit --amend, exatamente assim. O Git abrirá seu editor de texto e esperará que você edite a mensagem do commit:

+ +
fix async request in getUsers() functino
+
+# Please enter the commit message for your changes. Lines starting
+# with '#' will be ignored, and an empty message aborts the commit.
+#
+# Date:      Tue Jan 10 19:14:17 2023 -0300
+#
+# On branch master
+#
+# Initial commit
+#
+# Changes to be committed:
+#   new file:   file.txt
+#
+
+ +

A primeira linha é a mensagem de commit propriamente dita. As linhas que começam com o “#” são comentários e serão ignoradas. Basta corrigir o erro, salvar e fechar o arquivo de texto, e você terá uma nova mensagem de commit. Execute o git log --oneline novamente para vê-lo:

+ +

+ +

Você notará que a identificação (SHA-1) do commit é agora diferente do que era antes - e também diferente daquela da imagem acima. Voltarei a este assunto mais tarde.

+ +

Por enquanto, você alterou com sucesso sua mensagem de commit. Parabéns!

+ +

Esqueci de Incluir um Arquivo

+

Às vezes você tem vários arquivos alterados e quer commitar alguns, mas não todos. Na sua pressa, você deixa um ou mais arquivos para trás. Como corrigir isso?

+ +

amend ao resgate novamente.

+ +

Para simular esta situação, vamos criar um novo arquivo e também adicionar uma nova linha ao existente:

+ +
touch file2.txt
+echo 'New line' >> file.txt
+
+ +

Um erro comum aqui é fazer o commit com a opção -a, pensando que ela incluirá ambos os arquivos:

+ +

git commit -am "atualizar arquivo e adicionar arquivo2"

+ +

Execute o comando acima. Em seguida, execute o comando git status. Este é o resultado que você vai obter:

+ +
On branch master
+
+Untracked files:
+
+  (use "git add <file>..." to include in what will be committed)
+
+        file2.txt
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+

Corrigir a situação é fácil. Primeiro, você rastreia ou adiciona ao index o arquivo esquecido:

+ +

git add file2.txt

+ +

Em seguida, utilize novamente o git commit -amend. Seu editor irá abrir, mas neste caso, não há nada de errado com a mensagem. Basta fechar o editor e pronto: agora você tem um commit “emendado” que inclui o arquivo anteriormente esquecido.

+ +

Mas se você se parece comigo, provavelmente se sentiu meio trouxa tendo aberto seu editor de texto sem nenhuma razão.

+ +

Felizmente, você nem sempre tem que fazer isso. Quando você quer apenas adicionar um ou mais arquivos faltantes sem alterar a mensagem de commit, você pode usar a opção --no-edit, desta forma:

+ +

git commit --amend --no-edit

+ +

Desta forma, Git não abrirá seu editor de texto, mantendo a mensagem de commit original.

+ +

Quero Mesclar Vários Commits Em Um Só

+

A fusão de vários commits em um só é uma operação chamada “squashing”. Mas por que você iria querer fazer isso?

+ +

Bem, tudo se resume ao seu estilo Git. Eu gosto de fazer pequenos commits, com muita freqüência. Depois, quando estou prestes a torná-los públicos (por exemplo, ao abrir um pull request) eu os junto em um único commit, com uma mensagem bem escrita.

+ +

Esta também é uma exigência comum dos mantenedores de projetos de código aberto, por isso é uma boa habilidade pra se ter. Vamos aprender como fazer isso.

+ +

Primeiro, vamos criar três commits:

+ +
git commit --allow-empty -m "empty commit" -m
+git commit --allow-empty -m "empty commit 2" -m
+git commit --allow-empty -m "empty commit 3" -m
+
+ +

Ter de ficar criando arquivos inúteis para poder commitar é tedioso. É por isso que eu estou usando a opção --allow-empty, que me permite criar commits vazios.

+ +

Agora, digamos que eu preciso juntar os três commits acima em um só. Para fazer isso, precisarei rebaseá-los interativamente. Ao fazer um rebase interativo, você pode realizar tarefas como:

+ +
    +
  • Reordenar commits
  • +
  • Abandonar um ou mais commits
  • +
  • Mudar suas mensagens
  • +
  • Mesclar um ou mais commits
  • +
+ +

Agora vem a parte que pode ser confusa, então preste atenção, por favor. Já que vamos trabalhar com os três últimos commits, dizemos que os estamos rebaseando em cima do quarto commit (contando a partir do último.)

+ +

Então, use o comando git log --oneline -4 para exibir os últimos quatro commits e depois copie o SHA-1 do quarto commit do resultado:

+ +

+ +

Copie o identificador desse commit e passe-o para o comando de rebase, assim:

+ +

git rebase -i 45f90ca

+ +

Naturalmente, seu valor real de SHA-1 será diferente. Mas há uma maneira mais fácil:

+ +

git rebase -i HEAD~3

+ +

Para simplificar, HEAD aqui significa o último commit, e ~3 significa “três commits antes deste”.

+ +

Após executar um dos dois comandos acima, seu editor irá abrir, mostrando um arquivo de texto que contém as mensagens dos três commits que queremos reorganizar, cada um precedido pela palavra “pick”. E depois disso, um conjunto de instruções:

+ +

+ +

Observe que os commits aqui não estão na ordem em que você está acostumado a vê-los no Git. Em vez de estarem em ordem cronológica inversa, eles estão em ordem cronológica direta, e há uma razão para isso.

+ +

Cada linha que você vê acima é um comando que o Git executará quando você confirmar a operação de rebase. Há vários comandos disponíveis, e o pick é o comando padrão. Isso significa simplesmente que o commit será mantido como está. Você pode usar drop para remover um commit, reword para editar uma mensagem de commit, e assim por diante.

+ +

O comando que vamos utilizar é squash. Basta substituir a palavra pick por squash no segundo e terceiro commits, desta forma:

+ +
pick dd25df9 empty commit # empty
+squash c68804f empty commit 2 # empty
+squash a76fd60 empty commit 3 # empty
+
+ +

O comando squash mescla um commit com aquele anterior. Assim, o terceiro será fundido com o segundo, que será fundido com o primeiro. E é por isso que o primeiro precisa ser picked.

+ +

Depois de editar o texto como eu lhe disse, salve e feche o arquivo. Quando você fizer isso, seu editor será aberto novamente. Desta vez, você será solicitado a escrever uma mensagem de commit para o novo commit que irá surgir:

+ +

+ +

Substituir o conteúdo do arquivo por “this is now a single commit”. Salve e feche o arquivo.

+ +

Finalmente, vamos ver o resultado:

+ +

git log --oneline

+ +

Isto é o que você deveria ver:

+ +

+ +

Como você pode ver, os três commits vazios foram substituídos por um único commit. Você realizou com sucesso sua primeira operação de squash. Parabéns!

+ +

Quando Não Se Deve Mexer Com a História

+

Antes de terminar, vamos entender quando a mudança da história é problemática.

+ +

Primeiro, entenda que tanto amend quanto rebase produzem mudanças destrutivas. É como se eles estivessem destruindo a história e criando uma nova.

+ +

Então, imagine que você junta três commits (que já haviam sido enviados para o servidor) e depois faz o push desse novo commit para dentro do repositório remoto (você teria que forçar o push para que isso funcionasse, a propósito.) Mas enquanto você estava trabalhando, seu colega de trabalho tinha criado um branch novo a partir do (o que era então) último commit.

+ +

Esse commit não existe mais (tecnicamente, isso não é bem verdade, mas vamos fingir por um minuto que é), o que significa que eles não serão capazes de simplesmente dar o push das suas mudanças. Eles terão que puxar seus novos commits e então realizar um merge potencialmente complexo a fim de conseguir que as coisas sejam ordenadas.

+ +

Portanto, a regra de ouro é nunca reescreva a história da qual outras pessoas dependem. O que isto significa em específico depende do workflow de branches que você e sua equipe utilizam.

+ +

Se você usar trunk-based development, nunca reescreva o branch master/main. O mesmo é verdade se seu trabalho com GitHub Flow. Se você usa o git-flow, isso significa nunca reescrever os branches permanentes, ou seja, master/main e develop.

+ +

OK, Eu Menti: Toma Um Pouco De Teoria

+

Ao longo deste artigo, usei expressões como “mudar a mensagem do commit”, “juntar múltiplos commits em um”, e assim por diante.

+ +

Tecnicamente falando, tudo isso eram mentiras. Quando você utiliza comandos como git commit --amend ou rebase -i, você não está mudando nada. O que Git está fazendo é criar novos commits.

+ +

Lembra-se quando você usou o amend pela primeira vez e eu disse que era relevante que o commit agora tinha um novo identificador? Acontece que aquele era um commit completamente novo, e o antigo ainda está por aí!

+ +

O mesmo vale para a operação de rebase. Quando você “mescla três commits em um”, não é isso que está acontecendo. Em vez disso, Git cria um novo commit e atualiza a referência do branch, de modo que aponte para o novo commit. Os três commits antigos ainda estão lá (pelo menos por algum tempo), mas como nenhum branch aponta para eles, eles são inalcançáveis - a menos que você consiga obter de alguma forma os valores SHA-1 deles.

+ +

A imagem a seguir representa o que realmente aconteceu depois que você deu squash nos seus commits:

+ +

+ +

Agora, vamos ver o cenário após o squash:

+ +

+ +

Como você pode ver, há agora um novo commit, em laranja, que é o resultado de “mesclar” os três originais. No entanto, os três commits antigos ainda estão lá. Mas não se pode alcançá-los facilmente, porque agora não há nenhum branch apontando para eles.

+ +

O leitor astuto vai notar que até mesmo as imagens acima são uma simplificação. “Deveríamos ter mais commits na imagem”, dizem eles, com seu dedo indicador acusatório apontando para a tela. E adivinhe, eles estão certos.

+ +

Lembra-se de que começamos tudo isso alterando dois commits? Bem, como dar amend não altera os commits, mas cria novos, temos dois commits extra perdidos em nosso repositório. Eu os omiti dos diagramas acima porque eu estava com preguiça por uma questão de brevidade. Mas como um exercício para o leitor, você mesmo pode adicioná-los.

+ +

Reescreva o Passado Para Parecer (e ser) Mais Inteligente

+

Reescrever a história é uma poderosa capacidade do Git. Com comandos como git commit --amend e git rebase -i você pode “mudar” seus commits passados, escondendo seus erros e fazendo parecer que você fez tudo certo desde o início. Eu faço isso o tempo todo e colho os benefícios: meus colegas de trabalho pensam que sou muito mais esperto do que realmente sou - por favor, não conta meu segredo pra eles.

+ +

Falando sério agora: esses comandos são ferramentas fantásticas para você conseguir um histórico mais organizado. Com eles, você pode perder de uma vez o medo de commitar com frequência. Faça commits pequenos e frequentes, e não ligue muito para a mensagem — por exemplo, se você usa TDD, você pode commitar toda vez que os testes passarem.

+ +

Depois, quando for a hora de publicar o seu trabalho, dê squash nos commits e capriche na descrição. Aproveite e adote uma convenção de mensagens de commit para você e seu time, como o Conventional Commits. Seus colegas (e seu eu futuro) vão te agradecer.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/index.html b/pt/index.html new file mode 100644 index 00000000..9bf51fe7 --- /dev/null +++ b/pt/index.html @@ -0,0 +1,258 @@ + + + + + + + + carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+
+ +

receba atualizações via RSS

+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/metodos-privados-code-smell/index.html b/pt/metodos-privados-code-smell/index.html new file mode 100644 index 00000000..7f8eb72d --- /dev/null +++ b/pt/metodos-privados-code-smell/index.html @@ -0,0 +1,696 @@ + + + + + + + + Métodos privados são um 'Code Smell'? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Métodos privados são um 'Code Smell'?

+ +
+ +
+

+ +

Algumas pessoas acham que métodos privados devem ser evitados. Será que elas estão certas? +

+ +

Há uns dois meses, Marcos Douglas publicou um post sobre como o uso de regras e restrições pode melhorar seu código. Essa premissa costuma aparecer de novo e de novo pela web, e eu concordo totalmente com ela.

+ +

Marcos mostra várias orientações úteis, tais como o número ideal de argumentos em um método, o número ideal de métodos, em uma classe, e assim por diante. O artigo é muito bom, e eu recomendo a todos vocês que o leiam , mas ele não é o foco do meu post hoje.

+ +

Hoje, o que eu realmente quero falar é de um assunto que surgiu na área de comentários do artigo do Marcos: que diversas pessoas consideram métodos privados como um Code Smell (algo como “mau-cheiro de código”).

+ +

Como eu nunca tinha ouvido ou lido nada nesse sentido antes, fiquei bastante surpreso e decidi pesquisar mais.

+ +

Qual seria o problema de métodos privados?

+ +

Para começar, vamos tentar entender por qual razão métodos privados seriam um problema.

+ +

One common argument is that private methods violate the Single Responsibility Principle. The SRP states that each class should do only one thing. If you’re tempted to create private methods, the argument follows, that’s a sign that your class is doing too much.

+ +

Um argumento comum é que métodos privados violam o Princípio da Responsabilidade Única (ou SRP, do inglês Single Responsibility Principle).

+ +
+

Private helper methods indicate classes are doing too many things. Moving private helper methods to different classes, including creating new classes if necessary, splits the original responsibilities across multiple classes leading to simpler, better designs.

+ +

Kent R Spillner, em Private Methods are a Code Smell

+
+ +

Em tradução livre:

+ +
+

Métodos auxiliares privados indicam que as classes estão fazendo coisas demais. Mover métodos auxiliares privados para classes diferentes, incluindo criar novas classes se necessário, divide as responsabilidades originais em múltiplas classes, levando à projetos mais simples e melhores.

+
+ +

Aqui temos uma opinião bem parecida:

+ +
+

Private methods are not inherently bad, but they are a sign that you might be missing out on an opportunity to make a useful abstraction. If you have a private method that calls another private method, then there is almost certainly an area of responsibility that remains unidentified.

+ +

John McDowall, em Break. It. Up! – Private Method Access Modifiers as Code Smells

+
+ +

Em tradução livre:

+ +
+

Métodos privados não são inerentemente ruins, mas eles são um sinal de que você talvez esteja perdendo uma oportunidade de criar uma abstração útil. Se você tem um método privado que chama outro método privado, então é quase certeza que há uma outra área de responsabilidade que permanece não identificada.

+
+ +

Outro argumento é que métodos privados dificultam o uso de testes unitários:

+ +
+

Make it public!

+ +

[…]This is probably the simplest way to overcome the problem of untestability.[…] There’s a reason for that: testability is a perfectly good reason to make something public. And you should test most of your code.

+
+ +
+

Jason M Baker, em Enemies of Test Driven Development part I: encapsulation

+
+ +

Em tradução livre:

+ +
+

Torne [o método privado] público!

+
+ +
+

[…]Essa é provavelmente a maneira mais simples de resolver o problema da não-testabilidade[…] Existe uma razão para isso: testabilidade é uma razão perfeitamente boa para tornar algo público. E você deveria testar a maior parte do seu código.

+
+ +

Finalmente, pessoas também argumentam que métodos privados desempenham um papel importante no problema de “bagunçar” o estado interno dos objetos, o que pode lhe causar grandes problemas.

+ +
+

Functional programming teaches that state (in the form of member variables) is evil, because it makes your code more complex and harder to test.

+ +

Ryan Ginstrom, em Three reasons to avoid private class members

+
+ +

Em tradução livre:

+ +
+

Programação funcional ensina que estado (na forma de variáveis de instância) é maligno, porque ele torna seu código mais complexo e mais difícil de ser testado.

+
+ +

Eu acabei de mostrar alguns dos argumentos comuns contra a criação de métodos privados, então agora é hora de mostrar a opinião nesse assunto.

+ +

Métodos privados não são necessariamente violações do SRP

+ +

O primeiro argumento apresentando afirma que métodos privados violam o Princípio da Responsabilidade Única.

+ +
+

Private helper methods indicate classes are doing too many things.

+
+ +

Eu não penso que esse seja o caso. Pelo menos, não sempre. Isso depende do que exatamente o método privado faz.

+ +

Você provavelmente não deveria adicionar um método chamado ValidarEnderecoDeEmail à sua classe Cliente, sendo o método privado ou não. Afinal de contas, um cliente não é a única entidade que pode ter um endereço de e-mail. Ao invés disso, crie uma classe Email e coloque todas as validações pertinentes nela.

+ +

Por outro lado, digamos que você esteja criando um método Ordenar em uma estrutura de dados customizada. Nesse caso, faria todo o sentido manter o método Ordenar público, e ter alguns métodos privados auxiliares, como CompararItens e Trocar.

+ +
+

Moving private helper methods to different classes, including creating new classes if necessary, splits the original responsibilities across multiple classes leading to simpler, better designs.

+
+ +

Meu principal problema com esse argumento não é que classes pequenas são geralmente melhores que as grandes, o que eu concordo.

+ +

Meu problema é que eu não concordo que criar novas classes e métodos públicos apenas para evitar métodos privados vai automaticamente gerar “designs mais simples e melhores”. É claro que pode gerar; mas pode gerar projetos priores também. Cada situação é única.

+ +

Eu não compro testabilidade como um fim em si mesmo

+ +

Eu gosto muito de testes unitários (e testes automatizados de uma maneira geral). Eu ajudei evangelizar testes unitários no meu trabalho, e atualmente eu supervisiono o time que está adicionando testes unitários e de integração em nosso codebase.

+ +

E uma das primeiras perguntas que as pessoas fazem quando estão aprendendo sobre testes unitários é: Como eu faço para testar métodos privados?

+ +

+ +

Minha resposta geralmente é: você não deveria precisar. Na minha opinião, não é muito produtivo colocar um esforço excessivo em testar métodos privados: como eles são chamados pelos públicos, eles vão ser exercitados pela sua suíte de testes de qualquer forma.

+ +

O objetivo de um teste unitário deveria ser testar e documentar uma “unidade” (uma classe) por meio de usar sua API pública. O que nos leva ao próximo ponto.

+ +

Sua API pública deve ser estável (ou “Encapsulamento importa”)

+ +

API significa Application Programming Interface, ou Interface de Programação de Aplicações, em tradução livre. +Esse termo pode significar várias coisas, mas no nosso contexto aqui, pense no conjunto das classes e métodos públicos que você expõe aos consumidores.

+ +

A API age como um tipo de contrato entre você e os consumidores do seu código. É um acordo. Se você alterar o acordo, a outra parte não vai ficar muito feliz.

+ +

+ +

Sua API pública deveria ter o máximo de estabilidade possível. Isso é particularmente importante quando você está criando um web service, uma biblioteca, ou qualquer tipo de ferramenta na qual terceiros dependem.

+ +

A propósito, esses “terceiros” não necessariamente precisar estar distante geograficamente de você. É bem comum em empresas, médias para cima, que vários times dependam de código disponibilizado por outros. O que aconteceria se cada equipe fizesse alterações drásticas em suas APIs constantemente? Caos.

+ +

A partir do momento que você expõe um método publicamente, você tem a responsabilidade de mantê-lo funcionando e honrando seu contrato; do contrário, você corre o risco de causar quebra de retrocompatibilidade nos seus clientes!

+ +

Um bom uso de métodos privados pode ajudar a manter um encapsulamento correto no seu design.

+ +

Aqui temos mais uma citação de Kent R Spillner:

+ +
+

Sometimes, private methods are created just to give pieces of functionality more descriptive names. Although descriptive names are desirable, creating private methods to provide descriptive names for things is still a smell. Moving these methods to collaborators and making them public creates opportunities for future reuse without reducing the clarity of the original code.

+
+ +

Em tradução livre:

+ +
+

Às vezes, métodos privados são criados apenas para dar nomes mais descritivos a pequenos trechos de funcionalidade. Embora nomes descritivos são desejáveis, criar métodos privados para dar nomes descritivos a coisas ainda é um smell. Mover esses métodos para colaboradores e torná-los públicos cria oportunidades para reuso futuro sem reduzir a claridade do código original.

+
+ +

Esse é um dos pontos com os quais eu discordo mais veementemente. Eu frequentemente crio métodos privados pela exata razão que Kent critica aqui, ou seja, dar nomes descritivos a certos trechos de código, um hábito eu adquiri após ler o livro Código Limpo, de Robert C. Martin.

+ +

Kent defende que o jeito correto de lidar com isso seria mover esses métodos para novas classes e torná-los públicos.

+ +

Mas se eu fizer isso, eu adiciono um novo método à API público da minha aplicação! Agora eu tenho um método a mais para documentar, testar e manter, mesmo que jamais tenha intencionado que esse método fizesse parte da API.

+ +

Aqui temos uma definição para modificadores de acesso que na minha opinião acerta em cheio:

+ +
+

public - this method is part of the published API and will not change within major versions of the class

+ +

[…]

+ +

private - this method was refactored out of a well tested public or protected method for reasons of clarity or internal re-use. This method may absolutely change, even in patch releases, and should not be relied upon to even exist.

+
+ +

Em tradução livre:

+ +
+

público - este método é parte da API publicada e não vai mudar dentro de versões principais da classe.

+
+ +
+

[…]

+
+ +
+

privado - este método foi criado na refatoração de um método público ou protegido bem testado, por razões de claridade ou reuso interno. Este método com certeza pode ser alterado, mesmo em releases de correção, e ninguém deveria depender da existência dele.

+
+ +

Eu concordo com essa definição. Portanto, em minha visão.

+ +
    +
  • Métodos privados não são necessariamente uma coisa ruim a ser evitada a todo custo.
  • +
  • A prática de tornar métodos privados em públicos não leva automaticamente a um design melhor; ela pode também gerar uma API desnecessariamente inflada, encapsulamento enfraquecido, e maior trabalho para manutenção.
  • +
  • Testabilidade é um objetivo nobre, mas precisa ser buscado de maneira pragmática. Métodos públicos bem testados e bem documentados deveriam ser suficientes, na maioria dos casos.
  • +
+ +

Métodos privados podem ser bons ou ruins; aprenda a separ o joio do trigo

+ +

Tudo isso dito, eu também acho que existem casos nos quais métodos privados são usados de uma maneira errada. Toda ferramenta pode ser abusada. Existem alguns sinais para os quais você precisa ficar alerta:

+ +

Se um método privado está em um nível de abstração diferente que os públicos em uma classe, é um sinal de que ele pertence em outra classe. Leitura e escrita em arquivo está um nível de abstração bem mais baixo que o cálculo do pagamento mensal de um empregado, por exemplo.

+ +

Quando um método privado é tão complexo que você realmente queria poder testá-lo…é sinal de que ele provavelmente deveria ser público. (Antes que você corra para os comentários para apontar minha aparente contradição, eu não estou dizendo que todos os métodos privados deveriam virar públicos para serem testáveis…apenas aqueles que ultrapassam um determinado limiar de complexidade).

+ + + + +

E quando um método privado contém código duplicado, do tipo, copiado e colado de outra classe? Livre-se da duplicação na hora!

+ +

Então, esse é o ponto: duas das três dicas que acabo de mostrar são meio subjetivas. Em algum ponto, você tem que fazer algumas escolhas. Quão complexo é complexo o suficiente para um método privado precisar de testes unitários? Como distinguir níveis de abstrações diferentes?

+ +

A melhor dica que eu posso oferecer é: Duas cabeças pensam melhor que uma. Sempre faça com que outra pessoa olhe e examine seu código antes de ser commitado. Programação em par e/ou revisão de código são ótimas técnicas, não apenas para melhorar o projeto e encontrar bugs, mas principalmente para espalhar conhecimento por uma equipe. Não só conhecimento técnico, mas conhecimento do domínio também, e isso pode fazer toda a diferença na hora de tomar as decisões difíceis.

+ +

Conclusão

+ +

Embora métodos privados podem ser usados em maneiras ruins, eu penso que seria prematuro automaticamente rotulá-los como uma coisa ruim a ser evitada.

+ +

Me parece que algumas das pessoas que afirmam estar argumentando contra métodos privados estão na verdade argumento contra problemas que são ortogonais a métodos privados; você pode violar a SRP com ou sem métodos privados; você pode causar problemas com estado interno mutável com ou sem métodos privados, e assim por diante.

+ +

Desenvolver software é uma arte, cheia de trade-offs e incerteza. E ainda que “regras de ouro” possam ser úteis, elas não devem ser seguidas cegamente.

+ +

Este post ficou muito mais longo do que eu planejei. Agradeço caso tenha chegado até aqui. Até a próxima!

+ +

Veja também

+ + + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/null-problematico.html b/pt/null-problematico.html new file mode 100644 index 00000000..f63e4729 --- /dev/null +++ b/pt/null-problematico.html @@ -0,0 +1,626 @@ + + + + + + + + Null É Ruim. Qual A Melhor Alternativa? Null. | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Null É Ruim. Qual A Melhor Alternativa? Null.

+ +
+ +
+

+Foto por Ben Hershey on Unsplash

+ +

Nota editorial: Eu escrevi originalmente este post para o blog da NDepend. Você pode conferir o original aqui, em inglês, no site deles.

+ +

“Null é maligno”. Se você tem sido um desenvolvedor de software por qualquer período de tempo razoável, aposto que já se deparou com essa afirmação várias vezes.

+ +

Eu diria também que é muito provável que você concorde com o sentimento, ou seja, que a referência nula é uma característica sem a qual nossas linguagens de programação ficariam melhor. Até mesmo seu criador expressou seu pesar pela referência nula, chamando-a de seu “erro de um bilhão de dólares”

+ +

Criticar null tende a ficar chato rapidamente, portanto, os autores não fazem só isso. Eles também oferecem alternativas. E embora eu acredite que muitas das alternativas apresentadas têm seus méritos, também acho que talvez tenhamos negligenciado a melhor solução para tudo isso.

+ +

Neste post, vamos examinar algumas das alternativas comuns para o retorno nulo antes de fazer o argumento de que a melhor alternativa é a própria nulidade. Vamos começar!

+ +

Null é Tóxico…

+ +

Não vou me deter muito em toda essa coisa do “nulo é mal”, já que muito já foi escrito sobre isso. Alguns exemplos (em inglês):

+ +

Null Is Evil +Null has no type, but Maybe has

+ +

Esta resposta de Stack Overflow também tem algumas informações valiosas.

+ +

…Mas útil. Quais são as Alternativas?

+ +

Agora, espero que estejamos na mesma página no que diz respeito ao status de nulo como um recurso de linguagem problemática. Mas tóxico ou não, o nulo serve a alguns propósitos. As pessoas o usam para representar um dado ausente, inválido ou desconhecido, ou mesmo para indicar que ocorreu um erro.

+ +

O que deveriam estar fazendo ao invés disso?

+ +

Lançar uma Exceção

+ +

Em algumas situações em que as pessoas retornam null, a coisa razoável a fazer é lançar uma exceção. Pense desta maneira: se um método promete realizar algo e não o faz, ele deve lançar uma exceção. Em outras palavras: quando um método não cumpre seu contrato, então é razoável disparar uma exceção.

+ +

É claro que você deve reservar exceções para cenários que sejam verdadeiramente excepcionais. Se uma determinada situação acontece com freqüência, então uma exceção não é a melhor solução.

+ +

Padrão de Objeto Null

+ +

Considere as seguintes linhas de código:

+ +
var contract = repository.Find(42);
+contract.Extend(12);
+ +

O que deveria acontecer se não houvesse um contrato com ID igual a 42? Se o método “Find” retornar null, então você vai ganhar uma desagradável NullReferenceException. Como eu disse anteriormente, a nulidade faz seu código mentir. Se fossemos realmente pedantes sobre isso, o método “Find” deveria ser renomeado para “FindOrReturnNull”. Muito verboso, mas mais honesto.

+ +

De qualquer forma, o padrão de objeto nulo é uma tentativa de resolver este problema. E como ele faz isso? Criando seu próprio tipo de nulo.

+ +

Para implementar o padrão, criamos uma nova classe (vamos chamá-la de “NullContract”) que representa o caso quando um contrato está faltando. Fazemos esta nova classe cumprir o mesmo contrato que a classe original, mas não fazemos nada nos métodos. Assim, se imaginarmos que “Contrato” implementa IContract, nossa classe NullContract poderia ser algo parecido com isto:

+ +
public class NullContract : IContract
+{
+	// construtor, propriedades, etc 
+	
+	public void Extend(int months)
+	{
+		// não faz nada aqui, propositalmente
+	}
+}
+ +

Ao empregar o padrão de objeto nulo você poderia - teoricamente, pelo menos - ter a certeza de que sempre receberá um objeto que cumpre o contrato que você espera que ele honre sem explodir na sua cara.

+ +

Maybe/Option

+ +

Finalmente, temos uma alternativa muito interessante que muitas vezes é encontrada na programação funcional linguagens. Esta alternativa é o uso de um tipo dedicado, destinado a representar o caso de uso de um valor potencialmente ausente. Por exemplo, em F# isto é chamado de tipo de option; Haskell a chama de Maybe. A partir da versão 8, Java introduziu a classe Optional.

+ +

Neste momento, o C# não oferece algo parecido com este tipo nativamente.

+ +

Alternativas ao Null: Elas são boas?

+ +

Tendo apresentado as alternativas mais comumente usadas para nulo, é hora do veredicto final. Vamos começar com a opção “lançar exceção”.

+ +

Exceções

+ +

Se o chamador não fornecer os argumentos corretos para a função que está chamando, então poderíamos dizer que ele está quebrando o contrato da função. Lançar uma exceção é a coisa correta a fazer nesta situação.

+ +

O código a seguir é um bom exemplo do que não* deve ser feito:

+ +
public Foo Bar(int a, string b)
+{
+    if (a > 0 && a <= 100)
+    {
+        if (!string.IsNullOrWhiteSpace(b))
+        {
+            // tá tudo certo: vamos fazer o que precisa ser feito e retornar
+            // um novo objeto!
+            return new Foo();
+        }
+    }
+ 
+    // Tem coisa errada com os parâmetros recebidos. Já sei! Vamos retornar null!
+    return null;
+}
+ +

Eu vejo códigos como este o tempo todo em produção. Os ifs aninhados são horríveis. Eles deveriam pelo menos ter usado um “and” para encaixar tudo em apenas um “if”. Mas o que realmente deveria acontecer é algo assim:

+ +
public Foo Bar(int a, string b)
+{
+    if (a <= 0 || a > 100)
+    {
+        throw new ArgumentOutOfRangeException(
+        nameof(a),
+        "O valor deve estar no intervalo de 1 a 100, inclusive.");
+    }
+ 
+    if (string.IsNullOrWhiteSpace(b))
+    {
+        throw new ArgumentException(
+             "O valor deve ser uma string válida.",
+             nameof(b)
+             );
+    }
+ 
+    // tá tudo certo: vamos fazer o que precisa ser feito e retornar
+    // um novo objeto!
+    return new Foo();
+}
+ +

Além disso, não capture exceções exógenas que possam acontecer dentro de seu método e retorne nulo; em vez disso, deixe-as subir, pois este tipo de exceções representam problemas fora de seu controle. Problemas como uma falha na rede são problemas que você não poderia ter evitado de qualquer forma, em código.

+ +

Padrão Null Object

+ +

Vamos considerar o padrão de objeto nulo, do qual certamente não sou um grande fã. Um problema com este padrão é que você só deve usá-lo quando o código de chamada não se importa com o resultado do que quer que ele esteja tentando realizar. Considere novamente nosso exemplo de contrato:

+ +
var contract = repository.Find(42);contract.Extend(12);
+ +

Esta linha de código não é “consciente” (nem se importa) se a variável “Contrato” se refere a um contrato válido ou a uma instância da NullContract. Se for um contrato válido, ele será prorrogado por 12 meses. Se não for, então nada acontecerá. Às vezes, é exatamente isso que você quer, mas nem sempre. Neste exemplo, se um contrato com ID equivale a 42 realmente deveria existir, mas não… talvez lançar uma exceção funcionaria melhor.

+ +

Tudo o que eu disse até agora é que o padrão de objeto nulo não é bem adequado para cada cenário. Isto não é um problema tão ruim assim; você poderia dizer o mesmo sobre praticamente qualquer coisa.

+ +

Meu principal problema com o padrão de objeto nulo é que ele equivale a pouco mais do que criar um novo tipo de objeto nulo sem realmente resolver o problema. Veja, utilizar o padrão não impede que você retorne nulo. Se eu consumir algum método escrito por um terceiro que afirma usar o padrão, devo ser capaz de assumir que o que quer que seja que ele retorne é seguro. Mas eu não posso ter certeza. Eu tenho três opções:

+ +
    +
  • Confiar no autor do código;
  • +
  • Inspecionar o código-fonte, se possível; ou
  • +
  • Continuar a verificar a nulidade, o que derrota completamente o propósito de usar o padrão.
  • +
+ +

Pode-se argumentar que estes problemas não são relevantes no contexto de uma única equipe que trabalha com a mesma base de código. Os desenvolvedores poderiam concordar em usar o padrão corretamente. Mas se tudo equivale a confiança e convenção no final do dia, você poderia muito bem concordar em nunca retornar nulo e teria o mesmo resultado.

+ +

Maybe/Option

+ +

Por último, mas não menos importante, e quanto aos tipos Maybe/Option? Esta é uma alternativa ao mesmo tempo elegante e robusta, especialmente em linguagens como o F#, onde você é forçado, de certa forma, a lidar com ambos os casos usando pattern matching.

+ +

Mas a triste realidade é a seguinte: embora Maybe/Option sejam abordagens surpreendentes, elas não podem mudar o fato de que o nulo existe e continuará a existir. Você não pode realmente impedir as pessoas de usá-lo, nem pode removê-lo de todas as linhas de código que as pessoas têm escrito desde o início da história do C#.

+ +

Portanto, mesmo sendo grandes abordagens, elas ainda sofrem com o problema de serem mais um tipo de nulo para os desenvolvedores lidarem.

+ +

A solução para Null: O próprio Null

+ +

Você conhece o velho ditado “Quando em um buraco, pare de cavar”? Para o melhor ou para o pior, existe o nulo. Tóxico ou não, é uma característica que as pessoas usam. Portanto, talvez a solução para tudo isso seja apenas consertar o nulo.

+ +

A linguagem kotlin acertou ao ter diferentes tipos de nulos e não nulos e adicionar todos os tipos de verificações para evitar que o desenvolvedor faça coisas que acabariam mal, como desreferenciar um tipo nulo sem verificá-lo ou atribuir um valor nulo a uma variável não nula.

+ +

O C# nos deu o primeiro passo na direção certa há muitos anos com tipos de valor nulo. Após uma longa espera, tipos de referência finalmente obterão o mesmo benefício com C# 8.0.

+ +

A alternativa para o nulo é o próprio nulo… quando feito corretamente.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/operador-linq-join.html b/pt/operador-linq-join.html new file mode 100644 index 00000000..de8a1c3f --- /dev/null +++ b/pt/operador-linq-join.html @@ -0,0 +1,804 @@ + + + + + + + + Operador 'Join' do LINQ: Um Tutorial Completo | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Operador 'Join' do LINQ: Um Tutorial Completo

+ +
+ +
+

+ +

NOTA: Eu escrevi este artigo, originalmente, para o blog da Stackify. Caso lhe interesse, você pode ver o artigo original, em inglês, no site deles.

+ +

Acho que a maioria dos desenvolvedores C# concordaria que o LINQ é parte essencial da experiência de escrever código com a linguagem. O LINQ oferece uma maneira fluente, intuitiva e consistente de consultar conjuntos de dados. Neste artigo, ajudaremos você a dominar o LINQ, abordando o operador join.

+ +

Vou abrir o post com uma definição do próprio LINQ, para que estejamos todos na mesma página. Depois disso, você verá uma explicação das operações de join no LINQ. Depois, é hora de arregaçar as mangas e colocar a mão na massa com nosso guia prático sobre o operador de join.

+ +

Vamos começar.

+ +

O Quê é LINQ?

+

LINQ significa Language Integrated Query. É um recurso do C# que oferece uma sintaxe única e consistente para consultar conjuntos de dados, independentemente da origem deles. A principal vantagem do LINQ é que você pode usar a mesma sintaxe para consultar dados na memória, em um banco de dados, em arquivos XML e assim por diante.

+ +

O LINQ está disponível em dois “sabores” diferentes: a sintaxe de consulta (query syntax) e a sintaxe de método (method syntax).

+ +

A sintaxe de consulta utiliza palavras-chave especiais para criar uma sintaxe que é familiar a qualquer pessoa que tenha trabalhado com SQL. Aqui está um exemplo que consulta uma sequência de números, filtrando os maiores que 5:

+ +
int[] numbers = { 2, 8, 4, 9, 3, 6, 1, 7, 5 };
+var largerThanFive =
+    from num in numbers
+    where num > 5
+    select num;
+ +

A syntaxe de método usa métodos de extensão para realizar a mesma consulta:

+ +
int[] numbers = { 2, 8, 4, 9, 3, 6, 1, 7, 5 };
+var largerThanFive = numbers.Where(x => x > 5);
+ +

O que é o operador LINQ Join?

+ +

Ao trabalhar com dados, um cenário comum é ter duas fontes de dados que você deseja combinar com base em alguns critérios. Por exemplo, você pode ter uma tabela Books (Livros) e uma tabela Authors (Autores) em seu banco de dados, com um relacionamento de um para muitos entre elas, ou seja, um autor pode ser autor de muitos livros, mas cada livro tem apenas um autor. Se você precisar compilar uma lista de livros que contenha o nome do autor, precisará executar uma junção para fazer a correspondência entre cada linha da tabela Books e sua contraparte na tabela Authors.

+ +

Uma junção no LINQ é essencialmente a mesma coisa: uma operação em que você pode mesclar duas coleções de acordo com alguns critérios que você define.

+ +

O operador LINQ Join na prática

+ +

Os exemplos sempre deixam as coisas mais claras. Então, vamos ver como usar o operador join na prática.

+ +

Iniciando com um problema

+ +

Digamos que você tenha um aplicativo de comércio eletrônico com alguns dados sobre categorias:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdName
1Electronics
4Toys
5Stationery
7Books
10Clothes
+ +

Agora, vamos ver alguns produtos:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdNameCategory_Id
1Amazon Kindle1
2Refactoring7
3C# in Depth7
4Legal Pad 50 sheets5
+ +

Você já entendeu aonde isso vai, né? A próxima coisa que você deseja fazer é produzir uma única coleção, com a lista de produtos e os nomes das categorias às quais eles pertencem. Em outras palavras, uma visualização como esta:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdNameCategory
1Amazon KindleElectronics
2RefactoringBooks
3C# in DepthBooks
4Legal Pad 50 sheetsStationery
+ +

Resolvendo o problema: executando um LINQ Inner Join

+ +

Como seria essa operação no código? Em primeiro lugar, precisamos de código para representar nossas categorias e produtos. Graças ao recurso de record do C#, duas linhas de código são suficientes para isso:

+ +
public record Product(int Id, string Name, int CategoryId);
+public record Category(int Id, string Name);
+ +

Agora, vamos ter uma lista de cada tipo:

+ +
var categories = new List<Category>
+{
+    new Category(1, "Electronics"),
+    new Category(4, "Toys"),
+    new Category(5, "Stationery"),
+    new Category(7, "Books"),
+    new Category(10, "Clothes" (Categoria 10, "Roupas")
+};
+
+var products = new List<Product>
+{
+    new Product(1, "Amazon Kindle", 1),
+    new Product(2, "Refactoring", 7),
+    new Product(3, "C# In Depth", 7),
+    new Product(4, "Legal Pad 50 Sheets", 5),
+    new Product(5, "Surgical Gloves", 12)
+};
+ +

Como você pode ver, a lista de produtos tem um produto adicional (luvas cirúrgicas) cujo ID de categoria não corresponde a nenhuma das categorias disponíveis. Tenha isso em mente, pois será relevante em um momento.

+ +

Agora, vamos escrever o código para realizar essa união. Vou mostrar o código de uma só vez e depois eu explico:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+
+foreach (var line in query)
+{
+    Console.WriteLine(line);
+}
+ +

Agora, a explicação:

+ +

from p in products -> estamos definindo a origem de uma de nossas fontes de dados

+
    +
  • join c in categories -> Aqui, estamos dizendo que queremos juntar a coleção anterior com esta +*on p.CategoryId equals c.Id** -> Essa é a condição para a união: o CategoryId em cada produto deve corresponder ao Id de uma categoria
  • +
  • select new… -> Aqui, estamos aproveitando o recurso de objetos anônimos do C# para criar um novo objeto em tempo real, que tem as propriedades que desejamos
  • +
+ +

O resultado dessa consulta é um IEnumerable do nosso objeto anônimo. Em seguida, iteramos por cada item dessa coleção, exibindo-o no console. Este é o resultado: +`

+
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+{ Id = 2, Name = Refactoring, Category = Books }
+{ Id = 3, Name = C# In Depth, Category = Books }
+{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery }
+
+ +

Aqueles que se lembram das aulas de banco de dados perceberão que a junção LINQ que realizamos é equivalente a uma junção interna (inner join) no SQL. Em outras palavras, somente os itens que têm uma correspondência são retornados. Em SQL, a consulta equivalente seria a seguinte:

+ +
SELECT p.Id, p.Name, c.Name AS Category
+FROM products AS p
+JOIN categories AS c ON p.CategoryId = c.Id
+ +

Executando uma junção externa (OUTER JOIN) no LINQ

+ +

E se você quisesse executar o equivalente a um OUTER JOIN do SQL? Ou seja, você deseja recuperar todos os produtos, mesmo aqueles que não correspondem a nenhuma categoria. Como fazer isso?

+ +

Aqui está a consulta atualizada:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id into joinedCategories
+    from c in joinedCategories.DefaultIfEmpty()
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c?.Name
+    };
+ +

Parece semelhante, mas há duas diferenças:

+ +
    +
  • on p.CategoryId equals c.Id into joinedCategories -> aqui, depois de unir produtos com categorias, enviamos o resultado, como uma sequência agrupada, para a variável de intervalo joinedCategories
  • +
  • from c in joinedCategories.DefaultIfEmpty() -> Em seguida, recuperamos os itens da groupedSequence, usando o método DefaultIfEmpty() para retornar o valor padrão quando nenhuma correspondência for encontrada
  • +
  • Category = c?.Name -> Por fim, ao atribuir o nome da categoria à propriedade Category do nosso objeto anônimo, precisamos usar o operador condicional nulo para evitar uma exceção de referência nula (já que o valor padrão de Category é nulo porque é um tipo de referência).
  • +
+ +

O resultado agora é diferente:

+ +
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+{ Id = 2, Name = Refactoring, Category = Books }
+{ Id = 3, Name = C# In Depth, Category = Books }
+{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery }
+{ Id = 5, Name = Surgical Gloves, Category = }
+ +

Como você pode ver, o produto “Surgical Gloves” (Luvas cirúrgicas) agora aparece, mesmo que não tenha uma categoria correspondente.

+ +

Inner Join do LINQ com a condição Where

+ +

Realizar uma junção com uma cláusula where é muito fácil. Neste exemplo, realizaremos uma junção interna, filtrando apenas os produtos cujo id seja igual ou maior que 3:

+ +
var query =
+    from p in products
+    where p.Id >= 3
+    join c in categories
+    on p.CategoryId equals c.Id
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

Inner Join do LINQ com várias condições

+ +

Se você quiser usar várias condições em sua junção, basta usar mais de uma cláusula where. Vamos atualizar nossa consulta mais uma vez:

+ +
var query =
+    from p in products
+    join c in categories
+    on p.CategoryId equals c.Id
+    where p.Id >= 3
+    where c.Name.EndsWith('s')
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

Aqui, estamos filtrando apenas as categorias cujos nomes terminam com a letra “s”.`

+ +

LINQ Join com chave composta

+ +

Até agora, todos os nossos exemplos usaram chaves únicas para fazer a correspondência. Você também pode usar chaves compostas, ou seja, mais de um valor, para fazer a correspondência.

+ +

Suponha que as nossas classes Product e Category tenham adquirido uma nova propriedade chamada Status, que é um enum que pode variar entre três estados: Pending (pendente), Active (ativo) e Archived (arquivado). Agora, a propriedade Status também precisa ser usada para a correspondência.

+ +

Todos os nossos produtos estão ativos, mas nem todas as categorias:

+ +
var categories = new List<Category>
+{
+    new Category(1, "Electronics", Status.Active),
+    new Category(4, "Toys", Status.Active),
+    new Category(5, "Stationery", Status.Archived),
+    new Category (7, "Books", Status.Pending),
+    new Category (10, "Clothes", Status.Active)
+};
+
+var products = new List<Product>
+{
+    new Product(1, "Amazon Kindle", 1, Status.Active),
+    new Product(2, "Refactoring", 7, Status.Active),
+    new Product(3, "C# In Depth", 7, Status.Active),
+    new Product(4, "Legal Pad 50 Sheets", 5, Status.Active),
+    new Product(5, "Surgical Gloves", 12, Status.Active)
+};
+ +

Fica assim a consulta atualizada:

+ +
var query =
+    from p in products
+    join c in categories
+    on new { Id = p.CategoryId, Status = p.Status }
+    equals new { Id = c.Id, Status = c.Status }
+    select new
+    {
+        Id = p.Id,
+        Name = p.Name,
+        Category = c.Name
+    };
+ +

Não é muito mais complicado do que antes. A diferença é que, agora, usamos um objeto anônimo para realizar a comparação usando as propriedades id e status.

+ +

Um único resultado é exibido a partir dessa consulta:

+ +
{ Id = 1, Name = Amazon Kindle, Category = Electronics }
+ +

Conclusão

+ +

Como vimos, o LINQ é uma parte essencial do trabalho com o C#. Você pode aproveitar o LINQ em muitos cenários diferentes, desde o trabalho com dados na memória até XML e SQL. Você pode usar o LINQ em ORMs, como NHibernate e Entity Framework.

+ +

As equipes que desejam tornar suas experiências com LINQ ainda melhores podem usar as ferramentas à sua disposição. Por exemplo, Stackify’s Prefix e Retrace oferecem recursos avançados de rastreamento, criação de perfil e registro centralizado que ajudam as equipes a inspecionar seu código para encontrar oportunidades de melhorias de desempenho, o que inclui consultas LINQ.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/programacao-funcional-csharp/index.html b/pt/programacao-funcional-csharp/index.html new file mode 100644 index 00000000..fc4b73d8 --- /dev/null +++ b/pt/programacao-funcional-csharp/index.html @@ -0,0 +1,660 @@ + + + + + + + + Programação Funcional em C#: Mapeando, Filtrando e Reduzindo Em Busca de Código Limpo | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Programação Funcional em C#: Mapeando, Filtrando e Reduzindo Em Busca de Código Limpo

+ +
+ +
+

+ +

NOTA: Este post foi originalmente publicado no blog da SubMain. Você pode ler o original aqui, em inglês. Aproveite para conferir o CodeIt.Right, um produto que pode ajudar a melhorar seu código.

+ +

Você provavelmente pensa no C# como uma linguagem orientada a objeto. Mas é possível que você, ao programar em C#, tenha usado conceitos de programação funcional sem sequer ter notado.

+ +

O post de hoje trata desse tema. Vou começar abordando as vantagens da programação funcional, mostrando a justificativa se aplicá-la mesmo usando uma assim chamada linguagem orientada a objetos. Depois vou explicar como você já está usando um pouco do estilo funcional em seu código C#, mesmo sem estar ciente disso. Finalmente, vou demonstrar como aplicar um pouco de pensamento funcional ao seu código pode torná-lo mais limpo, seguro e mais expressivo.

+ +

Programação Funcional em C#: Por quê?

+ +

Nós sabemos que o .NET framework oferece algumas capacidades funcionais na forma dos métodos de extensão do LINQ, mas qual seria a vantagem de usá-las?

+ +

Para responder bem essa pergunta, precisamos voltar um passo e entender os atrativos da programação funcional em si. Na minha opinião, para começar a entender os benefícios da programação funcional você precisa primeiro entender dois tópicos: funções puras e imutabilidade.

+ +

Funções puras são funções que apenas podem acessar os valores que receberam por argumentos e, como consequência, não podem ter nenhum efeito colateral. Imutabilidade se refere a objetos ou estruturas de dados que, uma vez inicializados, não podem sofrer nenhuma mudança em seus valores. Isso os torna mais fáceis de entender e seguros para serem usados em código com múltiplas threads.

+ +

Operações Fundamentais da Programação Funcional e Como Executá-las Usando C#

+ +

Como já cobrimos o o quê e o porquê da programação funcional, está na hora de vermos o como.

+ +

Eu vou abordar três operações: map, filter e reduce. Vou começar mostrando alguns problemas, usando uma abordagem procedural tradicional para resolvê-los. Em seguida, vou apresentar a alternativa usando o estilo funcional.

+ +

Map

+ +

Em termos simples, a operação “map” recebe uma sequência de valores, aplica alguma transformação em cada um dos itens, e retorna uma nova sequência contendo os valores resultantes. Vamos ver alguns exemplos:

+ +

Imagine que você escreveu o código a seguir, devido à requisição de algum cliente:

+ +
	static void AddThreeToEachElement(int[] arr)
+	{
+	    for (var i = 0; i < arr.Length; i++)
+	    {
+	       arr[i] += 3;
+	    }
+	}
+ +

É uma função que adiciona três a cada elemento do array de inteiros especificado. Bem tranquilo.

+ +

Então aparece o pedido de uma nova função. Dessa vez, é para adicionar cinco a cada elemento do vetor. Ignorando a regra de três, você pula direto para uma versão generalizada, parametrizando o número a ser adicionado:

+ +
	static void AddNumberToEachElement(int[] arr, int n)
+	{
+	   for (var i = 0; i < arr.Length; i++)
+	   {
+	        arr[i] += n;
+	   }
+	}
+ +

Então aparece um novo pedido. Agora você tem que escrever uma função para multiplicar cada elemento do array especificado por três. Não vou me dar ao trabalho de adicionar o código de exemplo, porque seria bem trivial. A esse ponto, você já sabe o suficiente para evitar fixar o número no código, então você provavelmente vai pular direto para uma versão generalizada. Mesmo assim, alguma duplicação ainda vai permanecer: o laço de repetição em si. E se você pudesse manter o loop e parametrizar a ação a ser aplicada nos itens?

+ +

A Maneira Funcional

+ +

Leve em consideração o que você acabou de ler sobre funções puras—e também seu conhecimento prévio de boas práticas de programação em geral—e pense em maneiras nas quais o código do exemplo poderia ser melhorado.

+ +

No meu ponto de vista, os problemas principais são:

+ +
    +
  • O código é muito específico. Não é fácil modificá-lo para acomodar outras transformações a serem aplicadas nos elementos do array. O código só faz uma soma, e é só.
  • +
  • Muito código boilerplate. Olhe novamente o exemplo anterior. Conte as linhas. Há sete, das quais apenas uma realmente tem algo a ver com a regra de negócio do método.
  • +
+ +

Como que o estilo funcional pode melhorar isso? O código a seguir mostra como eu reescreveria o exemplo em F#, por exemplo:

+ +
	let result = Seq.map (fun x -> x + 3) numbers
+ +

Aqui, “numbers” represente uma sequência de números que eu consegui de alguma forma. Então eu uso a função map que pertence ao módulo Seq, passando a sequência como um dos parâmetros, junto com uma função que recebe um número inteiro e adiciona três a ele.

+ +

O Jeito Funcional, sabor C#

+ +

O .NET implementa a operação map na forma do método de extensão do LINQ chamado “Select.” Então, para converter o código em F# acima para C#, você faria assim:

+ +

var result = numbers.Select(x => x + 3);

+ +

É importante salientar o que o tipo da sequência resultante não precisa ser o mesmo da sequência de entrada. Você tem uma lista de objetos do tipo “Employee” e precisa recuperar os seus ids, na forma de uma sequência de ints? Fácil:

+ +
	List<Employee> employees = EmployeeRepository.All();
+	IEnumerable<int> ids = employees.Select(x => x.Id);
+ +

Filter

+ +

A operação filter é, sem dúvida, a mais fácil das três. Ela tem um nome bastante intuitivo, e a necessidade de se filtrar coisas é algo tão comum na programação que eu tenho certeza de que você adivinhou o que ela faz só pelo nome (caso já não soubesse antes).

+ +

Mesmo assim, vamos defini-la. A operação filter filtra uma sequência, retornando uma nova sequência contendo apenas os itens aprovados por um ou mais critérios especificados.

+ +

O Jeito Imperativo

+ +

Já que nós usamos o exemplo de “employees” na seção anterior, vamos continuar dentro do mesmo tema. Digamos que você precise recuperar uma lista com os funcionários que tenham tirado pelo menos três dias de atestado médico.

+ +

Em um estilo mais procedura, você provavelmente escreveria algo assim:

+ +
	public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number)
+	{
+	    List<Employee> result = new List<Employee>();
+	
+	    foreach (var e in employees)
+	    {
+	        if (e.Sickdays >= number)
+	        {
+	            result.Add(e);
+	        }   
+	    }
+	
+	    return result;
+	}
+ +

Eu não acho que o código acima esteja errado. O nome do método é um pouco longo, porém bastante descritivo. O código faz o que promete. E a legibilidade está boa.

+ +

Mas da mesma forma que no exemplo anterior, nós poderíamos fazer o argumento de que o código está poluído demais Podemos dizer quem, na prática, a única linha que faz algo relacionado à lógica do problema é o teste do if. Todas as outras linhas são código boilerplate. Será que a abordagem funcional consegue melhorar a situação?

+ +

A Maneira Funcional

+ +

Vamos reescrever o código acima usando LINQ:

+ +
	public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number)
+	{
+	    return employees.Where(x => x.SickDays >= n).ToList();
+	}
+ +

Here we use the “Where” extension method, passing the filtering criterium as a delegate. To be honest, the outer method became not very useful since it just delegates the work. In real life, I’d get rid of it.

+ +

Aqui nós usamos o método “Here”, passando o critério de filtragem como parâmetro. Para ser honesto, o método de fora não é tão útil, já que ele só delega o trabalho para o método do LINQ. Na vida real, em código de produção, eu jogaria ele fora.

+ +

Reduce

+ +

Geralmente, a operação reduce é a que algumas pessoas costumam ter dificuldade entendendo. Mas não tem nada de difícil. Pense dessa forma: você tem uma sequência de alguma coisa, e também tem uma função que recebe duas dessas coisas e retorna uma.

+ +

Então você começa a aplicar a função. Você a aplica nos dois primeiros elementos na sequência e guarda o resultado. Então aplica de novo, com o resultado e o terceiro elemento. Depois faz a mesma coisa, aplicando a função ao resultado da última etapa e o quarto elemento, e assim sucessivamente.

+ +

O exemplo clássico do reduce é a soma de uma lista de números, então é exatamente isso que vamos fazer.

+ +

O Modo Imperativo

+ +

Suponha que temos que somar um punhado de números inteiros. Poderíamos fazer assim:

+ +
	public int Sum(IEnumerable<int> numbers)
+	{
+	    var result = 0;
+	    foreach (var number in numbers)
+	    {
+	        result += number;
+	    }
+	
+	    return result;
+	}
+ +

A essa altura do campeonato você já pode até prever o que eu tenho a dizer a respeito desse código: não está necessariamente errado, mas é pouco flexível e cheio de ruído. Mas a programação funcional pode nos salvar.

+ +

O Modo Funcional

+ +

No .NET framework, a operação “reduce” toma a forma do método de extensão “Aggregate”. Dessa vez, vou me livrar do método externo e escrever a solução usando LINQ de uma vez:

+ +
	var sum = number.Aggregate((x, y) => x + y);
+ +

A aparência disso é um pouco mais complexa, mas não se assuste. Nesse caso, nós estamos apenas passando uma função que recebe dois parâmetros ao invés de um só, como nos exemplos anteriores. Precisa ser assim, já que a função precisa ser aplicada a dois elementos da sequência cada vez.

+ +

But as it turns out, there’s an even easier way of solving this particular problem (adding a bunch of numbers). Since summing a sequence of numbers is such a common use case, there’s a dedicated method to do just that. It’s called, not surprisingly, “Sum”:

+ +

Mas na verdade tem uma maneira ainda mais fácil de resolver esse problema em particular (somar vários números). +Sendo esse um caso de uso tão comum, o framework disponibiliza um método dedicado para fazer só isso. O qual, surpreendendo a um total de zero pessoas, é chamado de “Sum”:

+ +
	var sum = numbers.Sum();
+ +

Para que serve o “Aggregate”, então? Adicionar uma lista de números é apenas uma das muitas aplicações do reduce, mas você pode usá-lo com qualquer operação binária, como concatenação de strings ou a soma de tipos customizados.

+ +

O Veredito: A Abordagem Funcional é Melhor?

+ +

Após esses exemplos, você talvez esteja em dúvida se o jeito funcional de fazer as coisas é realmente melhor. Seria extremamente difícil definir o que “melhor” significa, então nem vou tentar. Vamos considerar outro critério: legibilidade.

+ +

Apesar de sabermos que legibilidade de código também pode ser bastante subjetiva, eu diria que sim, os exemplos funcionais são mais legíveis. Imagine que nós recuperar e somar todos os salários dos funcionários com mais de cinco anos de casa. Nós poderíamos facilmente fazer isso usando um loop, dentro do qual nós testaríamos a condição e acumularíamos o salário em uma variável, caso o teste tenha retornado verdadeiro.

+ +

Ou poderíamos escrever isso:

+ +
	var sum = employees.Where(x => x.CompanyTimeInYears > 5).Select(x => x.Salary).Sum();
+ +

Eu honestamente acredito que essa versão é mais legível (e melhor, em geral) que a abordagem procedural. É mais declarativa. Ela demonstra a intenção do que estamos tentando fazer sem se preocupar tanto com o como.

+ +

It almost reads like natural language: “The list of employees where their time in the company is greater than five years, select their salary and sum them”.

+ +

Para quem entende inglês, quase parece linguagem natural: “Da lista de todos os funcionários, onde o tempo de empresa é mais de cinco anos, selecione o salário e some.”

+ +

Uso Um Pouco de Tempero Funcional e Deixe Seu Código Mais Saboroso

+ +

Muitas pessoas usam LINQ por anos sem nem perceber que estão usando conceitos de programação funcional. Eu enxergo isso como prova de que a programação funcional não está além das capacidades do típico desenvolvedor enterprise que não tem uma sólida formação matemática.

+ +

Alguns dos conceitos apresentados aqui não são novos nem restritos à programação funcional. Os benefícios de distinguir entre funções que causam efeitos colaterais e as que não causam é a base de princípios como command-query separation (CQS), por exemplo.

+ +

O objetivo desse post não é ensinar programação funcional para ninguém. Isso está além das minhas capacidades, já que eu ainda estou aprendendo. E além disso, existem ótimos recursos para aprender programação funcional, para aqueles que se interessarem.

+ +

Ao contrário, o que eu queria fazer aqui era mostrar um pouco do que um estilo funcional pode fazer com seu código: torná-lo mais expressivo, conciso e declarativo. Agora depende de você aplicar o estilo funcional ao código que você escreve.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/programar-portugues-ou-ingles/index.html b/pt/programar-portugues-ou-ingles/index.html new file mode 100644 index 00000000..eef0df1b --- /dev/null +++ b/pt/programar-portugues-ou-ingles/index.html @@ -0,0 +1,597 @@ + + + + + + + + Programar em português ou inglês? That's the question! | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Programar em português ou inglês? That's the question!

+ +
+ +
+

+ +

No contexto de boas práticas de desenvolvimento, um ponto que gera controvérsia é a escolha do idioma no qual codificar. Uma rápida busca no Google por “programar em português ou inglês” retorna 535 mil resultados, o que mostra que o tema realmente causa bastante discussão.

+ +

Recentemente conversei com um colega de trabalho e também com meu chefe a respeito desse assunto. Esse post é consequência dessas conversas e das pesquisas que fiz depois.

+ +

Parece ser uma visão bastante comum na nossa área que programar em inglês é a melhor opção. Fabio Akita, grande referência na comunidade Ruby On Rails do Brasil, inclui codificar em português - ou melhor dizendo, qualquer idioma que não o inglês - na sua lista de piores práticas de desenvolvimento:

+ +
+

Escreva nomes em inglês dentro do seu código. Não me importo se você é brasileiro, italiano, francês ou o que for. Nomes de classes, de variáveis, de métodos, tudo deve ser em inglês. Estamos num mundo globalizado, não é pensar muito longe que amanhã um americano vai mexer no seu código todo em português. Além do problema de consistência: a sintaxe da linguagem, todas as bibliotecas padrão, é tudo em inglês. É uma enorme dissonância cognitiva ter nomes em português no meio. É como você estar lendo uma revista em português com diversos parágrafos em inglês no meio. Não faz nenhum sentido.

+
+ +

Carlos Brando, outro nome conhecido no mundo Rails, deu opinião semelhante em um post de 2009:

+ +
+

Embora não exista uma regra escrita para isto, também sou contra nomear variáveis, métodos ou classe em português. Acho que como todo o código já está em inglês, graças as palavras chaves do Ruby, devemos manter absolutamente tudo em inglês também. Isto não é tão difícil assim, já que você pode fazer uso de tradutores e dicionários (online) para encontrar a melhor descrição para eles.

+
+ +

Um exemplo de como esse tema é inflamável: há cerca de dois anos foi lançada a versão em português do Stack Overflow, famoso site de perguntas e respostas pra programadores. Pare aqui e vá lá dar uma olhada no post. Viu a quantidade de comentários criticando a iniciativa? A controvérsia foi tanta que duas semanas depois a equipe do Stack Overflow publicou um novo post, dessa vez em inglês, justificando a decisão.

+ +

Eu acredito que a discussão é necessária e saudável e que existem bons argumentos nos dois lados. Assim, vou examinar opiniões a favor do uso de cada idioma, e ao final do post, expressar minha conclusão.

+ +

Argumentos a favor do inglês

+ +

Um dos argumentos mais comuns usados a favor do inglês é que seria estranho ou feio misturar dois idiomas na codificação. Como as palavras reservadas das linguagens de programação/frameworks/SGBD’s já são em inglês, utilizar a língua portuguesa para nomear variáveis e outras coisas acaba gerando híbridos como getNome, ProdutosController, clientes.ForEach, CodigoNaoEncontradoException e assim por diante. No trecho citado logo ali acima, Fabio Akita afirma que a mistura dos idiomas causa uma dissonância cognitiva, seria como ler uma página escrita em um idioma e de repente se deparar com parágrafos escrito em outro.

+ +

Outro argumento comum, também utilizado pelo Akita no trecho citado, é a possibilidade de um programador não-brasileiro vir a trabalhar no projeto. Imagine um projeto que conte com desenvolvedores da França, Alemanha, Brasil, Estados Unidos. Se cada um resolve programar no seu idioma, a comunicação se tornará impossível, a menos que todos os membros da equipe sejam proficientes nos idiomas de todos os outros membros, o que seria bastante improvável.

+ +

Um ponto bem parecido com o anterior é que a utilização do português prejudicaria uma eventual venda do produto para uma empresa de outro país, o que é de fato inegável.

+ +

O fato de que o inglês é a língua franca da tecnologia também figura constantemente entre os argumentos dos defensores do uso dessa língua na codificação. Segundo eles, qualquer desenvolvedor que se preze precisa ter um domínio avançado da língua inglesa. Sendo assim, o uso da inglês na verdade facilitaria o desenvolvimento, e não o contrário.

+ +

Outro ponto interessante a favor do inglês é que os identificadores nesse idioma tendem a ser menores, o que incentiva a um código mais limpo e conciso. Por exemplo, compare setName com atribuirNome.

+ +

Uma consequência do ponto anterior é que o uso de um único idioma ajuda a consolidar um vocabulário compartilhado entre todos os programadores. Get e Set, por exemplo, são palavras-chaves familiares para a maioria dos desenvolvedores, por serem extremamente comuns em API’s e bibliotecas diversas. Digamos que um programador recém-chegado à sua empresa recebe a tarefa de dar manutenção em uma biblioteca que vocês desenvolveram para trabalhar com XML. Ele provavelmente teria mais facilidade em encontrar um método chamado GetChildren() do que se fosse chamado ObterFilhos().

+ +

Outra vantagem da utilização do inglês seria…que ela melhora o seu conhecimento de inglês. Já que programadores precisam dominar esse idioma de qualquer forma, toda e qualquer oportunidade de praticá-lo é válida.

+ +

Argumentos a favor do português

+ +

Um argumento a favor do uso do português é a baixa proficiência em inglês apresentada pelos desenvolvedores brasileiros em geral, e como isso pode prejudicar a comunicação não apenas entre os desenvolvedores, mais também entre os desenvolvedores e as pessoas de negócio:

+ +
+

Da mesma forma, uma regra de negócio traduzida para o inglês pode ser mal traduzida por quem não domina o idioma. Falsos cognatos existem e podem ser utilizados nessa tradução cotidiana. Imagine que, ao invés de criar classes chamadas Funcionario e Empregador você crie classes chamadas Employee e Employer. Isso seria tão confuso para um desenvolvedor que não domina o inglês, quanto para um desenvolvedor que domina o inglês. Na hora de programar, os termos podem misturar-se. +Gustavo Gondim

+
+ +
+

Eu já vi tantas atrocidades na transliteração de português para inglês usando Google Translator… Na falta da compreensão, pega-se a primeira palavra que aparece. Ou cria-se expressões com termos em inglês usando a sintaxe do português. Confunde-se a forma de usar substantivos, verbos e adjetivos. A língua resultante pode ser inglês de índio, mas não é inglês. O ponto é que em uma equipe que não fala inglês nativamente, usar os termos de negócio em inglês pode complicar até o entendimento entre os programadores.[…] +Fernando Correia

+
+ +

Resumindo: uma equipe que tem domínio superficial do inglês necessariamente produz inglês de baixa qualidade, por não estar ciente das “pegadinhas” que o idioma pode apresentar (por exemplo: falsos cognatos). Mas ainda tem mais: é de conhecimento geral que programadores passam mais tempo lendo código do que escrevendo. E qualquer programador com alguma experiência vai concordar que ler código é bem mais difícil do que escrever. Ao forçar uma equipe sem desenvoltura na língua inglesa a trabalhar com uma base de código escrita nessa língua, estaríamos aumentando a barreira necessária para a compreensão do código, dificultando a manutenção e aumentando a chance de criação de bugs.

+ +

O Tiago Albineli Motta, do blog “Programando Sem Cafeína”, traz um argumento bem interessante: de que o uso de idiomas diferentes prejudica a comunicação entre cliente e a equipe de desenvolvimento, principalmente quando o domínio do negócio é bastante específico. Para justificar, ele cita o exemplo de quando trabalhava em uma empresa que estava desenvolvimento um sistema para um laboratório geológico. Como os funcionários do laboratório usavam termos em português e a equipe de desenvolvimento em inglês, havia ruídos na comunicação.

+ +

Destaco um trecho interessante abaixo (destaque meu):

+ +
+

Eis então a pergunta: Será que um código que mistura termos em inglês e português causa mais problemas que os ruídos na comunicação com o cliente? Pode-se alegar que o código nem será mostrado ao usuário, mas na hora em que o desenvolvedor precisa se comunicar com o cliente, na mente dele ele não está trabalhando com amostras, ele está trabalhando com samples.

+
+ +

Ainda no tema do domínio, poderíamos imaginar o desenvolvimento de uma aplicação que se integra com a famigerada Nota Fiscal Eletrônica. Como o xml da nota já vem com os campos todos em português, utilizar nomes de variáveis em inglês poderia adicionar um esforço cognitivo desnecessário.

+ +

E a minha opinião?

+ +

Acredito ter sido capaz de demonstrar que existem boas opiniões nos dois lados desse debate. Mas e aí? Vocês devem estar se perguntando qual a minha opinião, não é? Ok, não vou ficar em cima do muro. Mas antes, acho necessário fazer algumas considerações importantes.

+ +

O inglês é a língua franca da tecnologia

+ +

O inglês é a língua franca da tecnologia. E da ciência, das finanças, e de muitas outras coisas. Todo mundo tem o direito de gostar ou não do idioma que quiser, mas é simplesmente contra produtivo querer brigar com um fato da vida que não vai mudar tão cedo. Eu particularmente acho que deveríamos ser gratos que o “idioma obrigatório” é o inglês, e não o russo, árabe, ou mandarim, por exemplo.

+ +

Então, independente do seu posicionamento no debate, aprender inglês é um investimento que vale muito a pena. O que nos leva ao próximo ponto.

+ +

E não é tão difícil de se aprender quanto parece

+ +

Estou convencido de que uma enorme inteligência não é requisito para aprender inglês. Muito menos pagar cursos caros em escolas renomadas, ou fazer intercâmbio. Então por que há tantas pessoas que querem aprender inglês e tão poucas conseguem?

+ +

Em minha opinião, o primeiro motivo é que a maioria dessas pessoas não querem realmente. E o segundo…é simplesmente que elas estudam errado, colocando o foco, tempo e energia no lugar onde não deviam.

+ +

Em breve vou fazer um post totalmente dedicado ao tema do aprendizado de inglês, onde vou expandir e explicar melhor o parágrafo anterior.

+ +

Seu projeto tem características únicas que não devem ser ignoradas

+ +

Seu projeto atual provavelmente tem características únicas, que nem eu, nem o Fabio Akita, nem o Tiago Motta, ou qualquer outra pessoa de fora sabe. Não conhecemos o nível de fluência no inglês da sua equipe, nem o domínio da sua aplicação.

+ +

Também desconhecemos o escopo do seu projeto, se todos os colaboradores são brasileiros ou se há pessoas de outros países,os prospectos de venda da empresa para uma companhia multinacional, etc.

+ +

Ou seja: há uma série de fatores que podem e devem ser levadas em conta no momento de se adotar essa ou aquela prática, essa ou aquela metodologia. Nessas horas, você tem que exercitar o senso crítico: mantenha a mente aberta na hora de ler, pesquisar e conhecer opiniões contrárias, mas use seu bom senso e experiência para filtrar o e decidir o que encaixa com a cultura da sua empresa, equipe e projeto.

+ +

Tentar prever o futuro é anti-ágil.

+ +

Eu costumo chamar isso de síndrome do “vai que um dia”, pois a conversa geralmente começa assim:

+ +

“Vai que um dia o cliente precisa de [insira aqui funcionalidade que o cliente não precisa agora e provavelmente nunca vai precisar]? Vamos fazer!”

+ +

E aí já viu: tabelas inúteis são criadas no banco de dados, classes e mais classes e formulários e telas e muito mais lixo entupindo seu projeto.

+ +

Tentar prever toda e qualquer alteração no projeto é anti-ágil. Equipes ágeis dão pequenos passos, implementando as histórias priorizadas pelo cliente e nada mais. Quando os requisitos mudarem (e vão mudar) nós mudamos junto com eles.

+ +

Entendeu onde eu quero chegar? “Vai que um dia uma empresa internacional resolve comprar nosso sistema? Vamos fazer todo o código e as tabelas em inglês!”

+ +

Em resumo: bom-senso é a chave

+ +

Com base em tudo isso aí que você leu, minha opinião atualmente está assim: tentar utilizar o inglês sempre, exceto quando há ótimas razões para não utilizá-lo.

+ +

Projetos open-source? Tudo em inglês, exceto em casos onde há benefícios claros em usar o português.

+ +

Em projetos particulares: se a equipe é fraca no inglês E/OU o domínio é muito específico e tem termos e jargões de difícil tradução E/OU há riscos claros de prejuízo na comunicação com o cliente, o português provavelmente é a melhor escolha.

+ +

Se a situação é o contrário do descrito acima, inglês sem dúvida.

+ +

Se desde o começo do projeto existe a certeza que a aplicação será disponibilizada para vários países, vocês vão precisar trabalhar em internacionalização, de tudo: especificações, ajuda, interface gráfica. Nesse caso, também não há motivo para não codificar em inglês.

+ +

E você, o que acha?

+ +

Concorda, discorda, prefere não opinar? Deixe um comentário aí em baixo e vamos continuando a conversa!

+ +

Referências

+ + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/reduzir-complexidade-ciclomatica/index.html b/pt/reduzir-complexidade-ciclomatica/index.html new file mode 100644 index 00000000..c470ef8d --- /dev/null +++ b/pt/reduzir-complexidade-ciclomatica/index.html @@ -0,0 +1,606 @@ + + + + + + + + Como Reduzir a Complexidade Ciclomática: Um Guia Completo | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Como Reduzir a Complexidade Ciclomática: Um Guia Completo

+ +
+ +
+

+Foto por Shahadat Rahman no Unsplash

+ +

Nota editorial: Escrevi originalmente este post para o blog da LinearB. Você pode conferir o original em inglês no site deles. Enquanto estiver lá, dê uma olhada no produto deles, uma solução de inteligência de software que usa Git e estatísticas de projetos para ajudar as equipes de desenvolvimento a melhorar sua produtividade.

+ +

Engenheiros(as) de software dignos do nome estão sempre em busca de maneiras de melhorar seu código. A boa notícia é que existe uma maneira confiável de avaliar a saúde de uma base de código e de um projeto, e isso é através do uso de métricas. O post de hoje é sobre uma métrica específica. Você aprenderá como reduzir a complexidade ciclomática e, mais importante, por que você gostaria de fazê-lo.

+ +

Vamos começar definindo a complexidade ciclomática. Depois disso, você aprenderá qual é o problema de ter um alto valor de complexidade ciclomática e por que você precisaria reduzi-la. Depois do “o quê” e do “porquê”, finalmente chegaremos ao “como”: mostraremos as táticas que você pode adotar para reduzir a complexidade ciclomática de seu código. Vamos lá.

+ +

Complexidade Ciclomática: Uma breve definição

+ +

A complexidade ciclomática é uma importante métrica de software. Refere-se ao número de caminhos de execução possíveis dentro de um determinado código - por exemplo, uma função. Quanto mais estruturas de decisão você usar, mais ramificações possíveis existem para seu código.

+ +

A complexidade ciclomática é especialmente importante quando se trata de testes. Ao calcular a complexidade ciclomática de uma função, por exemplo, você sabe o número mínimo de casos de teste que você precisará para alcançar a cobertura de ramificação completa dessa função. Portanto, podemos dizer que a complexidade ciclomática pode ser um preditor de quão difícil é testar um determinado código.

+ +

Um Exemplo de Complexidade Ciclomática Super Simples

+ +

Considere a seguinte função escrita em pseudocódigo:

+ +
void sayHello(name) {
+    print("Hello, ${name}!");
+}
+ +

Como tem uma única declaração, é fácil ver sua complexidade ciclomática é 1. Agora, vamos mudar um pouco as coisas:

+ +
void sayHello(name, sayGoodbye = false) {
+    print("Hello, ${name}!");
+    if (sayGoodbye) {
+        print("Goodbye, ${name}!");
+    }
+}
+ +

A segunda versão da função tem um ramo nela. O chamador da função pode passar true como o valor do parâmetro sayGoodbye, mesmo que o valor padrão seja false. Se isso acontecer, a função imprimirá uma mensagem de adeus após dizer olá. Por outro lado, se o interlocutor não fornecer um valor para o parâmetro ou escolher false, a mensagem de adeus não será exibida.

+ +

Portanto, a função tem dois ramos de execução possíveis, o que é o mesmo que dizer que sua complexidade ciclomática tem um valor de 2.

+ +

Por que a Complexidade Ciclomática é Ruim?

+ +

A complexidade ciclomática não é intrinsecamente ruim. Por exemplo, você pode ter um pedaço de código com um valor complexo ciclomático um pouco alto que é super fácil de ler e entender. Entretanto, de modo geral, podemos dizer que ter uma alta complexidade ciclomática é ou um sintoma de problemas com a base de código ou uma causa potencial de problemas futuros. Vamos cobrir algumas das razões pelas quais você gostaria de reduzi-la com mais detalhes.

+ +

A Complexidade Ciclomática Pode Contribuir para a Complexidade Cognitiva

+ +

A complexidade cognitiva refere-se ao quanto é difícil entender um determinado código. Embora nem sempre seja esse o caso, a complexidade ciclomática pode ser um dos fatores que impulsionam a complexidade cognitiva. Quanto maior a complexidade cognitiva de um pedaço de código, mais difícil é navegar e manter.

+ +

A Complexidade Ciclomática torna o código mais difícil de ser testado

+ +

Como já mencionamos, valores mais altos de complexidade ciclomática resultam na necessidade de um maior número de casos de teste para testar de forma abrangente um bloco de código - e.g., uma função. Portanto, se você quer facilitar sua vida ao escrever testes, provavelmente quer reduzir a complexidade ciclomática de seu código.

+ +

A Complexidade Ciclomática Contribui para Maior Risco de Defeitos

+ +

É mais provável que você introduza defeitos em uma área da base de código que você muda muito do que a uma que você raramente toca. Além disso, quanto mais complexo for um determinado pedaço de código, mais provável é que você o entenda mal e introduza um defeito a ele.

+ +

Portanto, código complexo que sofre muito churn- mudanças freqüentes pela equipe - representa mais risco de defeitos. Ao reduzir a complexidade ciclomática - e, idealmente, também a rotatividade do código - você estará mitigando esses riscos.

+ +

Como Reduzir a Complexidade Ciclomática: 6 Maneiras Práticas

+ +

Agora vamos rever algumas dicas práticas que você pode usar para garantir que a complexidade ciclomática de seu código seja a mais baixa possível.

+ +

1.Preferir funções menores

+ +

O que fazer?

+ +

Sendo todas as outras iguais, funções menores são mais fáceis de ler e entender. Elas também são menos propensas a conter bugs em virtude de seu comprimento. Se você não tem muito código, você não tem muitas oportunidades para o código de bugs. O mesmo raciocínio se aplica à complexidade ciclomática: é menos provável que você tenha um código complexo se tiver menos período de código. Portanto, o conselho aqui é preferir funções menores.

+ +

Como fazer isso?

+ +

Para cada função, identifique sua principal responsabilidade. Extraia o que sobra para suas próprias funções e módulos. Fazer isso também facilita a reutilização do código, o que é um ponto que revisaremos em breve.

+ +

2.Evitar Argumentos de Bandeira em Funções

+ +

O que fazer?

+ +

Os argumentos da bandeira são parâmetros booleanos que você acrescenta a uma função. As pessoas normalmente os utilizam quando precisam mudar o funcionamento de uma função, preservando ao mesmo tempo o antigo comportamento.

+ +

Como fazer?

+ +

O que usar ao invés de parâmetros de bandeira? Em poucas palavras, você pode usar estratégias que alcançam o mesmo resultado sem incorrer em alta complexidade. Por exemplo, você poderia criar uma nova função, mantendo a antiga como está e extraindo as partes comuns em sua própria função privada.

+ +

Se o parâmetro da bandeira estiver sendo usado para melhorar ou melhorar de alguma forma o comportamento da função original, você pode querer aproveitar o [padrão decorator] (https://en.wikipedia.org/wiki/Decorator_pattern) para alcançar o mesmo fim.

+ +

3.Reduzir o número de estruturas de decisão

+ +

O que fazer?

+ +

Você pode considerar este um “não-cérebro”. Se as estruturas de decisão - especialmente se-else e mudar de caso são o que causa mais ramos no código, é lógico que você deve reduzi-los se quiser manter a complexidade ciclomática à distância.

+ +

Como fazer isso?

+ +

Algumas das táticas que acabamos de ver podem contribuir para reduzir o número de se declarações em seu código. Por exemplo, em vez de usar argumentos de bandeira e depois usar uma declaração if* para verificar, você pode usar o padrão decorador. Em vez de usar um caso de troca para rever muitas possibilidades e decidir qual delas o código executará, você pode aproveitar o design pattern strategy. Claro que, em algum ponto do código, você ainda precisará de um estojo de troca. Afinal de contas, alguém tem que decidir qual a implementação real a ser usada. Entretanto, esse ponto se torna o único ponto no código que precisa dessa estrutura de decisão.

+ +

4.Get Rid of Duplicated Code (Livre-se do código duplicado)

+ +

O que fazer?

+ +

Às vezes, você tem funções/métodos que fazem quase a mesma coisa. Manter ambos aumentam a complexidade ciclomática total de sua classe ou módulo. Se você pode limitar suas duplicatas, você pode limitar a complexidade.

+ +

Como fazer?

+ +

Remova as duplicatas de código por:

+ +
    +
  • extraindo os bits de código comuns para seus próprios métodos/funções dedicados.
  • +
  • alavancando padrões de projeto - tais como o design pattern template- que incentivam a reutilização do código.
  • +
  • extraindo funções utilitárias genéricas em pacotes-gems, módulos npm, pacotes NuGet, etc. - que podem ser reutilizados por toda a organização.
  • +
+ +

5.Remover Código Obsoleto

+ +

O que fazer?

+ +

Há muitas razões pelas quais é uma boa idéia remover o código obsoleto, ou seja, o código morto de sua aplicação. Para nosso contexto, basta dizer que essa é uma forma “gratuita” de aumentar a cobertura de código e diminuir a complexidade ciclomática.

+ +

Como fazer isso?

+ +

Basta usar uma ferramenta que lhe permita identificar o código morto - até mesmo sua IDE pode ser capaz de fazê-lo - e depois apagá-lo impiedosamente.

+ +

6.Não Reinvente a Roda

+ +

O que fazer?

+ +

Deixe o desenvolvedor que nunca escreveu uma função - ou mesmo alguns deles - realizar a formatação da data lançar a primeira pedra! É quase como um rito de passagem.

+ +

Escrever código que simplesmente duplica a funcionalidade que a biblioteca padrão de seu idioma ou sua estrutura já oferece é uma maneira segura de aumentar desnecessariamente a complexidade. Se código é uma responsabilidade, você quer escrever apenas a quantidade estritamente necessária.

+ +

Como fazer isso?

+ +

Implemente uma sólida estratégia de revisão de código que seja capaz de identificar e se livrar de tais reinvenções de roda.

+ +

Reduzir a Complexidade Ciclomática, Aumentar a Clareza do Código

+ +

A complexidade ciclomática é uma das métricas mais valiosas na engenharia de software. Ela tem implicações importantes para a qualidade do código e a capacidade de manutenção, sem mencionar os testes. A alta complexidade ciclomática pode ser tanto um sinal de problemas existentes como um preditor de problemas futuros. Portanto, manter o valor desta métrica sob controle é certamente algo que você quer fazer se quiser alcançar uma base de código saudável. Mantê-lo sob controle é exatamente o que você aprendeu com nosso posto.

+ +

Antes de separar os caminhos, uma última advertência. Tenha em mente que nenhuma métrica é uma panacéia quando usada isoladamente. Muitas vezes, o que você realmente gostaria de fazer é rastrear e melhorar um grupo de métricas que, juntos, podem lhe dar uma visão geral da saúde de sua equipe e de seu projeto. Obrigado pela leitura.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/resenha-livro-programador-pragmatico/index.html b/pt/resenha-livro-programador-pragmatico/index.html new file mode 100644 index 00000000..046013f9 --- /dev/null +++ b/pt/resenha-livro-programador-pragmatico/index.html @@ -0,0 +1,498 @@ + + + + + + + + Resenha de Livro: O Programador Pragmático | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Resenha de Livro: O Programador Pragmático

+ +
+ +
+

+Se eu tivesse que escolher apenas um livro como leitura obrigatória de todo programador, eu escolheria “O Programador Pragmático”. Sem hesitar um segundo. Esse livro é simplesmente muito bom. +

+ +

O Programador Pragmático: De Aprendiz a Mestre é um livro de engenharia de software de autoria de Andrew Hunt e David Thomas, publicado originalmente em Outubro de 1999. O livro é organizado em capítulos curtos e auto-contidos, que podem ser lidos em qualquer ordem. Cada capítulo apresenta dicas (há 70 no total) que oferecem conselhos em diversos tópicos, tais como, estimativas, testes, debugging, como prototipar, como se comunicar de maneira eficaz, boas práticas no uso de exceções, e muito mais.

+ +

Cada capítulo também tem excercícios e/ou desafios. Qual a diferneça? Todos os excercícios têm respostas, e você pode encontrá-las no apêndice ao final do livro. Os desafios, por outro lado, não possuem necessariamente uma resposta certa. Eles foram feitos de maneira a te fazer pensar, refletir e (adivinha!) desafiar a si próprio e ao jeito que você está acostumado a fazer as coisas.

+ +

Uma coisa que eu gosto muito nesse livro é que ele é muito prático. É claro que a teoria tem o seu valor e seu lugar, e eu pessoalmente acredito que muitos programadores têm lacunas em seu conhecimento dos fundamentos da Ciência da Computação, e isso acaba prejudicando a nossa área. Dito isso, eu acho incrível que dois programadores tomaram o tempo de traduzir os seus anos de experiência e conhecimento em um livro que vai direto ao ponto com conselhos muito práticos que você consegue colocar em uso imediatamente.

+ +

Outro ponto que merece destaque é o fato de que esse livro é muito fácil e divertido de ser lido. Os capítulos e seções são bem curtos, o que +proporciona um ritmo agradável. Ele também possui um ótimo senso de humor. Não do tipo que faz você rir histericamente, mas sim aquele que te deixa confortável, como se o livro fosse uma conversa.

+ +

Mas eu acho que a coisa que eu mais gosto a respeito de “O Progamador Pragmático” é que ele não é realmente focado em código, ou preso a alguma tecnologia específica, ou ferramentas específicas. Claro, ele tem sua parcela de trechos de código (principalmente Java e C/C++). Sim, ele menciona algumas ferramentas ou aplicações específicas. Mas na maior parte, esse livro é sobre uma mentalidade. Um jeito específico de pensar, uma maneira de abordar problemas e desafios. Quando essa mentalidade, essa “filosofia pragmática”, estiver realmente enraizada na sua maneira de pensar, você será capaz de aplicá-la a diversas áreas da sua vida profissional, não apenas codifição. E eu acho que essa é realmente a maior força desse livro. Caso ele fosse focado em ferramentas ou alguma linguagem específica, eu provavelmente não estaria escrevendo sobre ele agora, quase 17 anos depois.

+ +

Alguns contras

+ +

Claro, agora que eu já elogiei bastante esse livro, vou falar um pouco sobre os pontos negativos dele. E olha, pra ser honesto, não é tão fácil achar coisas pra criticar nele não, viu? Mas se tem algo que eu penso que a maioria dos leitores concordaria, é que certos trechos do livro estão claramente datados.

+ +

Tipo, dá um tempo. Já são quase duas décadas. É incrível um livro sobre desenvolvimento de software permanecer influente por tanto tempo. É claro que pelo menos algumas partes têm que estar desatualizadas. Por exemplo, uma das dicas é “sempre use controle de versão”. Hoje em dia, controle de versão é algo que tomamos por garantido, qualquer desenvolvedor que se preze conhece o Github, então chega a ser engraçado ler essa recomendação. É igual quando você assiste o vídeo do Steve Jobs apresentando o primeiro iPhone, e você vê o público alucinado por causa das funcionalidades do aparelho, que podem não ser grande coisa para os padrões de hoje, mas eram incríveis naquela época. (Sim, eu sei que existem empresas por aí na qual os desenvolvedores nem ao menos sabem que existe controle de versão. Minha dica é: se você trabalha em um lugar assim, tente ensiná-los sobre controle de versão. Se der certo, ótimo! Se não, saia daí o mais rápido possível.)

+ +

Em outro trecho do livro, eles explicam uma ténica chamado “desenvolvimento tracer-bullet”. O nome pode ser um pouco estranho, mas quando eles começam a explicação, você pode perceber que é bastante parecido com o conceito de “mínimo produto viável”, que você talvez tenha aprendido nas metodologias ágeis.

+ +

O que não deveria ser uma empresa, já que Andy Thomas e Dave Hunt estavam entre os signatários do já lendário Manifesto Para Desenvolvimento Ágil de Software.

+ +

Conclusão

+ +

É por isso que é difícil achar algo pra criticar nesse livro. Veja bem, ele pode parecer um pouco datado hoje em dia, mas isso é justamente porque os autores estavam a frente de seu tempo. Algumas coisas que são comuns e óbvias hoje, eram totalmente não-óbvias e até mesmo contra-intuitivas quase 20 anos atrás. Foi preciso muita visão para escrever esse livro, e é por causa disso, e tudo o mais acima, que eu acredito que esse livro é uma leitura digna do seu tempo.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/revisao-codigo-vs-programacao-em-par/index.html b/pt/revisao-codigo-vs-programacao-em-par/index.html new file mode 100644 index 00000000..a255920d --- /dev/null +++ b/pt/revisao-codigo-vs-programacao-em-par/index.html @@ -0,0 +1,603 @@ + + + + + + + + Revisão de Código vs Programação em Par: Qual a sua equipe deve escolher? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Revisão de Código vs Programação em Par: Qual a sua equipe deve escolher?

+ +
+ +
+

+ +

NOTA: Eu escrevi este post originalmente para o blog da SubMain. Você pode conferir o artigo original no site deles, em inglês. Enquanto estiver por lá, dê uma conferida no CodeIt.Right, uma ferramenta que pode lhe ajudar com automação de revisões de código.

+ +

Algumas semanas atrás, eu estava olhando o Twitter quando vi isso:

+ + + + +

O que se seguiu foi uma breve discussão entre o autor e eu. Ele apresentou bons argumentos, mas eu continuei não convencido de que programação em par (pair programming) era um vencedor tão óbvio.

+ +

Como eu já havia implementado práticas de revisão de código (code review) com sucesso e também pareado até certo ponto, eu não tinha dificuldades em ver como as duas práticas podem ser valiosas. Mas será que uma deles é claramente melhor que a outra? Revisão de código e programação em par são intercambiáveis, ou há cenários em que um ou outro claramente se destaca?

+ +

É o que vou responder hoje. Vamos lá.

+ +

O que quero dizer por “Revisão de Código”

+ +

Imagine a seguinte cena: você é um(a) jovem programador(a) em seu primeiro trabalho com desenvolvimento de software. Após terminar sua primeira tarefa, você é convocado(a) a uma sala de reunião; lá você encontra o desenvolvedor líder e três desenvolvedores seniores. Um monitor enorme está ligado exibindo seu código. Hora da revisão!

+ +

Durante duas horas e meia sofridas, seu código é julgado sem só enquanto você sua profusamente. Desde suas decisões de projeto até as mais triviais preferências estilísticas, nada escapa da enxurrada de críticas.

+ +

É essa a cena exibida na sua mente quando você vê as palavras “revisão de código”?

+ +

Boa notícias pra você, então. Este não é o tipo de revisão de código sobre o qual estou falando. Ao invés, pense em um processo bem leve e informal. Você submete seu código para revisão criando um pull request ou mesmo usando alguma funcionalidade incorporada na sua IDE.

+ +

A parte boa

+ +

Após tocar brevemente no “o que” e no “como” de uma revisão de código, hora de abordarmos o “por que”. Por que o seu time deve adotar a prática? Quais são os benefícios?

+ +

A primeira razão, não surpreendentemente, é detectar bugs. Eu aposto que você é familiar com aquela velha pérola de sabedoria que diz que quanto mais tarde um defeito é encontrado, maior é o custo para sua resolução. Sendo assim, por que não usar um processo relativamente barato que pode encontrar até 60% dos defeitos?

+ +

Outra razão para a sua empresa adotar revisões de código: melhorar a legibilidade do código. Tentar ler e entender um trecho novo de código frequentemente leva à descoberta de problemas como:

+ + + +

O revisor também pode encontrar corner cases que passaram despercebidos ou ajudar na avaliação de performance do código escrito.

+ +

E chegamos à última razão. Uma revisão de código bem feita pode espalhar conhecimento pelo time. Isso destrói ilhas de conhecimento na equipe, melhorando a qualidade final do produto.

+ +

A parte ruim

+ +

Enquanto alguns dizem que a revisão de código é a prática mais importante que você deve adotar para aperfeiçoar seu código, tal entusiasmo não é universal. Assim, não poderíamos deixar de falar também das potenciais desvantagens da prática.

+ +

A queixa mais comum sobre revisão de código tem a ver com tempo. Quando você envia algum código para revisão, você obviamente precisa esperar até que a revisão seja finalizada.

+ +

O que fazer durante a espera? Idealmente, sua equipe deveria quebrar o trabalho disponível em unidades pequenas e discretas, que possam ser resolvidas de maneira mais ou menos independente. Nem sempre isso é prático, porém. E falando nisso, a própria troca constante de tarefas pode ser prejudicial para seu foco e produtividade.

+ +

Digamos que o Bruno gastou x horas implementando uma funcionalidade. Então a Ana revisa o trabalho dele e diz que a implementação está completamente errada, e ele precisa refazer tudo. Aquelas x horas de desenvolvimento acabaram de ir para o lixo.

+ +

Finalmente, às vezes as pessoas desperdiçam quantidades ridículas de tempo discutindo sobre detalhes estéticos inúteis, como a posição das chaves, ou se devem ou não incluir um underscore no nome de um campo privado. Infelizmente, debates idiotas assim às vezes escalam para níveis que tornam o local de trabalho tóxico.

+ +

Programação em Par: Mais que uma super revisão de código

+ +

Programação em par é uma técnica na qual duas pessoas colaboram no código juntas, na mesma estação de trabalho.

+ +

Elas periodicamente revezam em dois papéis. O piloto escreve o código, pensando em voz alta para explicar suas decisões e o que está pensando. O navegador observa o piloto, dando feedback e opiniões em tempo real.

+ +

Seria a programação em par nada mais que “code review on steroids”, como coloca Jeff Atwood?

+ +

Talvez não. Um dos princípios básicos das metologias ágeis é que o desenvolvimento de software se beneficia de ciclos de feedback curtos. Levando isso em consideração, trazer a revisão de código para o mais cedo possível no processo faria bastante sentido, por estar em harmonia com os princípios ágeis.

+ +

A parte boa

+ +

Não deveria ser surpresa que a programação em par compartilha vários dos benefícios da revisão de código, como detecção de bugs, melhoras na legibilidade do código e propagação de conhecimento pela equipe.

+ +

Mas a programação em par também pode oferecer benefícios exclusivos, tais como:

+ + + +

A parte ruim

+ +

Assim como no caso da revisão de código, programação em par está longe de ser uma prática universalmente aceita. Enquanto muitas pessoas amam a prática, outras não têm histórias tão felizes para contar

+ +

Vamos começar com uma reclamação comum: programação em par pode ser extremamente cansativa. Na verdade, não é incomum ourvir que parear é mais eficaz quando usado por blocos de tempo curtos — de 1 hora a 2 horas e meia.

+ +

Evidentemente, um número ímpar de integrantes na equipe não combina muito bem com programação em par. Mas um número flutuante de pessoal disponível é inevitável.

+ +

O próximo item na nossa lista de problemas é o fato de que programação em par não é muito compatível com trabalho remoto. Você pode ter uma ideia melhor do problema após ouvir o que Daniel Kaplan, que escreveu “What It’s Like to Pair for a Year,” tem a dizer sobre programação em par:

+ +
+

These scheduling interruptions happen, but on a typical day we avoid them by having the pairs show up at the same time (for breakfast and standup), go to lunch at the same time, and leave at the same time. This maximizes the time the pairs are pairing.

+
+ +

Em tradução livre, com grifo meu:

+ +
+

Tais interrupções ocorrem, mas em um dia típico nós conseguimos evitá-las fazendo com que os pares cheguem na mesma hora (para café da manhã e reunião em pé), vão almoçar no mesmo horário, e vão para casa no mesmo horário. Isso maximiza o tempo que os pares passam programando juntos.

+
+ +

Então, programação em par requer sincronismo, o que pode torná-la uma opção inviável para equipes remotas (ou mesmo equipes que trabalham no mesmo local mas tem horários extremamente flexíveis).

+ +

Tem gente que argumenta que trabalhar em pares pode prejudicar a criatividade e impedir experimentações. Durante uma sessão em par, pode ser considerado rude desperdiçar o tempo de seu par tentando uma abordagem experimental que pode talvez não dar em nada. Então, a decisão mais segura possível tende a prevalecer sempre, mesmo que não seja a melhor possível.

+ +

Finalmente, a programação em par não fornece um dos benefícios chave da revisão de código posterior: ter uma pessoa com zero contexto analisando o código produzido. As duas pessoas do par compartilham contexto desde o início da sessão, o que não deve ser subestimado. As pessoas têm uma tendência a superestimar o valor de suas contribuições e criar laços emocionais com o que elas criam; por isso é tão importante conseguir uma outra pessoa que, livre desses laços, será capaz de oferecer um julgamento mais claro.

+ +

Revisão de Código vs Programação em Par: O Veredito?

+

Eu cheguei à conclusão de que, embora revisão de código e programação em par pareçam equivalentes, na verdade não são. Existe uma intersecção ali, mas cada prática também apresenta benefícios e desafios únicos.

+ +

Não tem como fugir do fato de que programação em par, apesar de seus benefícios, requer um número par de pessoas, trabalhando ao mesmo tempo. Se seu time consiste de pessoas vivendo em diversos fusos horários diferentes (ou mesmo uma equipe local mas com horário flexível), é fácil decidir: revisão de código na cabeça.

+ +

Se a sua equipe não se encaixa na descrição acima, então eu digo: faça uma tentativa com programação em par. Contanto que você se esforce para acomodar e ter empatia com diferentes tipos de personalidades e não torne obrigatório, programação em par pode ser benéfica para sua equipe.

+ +

Finalmente, não há nada lhe impedindo de usar ambas práticas. Você pode adotar programação em par como o Modus Operandi padrão e deixar e revisão de código para preencher os vácuos onde o pareamento não funciona tão bem.

+ +

De um jeito ou de outro, abrace a automação

+

Imagine que você escreve para uma publicação, como uma revista. Após finalizar um rascunho, ele precisa ser submetido para revisão. Será que faz sentido para a editora gastar todo seu tempo procurando por erros de ortografia? É claro que não! Nós temos ferramentas para checar tais erros de forma automática, liberando a editora para procurar por problemas em um nível mais alto, como vocabulário mal escolhido, falta de coesão, tom inapropriado, e todas aquelas coisas sobre as quais a sua professora de português não dava sossego.

+ +

Com software não é diferente. Ao usar uma ferramenta de revisão de códigos automatizados, você pode eliminar muitas das discussões inúteis que acontecem frequentemente em revisões de código ou sessões de programação em par. Não vai ter mais briga sobre convenções estéticas e de nomenclatura, posição de chaves e outras trivialidades inúteis.

+ +

You can also employ a static analysis tool to warn you about potential bugs and opportunities for refactoring. That way, the reviewer/navigator is free to focus on the high-level stuff that requires human creativity, intelligence, and empathy.

+ +

Você também pode usar uma ferramenta de análise estática para lhe alertar sobre potenciais bugs e oportunidades para refatoração. Assim, o revisor/navegador fica livre para focar em preocupações de mais alto nível que necessitam da criatividade, inteligência e empatia humanas.

+ +

Confiança e respeito

+

Quando estava pesquisando para escrever esse post, um tema aparecia bastante: pessoas afirmando que revisão de código surge devido à falta de confiança em nossos desenvolvedores ou que programação em par os infantiliza.

+ +

Eu não poderia discordar mais.

+ +

É exatamente por respeitarmos nossos colegas e clientes que devemos empregar técnicas e ferramentas à nossa disposição para melhorar a qualidade do trabalho que produzimos.

+ +

Não é falta de confiança. É reconhecer que programar é difícil e às vezes, só um cérebro pode não dar conta do recado.

+ + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/testes-de-mutacao/index.html b/pt/testes-de-mutacao/index.html new file mode 100644 index 00000000..b1022b41 --- /dev/null +++ b/pt/testes-de-mutacao/index.html @@ -0,0 +1,546 @@ + + + + + + + + Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante

+ +
+ +
+

+ +

Photo by Christina @ wocintechchat.com on Unsplash

+ +

NOTA: Este post foi originalmente escrito para o blog da NCrunch. Você pode ler o artigo original, em inglês, no site deles.

+ +

Sou fascinado com o conceito de testes de mutação desde que os conheci. Pensei finalmente ter encontrado a resposta para tantos problemas que tive ao escrever testes. Com os testes de mutação, agora eu tinha uma maneira de realmente confiar em meus testes. Finalmente, a cobertura de código tinha significado novamente.

+ +

Então, fiquei atônito ao perceber que muito poucos desenvolvedores compartilhavam meu interesse em testes de mutação. Na verdade, ouso dizer que a maioria dos desenvolvedores ainda nem sequer ouviu falar sobre isso. E isso é uma pena porque eles - e nós, como uma indústria - estamos perdendo tantos benefícios.

+ +

Portanto, este posto é minha humilde tentativa de remediar a situação. Vou começar por explicar os atuais dilemas que os desenvolvedores enfrentam em relação à confiabilidade dos testes que escrevem. Em seguida, vou prosseguir para lhe mostrar como os testes de mutação são a resposta a estes dilemas. Explicarei o que é, como pode tornar seus testes mais confiáveis, e como pode transformar a cobertura de código na valiosa métrica que deve ser.

+ +

O problema: a confiabilidade dos testes

+ +

Ao aprender sobre testes unitários - ou testes automatizados em geral - a maioria das pessoas fará a mesma pergunta ou uma pergunta semelhante: Como sei que meus testes estão corretos? Essa é uma preocupação legítima. Se seus testes não são confiáveis, então talvez você esteja melhor sem nenhum teste.

+ +

Então, qual é a resposta? Como as pessoas lidam com o problema da confiabilidade dos testes sem depender de testes de mutação?

+ +

Tornando os testes confiáveis sem testes de mutação

+ +

Há técnicas que os desenvolvedores empregam para melhorar a confiabilidade de seus testes, e cobriremos brevemente algumas delas nesta seção. Se você tem experiência com testes unitários, provavelmente está familiarizado com essas técnicas. Vamos lá.

+ +

Manter os testes simples

+ +

A primeira técnica que cobriremos aqui para melhorar a confiabilidade de seus testes é apenas mantê-los simples. E por “simples” quero dizer com menos complexidade ciclomática. Quanto menor a complexidade ciclomática de um determinado código, mais provável é que ele realmente faz o que você pensa que faz. O código simples é mais fácil de entender, que é uma propriedade que você definitivamente quer que seus testes unitários tenham.

+ +

Mantenha o código de teste simples ao ponto de ser óbvio. Isso significa, por exemplo, evitar loops ou estruturas de decisão. Além disso, evite fazer qualquer coisa para computar o resultado esperado (mais sobre isso na próxima seção). Em vez disso, codifique-o de maneira fixa.

+ +

Não Duplique o Código de Implementação

+ +

Digamos que você esteja praticando o Coding Kata dos números romanos. Resista à tentação de gerar automaticamente os valores esperados (“I” para 1, “II” para 2, e assim por diante). Em vez disso, codifique os valores de forma fixa. Se a repetição realmente o incomoda e sua ferramenta de teste o permite, use testes parametrizados.

+ +

Por que isso seria um problema? Simples: Quanto mais sofisticado for o código de teste, mais provável é que seja uma duplicação do código de produção. Se este for o caso, você pode ter o azar de se encontrar na situação em que seu código de produção está errado (não resolve o problema como deveria fazer), mas os testes passam. Esse é um dos piores cenários possíveis. É ainda pior do que não ter nenhum teste.

+ +

Garanta que você veja o teste falhar

+ +

Garantir que cada teste falhe pelo menos uma vez antes de ser aprovado. Se você vê o teste falhar quando acha que deveria estar falhando e vice-versa, isso é um sinal de que você está se movendo na direção certa. Não garante nada, mas diminui a probabilidade de o teste estar passando devido a uma coincidência.

+ +

Como fazer isso? Assim que você chegar à fase verde, danifique o código de implementação de tal maneira que um ou mais testes devem falhar. Você poderia inverter os condicionantes, substituir strings ou literais numéricos por valores aleatórios, ou mesmo apagar um if. Se você conseguir sabotar o código de produção e se safar, isso não é um bom sinal. Seu conjunto de testes ou está errado ou incompleto. Em certo sentido, você está testando os testes.

+ +

Desenvolvedores que empregam TDD (desenvolvimento orientado a testes) já fazem isso, por definição. Uma vez que você escreve um teste falho e depois procede para que ele seja aprovado, você está vendo o teste falhar. É claro, o teste deve falhar da maneira esperada. Isso significa que se você estiver realizando uma asserção, o teste deve falhar devido a uma falha na asserção e não, digamos, porque o método sob teste lança uma exceção. Sim, isto é melhor do que nada, mas ainda assim pode não ser suficiente. Como um teste unitário representa um caso de uso único, é totalmente possível introduzir um defeito no código de produção de tal forma que este teste em particular ainda passe.

+ +

Temos que fazer melhor: É Aí Que Entra o Teste de Mutação

+ +

Então, você acabou de aplicar a técnica descrita na última seção. Ótimo! Não é perfeita, porém. Aí vem um problema. Você não pode simplesmente inserir muitos defeitos e executar os testes, pois não seria capaz de identificar qual defeito foi responsável pelo fracasso dos testes. A maneira correta de fazer isso é inserir um único defeito deliberado, executar todos os testes, verificar seu resultado e então reverter a mudança. Depois disso, você pode introduzir outro erro, executar todos os testes novamente, verificar o resultado, reverter a mudança…e repetir, muitas vezes. Nem precisa dizer que tal abordagem é extremamente lenta, entediante e propensa a erros.

+ +

É aí que entram os testes de mutação.

+ +

O que é teste de mutação, afinal?

+ +

O teste de mutação é nada mais, nada menos, do que automatizar todo o processo de “sabotar o código de produção e executar testes para ver se eles falham” que você acabou de ver. Para usar o teste de mutação, você precisa de um framework, ou ferramenta, de teste de mutação. O framework irá alterar o código de produção, introduzindo defeitos que são chamados de “mutações”. Para cada mutação introduzida, o framework executará novamente o conjunto de testes unitários. Se todos os testes forem aprovados, dizemos que a mutação sobreviveu. Isso é uma coisa ruim. Significa que ou seu conjunto de testes está faltando ou os testes existentes estão errados.

+ +

Se, por outro lado, um ou mais testes falharem, isso significa que a mutação foi morta, o que é uma coisa boa. A ferramenta repetirá esse processo até que se teste a parte relevante da base de código. Quando tudo estiver feito, você poderá verificar os resultados, que conterão o número de mutações introduzidas, assim como a proporção de mutantes sobreviventes vs. mutantes mortos.

+ +

Os testes de mutação melhoram a cobertura do código

+ +

Um dos tópicos mais controversos no mundo dos testes de unidade é o argumento sobre a cobertura de código. Alguns desenvolvedores dizem que chegar à cobertura total é essencial; outros argumentarão que é uma métrica inútil. Quem está certo?

+ +

Primeiro de tudo, é preciso entender que esta questão não é preto no branco. Como é o caso de praticamente tudo em software, há alguma nuance. É claro que a cobertura de código não é inútil. Saber que sua base de código tem, digamos, 10% de cobertura de teste é definitivamente um dado útil. Tal cobertura é muito baixa: ver a barra verde não lhes oferecerá nenhuma confiança. Isso não quer dizer que ter 100% de cobertura é necessariamente uma coisa boa em si mesmo. Você poderia ter testes que não têm afirmações, por exemplo. Sim, este é um exemplo elaborado, mas algo assim poderia (e às vezes acontece) acontecer.

+ +

Uma ocorrência mais comum seria ter apenas testes que não exercitam suficientemente os caminhos no software. Em resumo: baixa cobertura de código é definitivamente uma coisa ruim, mas alta (ou total) cobertura de código não é necessariamente uma coisa boa, uma vez que não diz nada sobre a qualidade dos testes na suíte.

+ +

Como os testes de mutação verificam a qualidade da suíte de testes, é a peça que falta no quebra-cabeça. Se sua base de código tem uma alta cobertura de código e os resultados dos testes de mutação mostram que a maioria ou todas as mutações introduzidas estão sendo mortas, então sorria! Você provavelmente tem uma ótima suíte de teste no lugar!

+ +

Testes de Mutação Abrace Hoje

+ +

No post de hoje, falamos sobre o problema da confiabilidade dos testes, depois procedemos a uma revisão de algumas técnicas e diretrizes que você pode usar para superar esse desafio. Finalmente, vimos como o teste de mutação é a abordagem superior para resolver esse problema.

+ +

Eis o seguinte: As técnicas que abordamos são boas diretrizes a serem seguidas ao escrever testes unitários. Seus testes serão beneficiados por cumpri-los, quer você empregue ou não testes de mutação. Mas as diretrizes só podem levá-lo até agora. Elas dependem muito da força de vontade e disciplina humanas, e todos nós temos quantidades limitadas delas. A fim de levar a qualidade de seus testes ao próximo nível, você precisa adotar a automação.

+ +

São necessários apenas alguns minutos de pesquisa no Google para encontrar uma ferramenta de teste de mutação para a plataforma de sua preferência. Faça isso hoje e comece a aproveitar os benefícios que os testes de mutação podem oferecer a você e à sua equipe!

+ + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/testes-unitarios-csharp-intro-tdd/index.html b/pt/testes-unitarios-csharp-intro-tdd/index.html new file mode 100644 index 00000000..d4676f48 --- /dev/null +++ b/pt/testes-unitarios-csharp-intro-tdd/index.html @@ -0,0 +1,907 @@ + + + + + + + + Testes Unitários em C#: Iniciando Com TDD | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Testes Unitários em C#: Iniciando Com TDD

+ +
+ +
+

+ +

Este post faz parte de uma série. Veja os outros artigos.

+ +

Hoje eu trago outro post para ajudá-los a começar com os testes da unidade C#. Já cobri o básico de testes unitários, explicando o que eles são e por que são tão importantes. Depois disso, mostrei como começar com os testes unitários com um exemplo prático. Hoje, vamos um passo adiante, explorando a metodologia TDD.

+ +

Você provavelmente já ouviu falar de TDD, mas pode ficar confuso quanto ao que é. A propósito, isto não é culpa sua. Há muitos equívocos em torno desta sigla. Algumas pessoas até a usam de forma intercambiável com os testes unitários. Neste post, você vai aprender por que eles estão errados, e mais.

+ +

Começamos o post com uma breve definição de TDD. Você aprenderá não apenas que TDD significa Desenvolvimento Orientado por Testes, mas também que não é uma técnica de teste, apesar do nome. Depois disso, eu explico o que é TDD e quais são seus benefícios.

+ +

Após o “o quê” e o “porquê” estarem ambos fora do nosso caminho, estaremos prontos para nos divertir um pouco. Vou lhes mostrar, na prática, como começar com a TDD, desenvolvendo uma solução para um famoso exercício de programação. Soa bem? Então, vamos começar.

+ +

Testes Unitários em C# & TDD: Começando Pelo Básico

+ +

Já mencionei anteriormente que o TDD não é uma técnica de teste. Mas o que é isso? E como está relacionado ao teste de unidade C# (ou teste de unidade em geral, já agora?)

+ +

Definindo TDD

+ +

Como você já viu, TDD significa “Test-Driven Development”, ou “Desenvolvimento guiado por testes.” É uma técnica ou metodologia de desenvolvimento de software que utiliza testes unitários para guiar ou dirigir o desenvolvimento da aplicação.

+ +

Em vez de fazer a coisa mais intuitiva, que seria escrever testes unitários após o código de produção, a metodologia TDD afirma que você deve começar escrevendo um teste unitário falho. Depois você escreve o código de produção, mas apenas o necessário para que o teste seja aprovado.

+ +

Acho que agora você está se perguntando pelo menos duas coisas:

+ +
    +
  • Como isso funciona na prática?
  • +
  • Por que escrever o código de uma maneira tão estranha?
  • +
+ +

É o que vamos ver a seguir.

+ +

As fases do TDD

+ +

O desenvolvimento orientado por testes depende da repetição de um ciclo incrivelmente curto. Este ciclo é composto de três fases:

+ +
    +
  1. Primeiro, você escreve um teste que representa um requisito específico da funcionalidade que você está tentando implementar.
  2. +
  3. Em seguida, você faz o teste passar, escrevendo a quantidade mínima de código de produção com a qual você pode escapar.
  4. +
  5. Se necessário, você refatoria o código para eliminar duplicações ou outros problemas.
  6. +
+ +

Como a funcionalidade ainda não existe, o teste que você escreve no passo nº 1 falhará. Ou seja, em linguagens como Python ou Ruby. No caso de linguagens estaticamente digitadas, como Java ou C#, o código nem sequer será compilado. Para nossos propósitos, a não compilação do código conta como falha no teste.

+ +

No passo 2, você tem que fazer o teste passar, mas nada além disso. O que eu quero dizer é que seu objetivo aqui não é resolver o problema, pelo menos ainda não. Ao invés disso, seu único trabalho é fazer o teste passar, escrevendo a menor quantidade possível de código. Fazer batota - por exemplo, devolver um valor codificado - não só é OK, mas encorajado, como você logo verá.

+ +

Finalmente, a terceira fase é a única que permite a você escrever o código de produção sem ter que criar primeiro um teste de reprovação. Mas você não pode criar novas classes ou funções; você só pode refatorar o código que você escreveu na etapa anterior, para torná-lo mais legível, para eliminar a duplicação ou para resolver outro problema. E, é claro, o teste ainda deve ser aprovado.

+ +

As pessoas freqüentemente usam o TDD como “red green-refactor” porque a maioria das ferramentas de teste de unidade usa vermelho para denotar testes fracassados e verde para passar nos testes.

+ +

Por que usar o TDD?

+ +

O difícil de entender quando se começa a usar o TDD não é o como. O “como” é trivial: escrever um teste, faze-lo passar, talvez refatorar, enxaguar, repetir. A parte preocupante é o “por quê”. Por que desenvolver software de uma maneira tão não-intuitiva?

+ +

Vou falar mais sobre a filosofia TDD em artigos futuros. Em poucas palavras, aplicar TDD garante que você terá um código testável desde o início. Ele o incentivará a projetar seu código de uma maneira simples e modular.

+ +

Mas talvez a principal vantagem do TDD seja aumentar a confiança do desenvolvedor em seu código. Ao desenvolver um pequeno passo de cada vez, você nunca será capaz de errar muito, já que está fazendo muito pouco. Saber que você está apenas a um teste de reprovação de ter um código de trabalho é reconfortante.

+ +

Testes Unitários em C# & TDD: O Guia Mão-Na-Massa

+ +

Eu cobri como começar com os testes de unidade C# no passado. Eu também cobri as ferramentas necessárias e como começar. Entretanto, não vou assumir que você tenha lido esses artigos. Em vez disso, vou cobrir tudo a partir do zero. Assim, você será capaz de seguir o tutorial mesmo que tenha zero de experiência com testes unitários.

+ +

Nosso problema: O Kata String Calculator

+ +

Para nosso tutorial, escreveremos uma solução para o coding kata String Calculator, idealizado pelo Roy Osherov. Um kata de codificação é um exercício de programação, destinado a permitir que os desenvolvedores pratiquem práticas de engenharia de software ágeis fundamentais, como a refatoração, e - você adivinhou - TDD.

+ +

Para simplificar, vou ignorar algumas das exigências do kata. O que se segue são as exigências que vamos utilizar:

+ +
    +
  1. Vamos criar uma classe chamada StringCalculator, com um único método estático com a assinatura estática int Add(string numbers);
  2. +
  3. O método pega uma string representando números separados por uma vírgula, e retorna sua soma.
  4. +
  5. Se passarmos uma string vazia, o método deve retornar zero.
  6. +
  7. A passagem de um único número deve resultar no próprio número.
  8. +
  9. Se passarmos números negativos, o método deve lançar uma ArgumentException, com a mensagem “Números negativos não permitidos:” seguida dos negativos que foram especificados.
  10. +
  11. O método deve ignorar números maiores que 1000 devem. Portanto, “1.2.1000” deve resultar em 1003, mas “1.2.1001” deve resultar em 3.
  12. +
+ +

Criando o Projeto de Produção

+ +

Para este tutorial, estarei usando a edição comunitária do Visual Studio 2019. Se você ainda não o tem, pode baixá-lo e instalá-lo de graça.

+ +

Abra o VS e clique em “Criar um novo projeto”, como na imagem a seguir:

+ +

+ +

Na janela aberta, escolha Biblioteca de Classes (.NET Core) como modelo para o novo projeto. Em seguida, clique em “Next” (Próximo):

+ +

+ +

A tela seguinte simplesmente pede um nome para o projeto e a solução. Eu escolhi” StringCalculatorKata” tanto para o projeto quanto para a solução. Você também terá que fornecer um local para salvar os arquivos do projeto. Quando terminar, basta clicar em “Criar”.

+ +

Se tudo correr bem, você deverá ver a classe padrão aberta para você no Visual Studio. Vá ao Solution Explorer e exclua essa classe; não vamos precisar dela.

+ +

Criando o Projeto de Teste

+ +

Agora, é hora de criar o projeto de teste. Poderíamos fazer isso de duas maneiras: criando um projeto regular de “Biblioteca de Classe” e depois adicionando as dependências necessárias a ele, ou criando um projeto de teste de unidade imediatamente. Iremos com este último, já que facilita tudo isso.

+ +

Você conhece o procedimento: clique com o botão direito do mouse na solução, vá para “Adicionar”,depois para “Novo Projeto…”. Em seguida, escolha o modelo “NUnit Test Project (.NET Core)”.

+ +

Em seguida, você deverá fornecer um nome e um local para o projeto. Gosto de seguir a convenção de nomear o projeto de teste após o projeto de produção, com um “.Test” adicionado. Portanto, escolho “StringCalculatorKata.Test”. Terminar a criação do projeto.

+ +

Se tudo correr bem, você deve ver agora uma nova classe que se parece com esta:

+ +
public class Tests
+{
+    [SetUp]
+    public void Setup()
+    {
+    }
+
+    [Test]
+    public void Test1()
+    {
+        Assert.Pass();
+    }
+}
+ +

Vamos fazer algumas coisas. Primeiro, livre-se do método Setup(). Não vamos precisar dele. Depois, acrescente um novo método com o código abaixo:

+ +
[Test]
+public void Test2()
+{
+    Assert.Fail();
+}
+ +

Portanto, agora temos dois testes, um que deve passar e outro que deve falhar. Vamos examiná-los para ver se eles estão funcionando corretamente. Vá ao menu “Executar” e clique em “Executar todos os testes”.

+ +

Agora, abra a janela Test Explorer (View -> Test Explorer). Deve ser parecido com isto:

+ +

+ +

Parece que tudo está funcionando bem! Mas antes de começarmos a fazer nosso exercício de codificação do kata, há dois passos finais que precisamos dar. Primeiro, vamos renomear a classe de teste. Ir para o explorador de soluções, expandir o projeto de teste de unidade, e excluir sua classe de teste padrão. Depois, clique com o botão direito do mouse no projeto de teste, vá para “Adicionar”, depois para “Nova classe…” e adicione uma nova classe chamada “StringCalculatorKata”. Alternativamente, você pode renomear a classe existente.

+ +

A segunda coisa que temos que fazer é garantir que nosso projeto de teste possa ver nosso projeto de produção. Para resolver isso, estamos acrescentando uma referência.

+ +

Vá até o explorador de soluções novamente, clique com o botão direito do mouse no projeto de teste, depois vá até “Adicionar” e clique em “Referência…”.

+ +

Na nova janela, selecione “Projetos” no painel esquerdo, e depois selecione o projeto StringCalculatorKata, que deve ser o único disponível:

+ +

+ +

Depois, basta clicar em “OK”, e agora você está pronto para continuar.

+ +

Iniciando nosso Kata de Codificação

+ +

Agora, estamos prontos para escrever nosso primeiro teste de reprovação. Portanto, abra a classe StringCalculatorTest e acrescente a ela o seguinte método

+ +
[Test]
+public void Add_EmptyStringAsParam_ReturnsZero()
+{
+    Assert.AreEqual(0, StringCalculator.Add(string.Empty));
+}
+ +

Em nosso primeiro caso de teste, testamos o cenário mais simples possível. Ou seja, chamamos o método Add de passar uma string vazia, que, de acordo com os requisitos que você viu antes, deve resultar em 0. É claro que nem o método Add nem a classe StringCalculator existem, portanto nosso código nem sequer é compilado. Bem, parabéns! Você realizou com sucesso o primeiro passo no ciclo vermelho-verde-refator, escrevendo um teste de reprovação! Lembre-se: em idiomas estaticamente digitados como C#, a falha em compilar conta como um teste reprovado.

+ +

Portanto, nosso primeiro passo é nos livrarmos do erro de compilação. Se você pairar sobre “StringCalculator”, você deve ver um pequeno pop-up explicando o erro e oferecendo possíveis correções:

+ +

+ +

Clique em “Mostrar correções potenciais” e depois em “Gerar novo tipo…”. Você deve então ver uma janela solicitando os detalhes e a localização do novo tipo. Mude o “acesso” para “público” e a localização para o projeto de produção, que é “StringCalculatorKata”. A janela deve ser parecida com esta:

+ +

+ +

Clique em “OK”. Agora, se você abrir o explorador de soluções e expandir o projeto StringCalculatorKata, você deve ver a classe StringCalculator.cs à espreita por lá. Legal.

+ +

Entretanto, nosso código ainda não está compilado. E isso porque, apesar de termos criado a classe de produção, não adicionamos o método Add a ela. Então, vamos fazer da mesma forma que fizemos com a classe.

+ +

Passe o mouse sobre a palavra “Adicionar” até que a ajuda apareça com a mensagem “’ StringCalculator’ não contém uma definição para ‘Adicionar’”. Clique em Mostrar correções potenciais, e depois clique em “Gerar método ‘StringCalculator.Add’”.

+ +

Você verá que a classe de produção agora contém um método chamado Add, com o dobro como um tipo de retorno. Queremos que o método retorne int, então vamos mudar isso. Vamos também mudar o nome do parâmetro para “números” para corresponder aos requisitos do kata de codificação. Neste ponto, sua classe StringCalculator completa deve ser parecida com esta:

+ +
public class StringCalculator
+{
+    public static int Add(string numbers)
+    {
+        throw new NotImplementedException();
+    }
+}
+ +

Agora seu código deve ser compilado. Faça o teste novamente, e você verá que ele falha, com uma mensagem como esta:

+ +
+Add_EmptyStringAsParam_ReturnsZero
+   Source: StringCalculatorTest.cs line 8
+   Duration: 43 ms
+
+  Message: 
+    System.NotImplementedException : The method or operation is not implemented.
+  Stack Trace: 
+    StringCalculator.Add(String numbers) line 9
+    StringCalculatorTest.Add_EmptyStringAsParam_ReturnsZero() line 10
+
+
+ +

Temos uma falha de teste verdadeira. Estamos prontos para escrever o código de produção? Não tão rápido. Claro, nosso teste falha, mas falha da maneira errada. Como nosso teste contém uma asserção, esperávamos uma asserção fracassada. Em vez disso, o que temos é uma falha devido ao método em teste, lançando uma exceção.

+ +

A correção aqui é simples. Vamos apenas mudar o método Add, para que ele retorne qualquer número diferente de zero:

+ +
public static int Add(string numbers)
+{
+    return -1;
+}
+ +

Agora, faça o teste novamente, e você verá que a mensagem de erro é esta:

+ +
+Add_EmptyStringAsParam_ReturnsZero
+   Source: StringCalculatorTest.cs line 8
+   Duration: 76 ms
+
+  Message: 
+      Expected: 0
+      But was:  -1
+
+ +

Fazendo o teste passar

+ +

Estamos agora finalmente prontos para fazer o teste passar. Como disse anteriormente, para passar no teste, você não só é permitido, mas também encorajado a fazer batota. Em nosso caso, podemos simplesmente fazer com que o método Add retorne zero:

+ +
public static int Add(string numbers)
+{
+    return 0;
+}
+ +

Escrevendo o segundo teste: Um único número

+ +

Os requisitos dizem que a passagem de um único número deve retornar o próprio número. Isso soa como uma coisa útil para testar:

+ +
[Test]
+public void Add_StringContainingSingleNumber_ReturnsTheNumberItself()
+{
+    Assert.AreEqual(5, StringCalculator.Add("5"));
+}
+ +

O teste falha com a seguinte mensagem:

+ +
+Add_StringContainingSingleNumber_ReturnsTheNumberItself
+   Source: StringCalculatorTest.cs line 14
+   Duration: 56 ms
+
+  Message: 
+      Expected: 5
+      But was:  0
+
+
+ +

Como podemos fazer o teste acima passar da maneira mais preguiçosa possível? Que tal assim?

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    return 5;
+}
+ +

Testando Dois Números

+ +

Como já testamos o método Add passando por números zero (uma seqüência vazia) e um único número, parece que o próximo passo natural para nós agora seria escrever um teste para o cenário de adição de dois números. Então, vamos fazer exatamente isso.

+ +
[Test]
+public void Add_TwoNumbersSeparatedByComma_ReturnsTheirSum()
+{
+    var numbers = "7,8";
+    var expectedResult = 15;
+    Assert.AreEqual(expectedResult, StringCalculator.Add(numbers));
+}
+ +

O teste acima naturalmente falha uma vez que nosso método atualmente retorna 0 quando recebe um fio vazio e cinco de outra forma. Como podemos mudá-lo, para que este novo teste passe, os testes mais antigos continuem a passar, de uma forma que não resolve o problema em geral?

+ +

Esta é uma idéia:

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    return 5;
+}
+ +

Testando Três Números

+ +

Você já notou que, até agora, não fizemos nenhuma refatoração? Bem, estamos nos aproximando do ponto em que nossos testes nos levam a incluir alguma duplicação desagradável em nosso código. Então, usaremos a refatoração para alterar o código de uma forma que se aproxime de uma solução geral.

+ +

Vamos ver se podemos fazer isso testando o cenário com três números:

+ +
[Test]
+public void Add_ThreeNumbersSeparatedByComma_ReturnsTheirSum()
+{
+    var numbers = "1, 2, 3";
+    var expected = 6;
+    Assert.AreEqual(expected, StringCalculator.Add(numbers));
+}
+ +

O teste naturalmente falhará. Como a corda fornecida contém vírgulas, caímos no ramo condicional que retorna 15. Nosso desafio agora é mudar o método de produção de forma a fazer este teste passar. Podemos fazê-lo sem ir à solução geral do problema? Vamos ver.

+ +
public static int Add(string numbers)
+{
+    if (numbers == string.Empty)
+        return 0;
+
+    if (numbers == "1, 2, 3")
+        return 6;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    return 5;
+}
+ +

Comparando o parâmetro especificado com a entrada exata usada no teste, podemos fazer o teste passar, evitando ir para a solução geral. Entretanto, agora conseguimos criar uma duplicação de código. Você consegue ver isso? Estamos fazendo duas comparações contra o valor dos números, uma logo após a outra. Vamos ver se conseguimos nos livrar dessa duplicação.

+ +
public static int Add(string numbers)
+{
+    if (numbers == "1, 2, 3")
+        return 6;
+
+    if (numbers.Contains(','))
+        return 15;
+
+    int.TryParse(numbers, outint result);
+    return result;
+}
+ +

Aproveitando o método TryParse do tipo System.Int32, consegui me livrar do primeiro if. Também usamos um recurso introduzido no C# 7 chamado “out variables”. Este recurso nos permite utilizar parâmetros sem ter que declará-los previamente.

+ +

Todos os testes ainda passam, portanto, não posso escrever mais código de produção. Qual deve ser o próximo teste?

+ +

Testando Mais de Três Números

+ +

Os requisitos não dizem que devemos ser capazes de lidar apenas com três números. Portanto, vamos criar outro caso de teste para cobrir os cenários com 4, 5, ou mais números. Já que estamos nisso, podemos também incluir a exigência de ignorar números maiores que 1000.

+ +

Para fazer isso sem ter que criar muitos métodos de teste, vamos aproveitar o recurso NUnit [testes parametrizados] (https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html), adicionando um único método com vários casos de teste:

+ +
[TestCase("1,2,3,4", 10)]
+[TestCase("8,7,20", 35)]
+[TestCase("5,0,4,1001", 9)]
+[TestCase("5,0,4,1000", 1009)]
+[TestCase("26,6,90", 122)]
+public void Add_MoreThanThreeNumbersSeparatedByComma_ReturnsTheirSum(
+    string input, int result)
+{
+    Assert.AreEqual(result, StringCalculator.Add(input));
+}
+ +

Observe que o terceiro caso de teste exemplifica a exigência que diz que devemos ignorar números superiores a 1000. O próximo caso de teste, no entanto, mostra que 1000 não deve ser ignorado. Se você executar os testes, verá que o test explorer mostra cada caso de teste como um teste distinto.

+ +

Como podemos fazer este teste passar? Honestamente, a essa altura, é muito mais fácil ir para a implementação correta do que trapacear. Então, vamos fazer exatamente isso:

+ +
public static int Add(string numbers)
+{
+    var parts = numbers.Split(',');
+    var result = 0;
+
+    foreach (var part in parts)
+    {
+        int.TryParse(part, outint number);
+
+        if (number <= 1000)
+            result += number;
+    }
+
+    return result;
+}
+ +

O código acima deve ser fácil de entender. Nós apenas dividimos o fio em partes usando a vírgula como delimitador. Então, para cada parte, nós a dividimos em um inteiro, verificamos se é igual ou inferior a mil e, se for o caso, adicionamo-la à variável de resultado. Finalmente, retornamos o resultado.

+ +

Ainda não terminamos

+ +

Os requisitos dizem que números negativos não devem ser permitidos. Vamos acrescentar um teste para isso! Por uma questão de brevidade, acrescentaremos um único método de teste com vários casos de teste, de modo que somos forçados a ir imediatamente para a implementação correta:

+ +
[TestCase("1,2,3,4,5,-5")]
+[TestCase("-1,1,2,9")]
+[TestCase("5,6,8,-5")]
+public void Add_StringContainingNegativeNumbers_Throws(string numbers)
+{
+    Assert.Throws<ArgumentException>(() => StringCalculator.Add(numbers));
+}
+ +

Para este teste, afirmamos que não estamos contra um valor de retorno. Ao invés disso, estamos verificando se o método em teste abre uma exceção.

+ +

Lembre-se que os requisitos dizem que devemos lançar uma exceção com uma mensagem dizendo que os negativos não são permitidos. Devemos também incluir uma lista dos negativos que foram aprovados. Isto exigirá algumas mudanças em nosso método:

+ +
public static int Add(string numbers)
+{
+    var parts = numbers.Split(',');
+    var result = 0; 
+    var negatives = new List<int>();
+
+    foreach (var part in parts)
+    {
+        int.TryParse(part, outint number);
+
+        if (number < 0)
+            negatives.Add(number);
+        elseif (number <= 1000)
+            result += number;
+    }
+
+    if (negatives.Count > 0)
+    {
+        var negativesList = string.Join(',', negatives);
+        var exceptionMessage = $"Negative numbers not allowed: {negativesList}.";
+        throw new ArgumentException(exceptionMessage);
+    }
+    
+    return result;
+}
+ +

Como você pode ver, logo no início, nós definimos uma instância de List<int> para armazenar os negativos que encontramos enquanto iteramos sobre todos os números. Dentro do laço, verificamos se o número atual é negativo. Se for, adicionamo-lo à lista. Se não for, verificamos se é menor ou igual a 1000, caso em que o adicionamos à variável de resultado.

+ +

Após o loop, verificamos se a lista negativa tem algum elemento. Se tiver, criamos uma mensagem de exceção que inclui os negativos especificados e, em seguida, lançamos uma nova ArgumentException. Caso contrário, devolvemos o resultado.

+ +

Conclusão

+ +

Este post foi um guia prático sobre como começar com o TDD em C#. Então, para onde você vai a partir daqui?

+ +

Bem, a maioria das coisas na vida você aprende fazendo. A programação é certamente uma dessas coisas. Portanto, se você quer que os conceitos que você viu hoje realmente se afundem, você tem que praticar.

+ +

O código que escrevi durante este post está disponível como um repositório público no GitHub. Vá lá, clone-o usando Git,, e comece a brincar com ele.

+ +

Você verá que eu criei um compromisso para cada etapa do ciclo TDD. Dessa forma, torna-se mais fácil para os futuros leitores visualizar todas as etapas do processo, percorrendo a história do projeto, um compromisso de cada vez.

+ +

É possível melhorar o código que eu usei hoje. Por exemplo, o código do método Add pode ser escrito de uma forma mais curta, clara e eficiente, usando LINQ Você pode criar mais testes. Os requisitos do exercício que apresentamos no início pedem por uma mensagem de erro específica ao lançar a exceção quando há números negativos na string. Apesar de termos implementado a mensagem como pedido, nós não criamos um teste pra isso. Você pode fazer isso, como forma de praticar.

+ +

Finalmente, fique atento a este blog. Este post é parte de uma série, à qual pretendo acrescentar mais partes.

+ +

Obrigado pela leitura, e até a próxima!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/testes-unitarios-iniciantes-parte-2.html b/pt/testes-unitarios-iniciantes-parte-2.html new file mode 100644 index 00000000..d06ef6aa --- /dev/null +++ b/pt/testes-unitarios-iniciantes-parte-2.html @@ -0,0 +1,748 @@ + + + + + + + + Testes Unitários Para Iniciantes - Parte 2 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Testes Unitários Para Iniciantes - Parte 2

+ +
+ +
+

+ +

Antes tarde do que mais tarde! Hora de continuar nossa série sobre testes unitários para iniciantes. Hoje você vai escrever seu primeiro teste unitário. +

+ +

Introdução

+ +

Este post faz parte de uma série. Veja os outros artigos.

+ +

No primeiro artigo nesta série eu defini o que são testes unitários, e também falei dos benefícios de sua utilização.

+ +

Hoje você vai aprender, na prática, como criar testes unitários. Vou mostrar como instalar e utilizar o framework de testes NUnit. E depois vamos criar alguns testes para você conhecer algumas das features deste framework.

+ +

Instalando o NUnit

+ +

Como eu expliquei no primeiro post da série, para utilizar testes unitários na sua aplicação você necessita de um Framework de Testes.

+ +

O framework que vamos utilizar é o NUnit, que é baseado no JUnit, um framework de testes desenvolvido para a linguagem Java. Existem outros frameworks de teste disponíveis no mundo .Net, como o MS Test, desenvolvido pela própria Microsoft. +Se for do seu interesse, você poderá experimentar os outros frameworks por conta própria mais tarde.

+ +

Ok, vamos começar. Para este projeto, eu vou utilizar o Visual Studio 2017. Clique aqui para baixar a versão Community.

+ +

Crie uma nova solução do tipo Class Library, com o nome de LearningUnitTesting.

+ +

Uma coisa que eu sempre costumo fazer ao criar uma nova solução é excluir a classe Class1 que vem criada por padrão. Você também poderia renomeá-la, é claro, mas fica totalmente ao seu critério.

+ +

Agora, vamos renomear o projeto padrão que foi criado para Application. Este projeto vai servir para guardar o código de produção em nossa solução.

+ +
+

No contexto de testes unitários, usamos o termo Código de Produção para nos referirmos ao código “real” da nossa aplicação, em contraste ao Código de Testes.

+
+ +

O próximo passo é criar o projeto de testes. Existem algumas opiniões diferentes a respeito de onde devem ficar as classes de teste: se junto às classes de produção, ou em um local separado. Eu particularmente prefiro criar um projeto à parte, e o sistema de nomenclatura que eu costumo usar é: o mesmo nome do projeto de produção, mais a palavra Test no final.

+ +

O nome do projeto será, portanto, ApllicationTest, e também será do tipo Class Library. +Após a criação do projeto, vou remover a classe adicionada por padrão, assim como fiz com o projeto de produção.

+ +

Sua solução deveria estar desta forma:

+ +

+ +

Chegou a hora de instalarmos o NUnit. Felizmente, o framework é disponibilizado como um pacote do Nuget, o que torna sua instalação trivial.

+ +

Pimeiro, abra o Console do Gerenciador de Pacotes. Vá para: Ferramentas > Gerenciador de Pacotes do Nuget > Console do Gerenciador de Pacotes.

+ +

Quando o console estiver aberto, digite ou copie e cole o seguinte comando:

+ +
+

Install-Package NUnit

+
+ +

Verifique que o projeto de testes é o que está selecionado, como na imagem:

+ +

+ +

E pressione ENTER. A instalação será realizada em poucos segundos.

+ +

Entretanto, isto não é tudo. Precisamos instalar um outro pacote, o NUnit Test Adapter, para que sejamos capazes de executar os testes do NUnit com o Visual Studio. O processo é o mesmo, o que muda é o comando:

+ +
+

Install-Package NUnit3TestAdapter

+
+ +

Assim como no passo anterior, verifique que o projeto correto está selecionado antes de confirmar. A instalação deve terminar em poucos segundos.

+ +

É isto.

+ +

Criando e executando o primeiro teste

+ +

Vamos começar a criar alguns testes. Primeiro, vamos adicionar uma nova classe ao nosso projeto de Produção. A classe se chamará Employee e terá o seguinte código:

+ + + +

Eu imagino que a classe seja simples o suficiente e não necessita de explicação. Agora, vamos criar nossa classe de teste. No projeto ApplicationTest, adicione uma nova classe com o nome de EmployeeTest.

+ +
+

Este é um dos padrões de nomenclatura que eu também utilizo: nomear a classe de teste com o mesmo nome da classe de produção, acrescentando Test no final.

+
+ +

Após a criação da classe, adicione o namespace NUnit.Framework na lista de usings da classe. Em seguida, crie um novo método público de retorno void chamado MyFirstTestMethod e adicione o atributo [Test] a ele.

+ +

Nesse ponto, o código da classe deve estar assim:

+ + + +

O esqueleto do teste já está pronto. Então vamos escrever nossa primeira asserção. Uma asserção é uma afirmação sobre como um determinado método deveria se comportar. Caso a afirmação se prove verdadeira, dizemos que o teste passou. Caso a afirmação se prove falsa, dizemos que o teste falhou, ou quebrou.

+ +

No NUnit, utilizamos a classe Assert para escrevermos nossas asserções. Esta classe possui um número grande de métodos que nos permitem expressar nossas expectativas com relação ao comportamento das unidades que estamos testando.

+ +

Adicione a seguinte linha de código ao método de teste:

+ +
+

Assert.Pass();

+
+ +

Esta é uma asserção que serve para forçar o teste a passar. Vamos agora rodar esse teste para vê-lo passando. Primeiro, precisamos abrir o Gerenciador de Testes. Vá para: Testar > Janelas > Gerenciador de Testes.

+ +

Na janela exibida, clique em Executar Tudo. Caso tudo tenha funcionado da maneira correta, você verá isso:

+ +

+ +

Ao clicar no nome do teste, serão exibidas algumas informações adicionais, como o arquivo do teste e tempo decorrido:

+ +

+ +

Note o uso da cor verde para indicar o sucesso do teste.

+ +

Vamos agora fazer o contrário: forçar a falha do teste. Substitua a linha no método por:

+ +
+

Assert.Fail();

+
+ +

Execute o teste novamente e verá a mensagem de falha, dessa vez com a barra vermelha:

+ +

+ +

Agora que você já está pegando o jeito, vamos começar a testar a nossa classe Employee. Não esqueça de voltar o método de teste que fizemos para Assert.Pass para que ele não fique falhando.

+ +

Em seguida, adicione um novo método de teste chamado IntroduceMethodShouldWorkCorrectly. Nele, vamos criar uma nova instância do objeto Employee e verificar que o método Introduce está funcionando como deveria.

+ +

Antes de fazermos isso, porém, precisamos adicionar uma referência do projeto de produção ao nosso projeto de testes. Do contrário, nossa classe de teste não conseguirá enxergar as classes que deveria testar!

+ +

Para isso, clique com o botão direito no projeto ApplicationTest > Adicionar > Referência…. Na janela exibida, selecione o projeto, conforme a imagem a seguir:

+ +

+ +

E depois clique em OK.

+ +

De volta à classe de teste, modifique o método de teste para que fique da forma abaixo:

+ + + +

Você vai notar que Employee está marcado como erro. Ao passar o cursor em cima, você verá uma mensagem avisando que o nome Employee não pode ser encontrado e perguntando se não tem alguma referência ou diretiva using faltando.

+ +

É claro que tem uma diretiva using faltando, relativa à referência que acabamos de adicionar. Para corrigir o problema, basta adicionar a linha using Application; no começo do arquivo.

+ +

Agora que o código compila, vamos entender este método, linha a linha.

+ +

Na primeira linha, instanciamos nossa classe Employee, definindo nome, profissão e salário. Na linha seguinte, atribuímos a uma variável o valor que esperamos que o método retorne. Em seguida, atribuímos a outra variável o resultado da execução do método.

+ +

Finalmente, utilizamos o método AreEqual da classe Assert para verificar se os dois valores são iguais. Este método é, provavelmente, o que você mais vai utilizar durante seus testes.

+ +

Agora é hora de executar o teste. Utilize o atalho CTRL + R, A ou clique em Executar Tudo na janela do Gerenciador de Teste. Se tudo der certo, você verá a barra verde e a mensagem indicando que os dois testes passaram.

+ +

Vamos agora testar o teste: vamos “estragar” o método Introduce e ver se o método falha como deveria. De volta à classe de produção, vamos modificar o método da seguinte forma:

+ + + +

Como você viu, nós retiramos os colchetes ao redor de JobTitle. Desta forma, a interpolação de string não será realizada, fixando o texto “JobTitle” ao invés de substituí-lo pelo valor da variável.

+ +

Ao rodar os testes novamente, obtemos o seguinte resultado:

+ +
+

Mensagem: Expected string length 48 but was 46. Strings differ at index 37. +Expected: “Hi! My name is Alice and I work as a Programmer.” +But was: “Hi! My name is Alice and I work as a JobTitle.” +————————————————^

+
+ +

Em tradução livre, seria algo como:

+ +
+

O comprimento esperado da string era 48 mas o obtido foi 46. As string diferem a partir do índice 37. +Esperado: “Hi! My name is Alice and I work as a Programmer.” +Mas foi: “Hi! My name is Alice and I work as a JobTitle.”

+
+ +

Como podemos ver, a mensagem é bem explicativa. Ela nos informa não apenas que as string divergiram mas exatamente em que parte elas começaram a divergir. Também nos informa exatamente o texto esperado e o que realmente foi obtido. É importante salientar que a ordem dos parâmetros do método AreEqual importa, pois isso influi na mensagem exibida quando o teste falha.

+ +
+

A ordem dos parâmetros no método AreEqual é muito importante. Passe primeiro o resultado esperado, e depois o que realmente foi obtido.

+
+ +

Ótimo. Podemos voltar o método para sua implementação anterior e executar os testes novamente, para ver que o teste volte a passar.

+ +

Como você pode ver, um teste de unidade envolve uma sequência de passos bem definida: preparamos o cenário, executamos a ação, e verificamos o resultado. Essa sequência de passos - ou fases - é muitas vezes chamada de AAA: Arrange-Act-Assert.

+ +
+

Um teste de unidade típico envolve as fases Arrange-Act-Assert.

+
+ +

Embora existam outras nomenclaturas para as fases do teste de unidade, vamos adotar Arrange-Act-Assert como nossa nomenclatura padrão, ao menos por enquanto.

+ +

Você talvez esteja se perguntando por qual motivo eu de o nome de “sut” à variável declarada no início do método. Este é um padrão de nomenclatura que aprendi lendo o blog do Mark Seeman. SUT significa System Under Test, ou “Sistema Sob Teste”, em tradução livre. É um termo usado para se referir à classe sendo testada no teste atual. Não há nada que obrigue a utilização de sut como o nome da variável, mas eu gosto de usar dessa forma, pois deixa evidente no teste quem é que está sendo testado.

+ +
+

Dica: Procure utilizar padrões de codificação que melhorem a legibilidade e deixem a intenção do autor explícita para o leitor do código.

+
+ +

Logo abaixo temos o método de teste, dessa vez com comentários demonstrando cada fase do teste:

+ + + +

Embora não seja realmente necessário, eu sugiro que você use comentários para demarcar as fases do teste como no exemplo acima, ao menos no início de seu aprendizado.

+ +

Mais um teste: método GiveRaise

+ +

Um aumento no salário é sempre bem-vindo, concordam? Vamos testar que o método GiveRaise funciona como deveria. Na sua classe de teste, adicione o método a seguir:

+ + + +

Execute o teste e você deverá ver a familiar barra verde de sucesso. Deu certo? Ótimo. Hora de testar o teste: vamos “sabotar” a implementação do método GiveRaise e ver se o teste falha.

+ +

Na classe de produção, vamos deixar o método assim:

+ + + +

Agora que o método está obviamente errado, o teste deveria falhar. Vamos executá-lo?

+ +
+

Mensagem: Expected: 110 + But was: 5m

+
+ +

Ok, podemos ver que o teste realmente falhou. Podemos voltar o método ao normal e ver que agora tudo passa como deveria.

+ +

Um último teste

+ +

Digamos que surgiu um novo requisito: se a porcentagem de aumento passada for negativa, o salário deve permanecer o mesmo. Vamos então alterar o método GiveRaise para tratar este caso:

+ + + +

Fizemos uma alteração no código de produção. Nossa prioridade agora é verificar que nada quebrou. Execute os testes para verificar se todos ainda estão passando normalmente.

+ +

Tudo ainda está verde? Ótimo, vamos em frente. Agora precisamos criar um novo teste para documentar o caso da tentativa de aumento negativo.

+ +
+

Testes de unidade também são uma forma de documentação.

+
+ +

Na classe de teste, adicione o método a seguir:

+ + + +

Nada de surpreendente aqui, certo? À esta altura, você já deve ter pegado o jeito da coisa. Assim, vou deixar por sua conta o teste do teste: sabote o método de uma ou mais maneiras e confira que o teste falhou conforme deveria.

+ +

Recapitulando

+ +

O artigo de hoje foi bem mais prático que o anterior. Conseguimos abordar diversos tópicos:

+ +
    +
  • Instalação do NUnit e NUnit Test Adapter;
  • +
  • Criação de caso de teste;
  • +
  • Conceito de asserção e classe Assert;
  • +
  • Execução dos testes, tanto por meio do Gerenciador de Testes quanto por teclas de atalho;
  • +
  • Interpretação da mensagem de erro do teste;
  • +
  • Fases do teste unitário (Arrange-Act-Assert).
  • +
+ +

Além desses tópicos, também ampliamos nosso vocabulário relativo à testes, com os termos SUT, asserção, código de teste x código de produção, entre outros.

+ +

Também foram abordados alguns padrões de nomenclatura, tanto para classes quanto para métodos de teste.

+ +

Finalmente, você aprendeu sobre a importância de ver o teste falhar, e como podemos “testar o teste” através de uma sabotagem deliberada do código de produção.

+ +

Notas

+ +
    +
  • O código do post de hoje está no Github.
  • +
  • Agradeço novamente ao amigo Gunter Italiano Ribeiro por revisar este artigo.
  • +
+ +

Conclusão

+ +

Este foi o segundo artigo da minha série sobre testes unitários. Como já mencionei, ele é propositalmente maior e mais prático que o artigo inicial da série. Ainda assim, tudo o que foi abordado é apenas a ponta do iceberg do que existe a respeito de testes de unidade. Livros inteiros poderiam foram escritos sobre este assunto. Nos artigos futuros indicarei alguns, além de outros materiais para estudo.

+ +

Nos testes que escrevemos hoje, utilizamos a abordagem mais intuitiva - e provavelmente mais comum - de se criar os testes após o código de produção. Porém, muitas pessoas e equipes trabalham com uma metodologia diferente: eles escrevem os testes antes do código de produção.

+ +

Pode parecer estranho, à princípio, mas trabalhar desta forma pode trazer diversos benefícios para seu projeto. Este e outros tópicos serão abordados no próximo artigo.

+ +

Até lá!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/testes-unitarios-iniciantes-parte1.html b/pt/testes-unitarios-iniciantes-parte1.html new file mode 100644 index 00000000..013c3ef5 --- /dev/null +++ b/pt/testes-unitarios-iniciantes-parte1.html @@ -0,0 +1,611 @@ + + + + + + + + Testes unitários para iniciantes - Parte 1 | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Testes unitários para iniciantes - Parte 1

+ +
+ +
+

+ +

Você já deve ter trabalhado em um sistema assim: incrivelmente complexo, com uma base de código gigantesca, mal documentada, cheia de gambiarras, acoplamentos desnecessários, com arquitetura confusa, especificações inexistentes, onde era quase considerado um milagre que o software chegasse a funcionar. Talvez eu tenha acabado de descrever seu projeto atual! +

+ +

Este post faz parte de uma série. Veja os outros artigos.

+ +

Nesse tipo de projeto, é comum que os desenvolvedores fiquem com receio de mexer no código, pois sabem que, inevitavelmente, algo vai quebrar. E provavelmente, o erro só vai ser descoberto em produção.

+ +

Agora, imagine se a aplicação fosse completamente protegida por um sistema de alarmes. Cada vez que uma feature parasse de funcionar, o alarme dispararia. Os desenvolvedores seriam imediatamente notificados, e alguém resolveria o problema o mais rápido possível.

+ +

Imagine ainda que esse sistema de alarmes fosse composto por centenas de sistemas menores. Cada um desses subsistemas seria responsável por “vigiar” uma parte bem pequena e específica da sua aplicação. E para que o sistema de alarmes funcionasse bem, os subsistemas deveriam ser totalmente independentes uns dos outros.

+ +

A adoção de um sistema desse tipo traria muitos benefícios. Logo de cara, o medo de mexer no código iria embora. A refatoração se tornaria mais fácil e frequente, e, como consequência, a qualidade do código aumentaria.

+ +

O próprio processo de desenvolvimento seria simplificado. O sistema de alarmes reduziria drasticamente a necessidade dos lentos testes manuais, agilizando a entrega da aplicação para os usuários.

+ +

Por fim, a necessidade de independência entre os subsistemas incentivaria a diminuição do acoplamento entre as partes da aplicação.

+ +

Parece bom demais para ser verdade? Pois saiba que não é. Esse sistema de alarmes é o benefício que você ganha ao implementar uma suíte de testes unitários em sua aplicação.

+ +

O que são testes unitários

+ +

Vamos ver a definição da Wikipédia:

+ +
+

In computer programming, unit testing is a software testing method by which individual units of source code, […] are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. […] + Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.

+
+ +

Em tradução livre:

+ +
+

Em programação de computadores, teste unitário é um método de teste de software pelo qual unidades individuais de código fonte […] são testadas para determinar se são adequadas para o uso. Intuitivamente, pode-se considerar uma unidade como a menor parte testável de uma aplicação. […] + Testes unitários são tipicamente escritos e executados por desenvolvedores para garantir que o código está de acordo com o projeto e se comporta da maneira desejada.

+
+ +

A primeira coisa que chama a atenção é que os testes unitários não têm o propósito de testar o sistema como um todo. Pelo contrário, eles testam pequenas partes do software - as tais das unidades. E o que é uma unidade? Existem diversos pontos de vista conflitantes sobre isso, diversas “escolas de pensamento”. Mas é seguro dizer que, no contexto de programação orientada a objeto, a maioria das pessoas considera unidade como sendo uma classe.

+ +

Logo a seguir, nós vemos que os testes unitários são tipicamente escritos e executados por programadores. Isso é interessante por dois motivos: primeiro, contradiz uma ideia antiga de que programadores não são bons testadores de software (vou voltar nesse ponto depois). E mais importante do que isso, ele deixa claro a principal característica dos testes unitários: eles são automatizados.

+ +

Tenha em mente que existem diversos tipos de testes automatizados, mas aqui estamos tratando apenas de testes unitários (os quais, de acordo com diversos autores, tais como Martin Fowler, são os que trazem mais benefícios para uma aplicação).

+ +

Na prática, os testes unitários consistem de classes contendo métodos que testam partes pequenas e isoladas do sistema. Essas classes são criadas com o auxílio de um framework de testes (como o JUnit no Java, ou o NUnit ou o Microsoft Test no .Net). Esses testes podem então ser executados pela linha de comando, pela sua IDE ou mesmo por um serviço de build automatizado.

+ +

Exemplo de método de teste em C#

+ +

Após a execução dos testes, você obtém um retorno imediato sobre quais testes passaram e quais falharam, acompanhado do tempo de execução de cada um dos testes.

+ +

Janela exibindo resultados da execução de testes unitários

+ +

Com base nesse feedback, você decide o melhor curso de ação. Idealmente, um teste que falha deveria ser sinal de erro no código. O código de produção deveria então ser ajustado para que o teste volte a passar.

+ +

Benefícios dos testes unitários

+ +

No começo do post, ao usar a metáfora do sistema de alarmes, eu falei de alguns dos benefícios que os testes unitários trazem, como por exemplo:

+ +
    +
  • incentivo à refatoração;
  • +
  • incentivo à evolução da arquitetura do sistema;
  • +
  • simplificação e agilidade na entrega do produto aos usuários;
  • +
+ +

Outro benefício que vale a pena citar é que os testes também servem como documentação do código. Pense bem: para cada classe de produção no seu sistema, existem diversos métodos de teste que exercitam e exemplificam todos os usos possíveis dessa classe. Uma boa suíte de testes poderia ajudar um recém-chegado ao time adquirir familiaridade com a base de código em pouco tempo.

+ +

Ou seja: documentação viva, executável, sempre atualizada, e que nunca mente.

+ +

Não podemos deixar de mencionar também que uma boa suíte de testes unitários também ajuda a prevenir a regressão de bugs. É uma ótima prática criar um novo teste toda vez que um bug for encontrado. Assim, caso alguma alteração futura faça com que o bug retorne (“regresse”), o teste vai indicar isso.

+ +

Finalmente, um dos maiores benefícios da automação de testes que eu não vejo sendo alardeado por aí é a redução de custos - talvez por ser um fator mais de negócios do que técnico. Digamos que antes de cada release a sua equipe faça um teste completo na aplicação, com quatro testadores, trabalhando 8 horas por dia, durante duas semanas. Basta fazer uma simples multiplicação e você verá que testes manuais custam caro.

+ +

Pior ainda: eles custam caro duas vezes. Primeiro, há o custo dos testes em si, que você pode calcular com a fórmula valor da hora de trabalho dos testadores x nº de testadores x horas gastas em teste.

+ +

Além disso, há o custo de oportunidade: quando profissionais precisam desempenhar testes manuais que poderiam ser automatizados, eles estão deixando de desempenhar atividades criativas/intelectuais que teriam potencial de trazer ganhos muito maiores para a empresa.

+ +

Equívocos comuns

+ +

Nessa seção, vou tentar esclarecer alguns dos mitos e equívocos que existem a respeito de testes unitários.

+ +

Programadores não deveriam escrever testes, pois geralmente são maus testadores

+ +

Existe uma ideia bastante difundida de que programadores não deveriam testar seu próprio código. O raciocínio é que eles, inconscientemente, evitariam usar a aplicação de uma maneira que a faria quebrar. E por experiência própria, eu digo que isso de fato acontece. Já perdi a conta de quantas vezes algum colega encontrou bugs em uma aplicação que eu fiz após segundos de uso, sendo que eu já havia passado muito mais tempo que isso testando e sem conseguir fazer falhar.

+ +

O ponto a salientar aqui é: há testes e testes. Geralmente, quando pessoas dizem que programadores não deveriam testar, elas estão se referindo a testes de sistema, também chamados testes ponta a ponta. Tais testes têm o propósito de testar o sistema como um todo, o que, como já vimos, não é o objetivo dos testes unitários.

+ +

Muitas vezes o que ocorre é simplesmente falta de informação: a pessoa talvez desconheça a natureza e propósito dos testes unitários, e os toma por testes de ponta a ponta.

+ +

Escrever testes unitários é uma perda de tempo; é o mesmo que programar duas vezes

+ +

Ao tentar “vender” testes unitários para a gerência na sua empresa, uma boa estratégia é apelar para a redução de custos, como visto anteriormente. Mas…e os desenvolvedores? Como convencê-los a gastar mais tempo escrevendo código de teste além do código de produção?

+ +

Dizer que os testes unitários são perda de tempo é uma justificativa comum apresentada por desenvolvedores que não querem escrever testes. E é uma justificativa aparentemente legítima. Afinal, nossos prazos são apertadíssimos, como podemos arrumar tempo para ficar escrevendo casos de teste?

+ +

O que essas pessoas falham em perceber é que elas já testam o próprio código constantemente, mesmo que não chamem por esse nome. É bem provável que seu workflow de desenvolvimento seja bem parecido com isso:

+ +
    +
  • Escreve um pouco de código
  • +
  • Compila
  • +
  • Executa a aplicação, testa a funcionalidade +
      +
    • Se funcionou, começa a escrever a próxima funcionalidade
    • +
    • Se não funcionou, passa um tempo debugando até encontrar e corrigir o erro
    • +
    +
  • +
  • Repita
  • +
+ +

O que estamos propondo é simplesmente trocar o ciclo “escreve código de produção -> compila -> testa -> debuga -> repete” pelo ciclo “escreve código de produção -> escreve código de testes -> executa testes -> corrige código de produção se necessário”.

+ +

É até possível argumentar que os ciclos são praticamente os mesmos. Mas a grande vantagem dos testes unitários é que, uma vez escritos, eles estão automatizados para o resto da vida do projeto. Você “perde tempo” só uma vez. Você investe tempo e esforço no começo, para criar os testes, e colhe os benefícios por tempo indefinido.

+ +

Testes unitários substituem todos os testes manuais

+ +

Testes unitários não são os únicos tipos de testes que trazem benefícios a um projeto. Também podemos utilizar outros tipos de testes automatizados como testes de integração e testes de aceitação.

+ +

Triângulo dos testes, mostrando a razão ideal entre os diversos tipos de teste de software

+ +

Isso não significa que testes manuais devem ser extintos. Pelo contrário, eles continuam tendo um papel importante no processo de controle de qualidade. De preferência, os testes manuais devem se concentrar nas áreas que não podem ser automatizadas, como testes de usabilidade.

+ +

Dentro de um contexto de metodologias ágeis, é essencial que o Product Owner/Cliente/Pessoa de Negócios valide e aceite as histórias antes delas serem incluídas em uma release.

+ +

Testes manuais exploratórios, que não seguem um roteiro definido, costumam ser valiosos na detecção de certos tipos de bugs. Os casos de testes automatizados tendem a focar no “Happy Path”, ou seja, o cenário no qual deu tudo certo, as unidades foram usadas exatamente do jeito que o codificador pensou e projetou. Na vida real, é muito comum que os usuários utilizem a aplicação de maneiras…como dizer?…“criativas”. Então,colocar o software sob stress, utilizando-o de maneiras diferentes e inesperadas, podem acabar revelando bugs que de outra forma permaneceriam ocultos.

+ +

É claro que, uma vez que o bug tenha sido revelado pelo teste manual, deve-se imediatamente escrever um teste automatizado que o exponha. Assim, na eventualidade do bug regredir, ele será facilmente detectado.

+ +

Conclusão

+ +

Testes unitários - e automação de testes, no geral - são um tema gigantesco. Há muitos livros sobre esse tema, bem como teses de mestrado. Há conferências anuais em diversos países apenas sobre teste de software. Então, é claro que seria impossível que eu, com uma mera postagem no meu blog, fizesse jus a esse tema.

+ +

Mas eu espero, sinceramente, ter feito uma boa introdução aos testes unitários e esclarecido um pouco das dúvidas que os iniciantes geralmente têm. Qualquer dúvida, sugestão ou crítica, a área de comentário é de vocês.

+ +

Este post é o início de uma série dedicada ao tema dos testes. +No próximo artigo, começaremos a colocar a mão na massa: vou mostrar a vocês como criar seus primeiros testes!

+ +

Até lá!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/tipos-de-comentarios-a-evitar/index.html b/pt/tipos-de-comentarios-a-evitar/index.html new file mode 100644 index 00000000..3ac04a8b --- /dev/null +++ b/pt/tipos-de-comentarios-a-evitar/index.html @@ -0,0 +1,588 @@ + + + + + + + + Aprenda quais tipos de comentários devem ser evitados | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Aprenda quais tipos de comentários devem ser evitados

+ +
+ +
+

+ +

Alerta de Spoiler: Você deveria evitar a maioria. +

+ +

“Comentar ou não comentar”. Essa é uma questão que gera debates acalorados. Algumas pessoas dizem que comentários são indispensáveis. Outros defendem que comentários apenas mostram a incapacidade do desenvolvedor de se expressar claramente no código. Quem está certo?

+ +

Na época da faculdade, eu considerava comentários indispensáveis na hora de programar. Do contrário, como você poderia entender o que código deveria fazer?

+ +

Depois de me formar e encontrar um emprego, as coisas começaram a mudar. Eu comecei a ser exposto à código real. Eu estava lendo livros, artigos e blog posts escritos por pessoas influentes da área.

+ +

Todas essas experiências moldaram a minha visão atual.

+ +

Os perigos da documentação ruim

+ +

Comentários são apenas outra forma de documentação. E não se engane: documentação é uma coisa boa - quando feita corretamente e na quantidade certa.

+ +

Infelizmente, é feita errada frequentemente!

+ +

Muitos tipos de documentação podem ser problemáticas. É muito comum que a documentação perca sincronia com o que está documentando, o que é bem pior que não ter documentação nenhuma para começar.

+ +

Esse é um dos problemas dos quais comentários sofrem, mas está longe de ser o único.

+ +

Código comentado

+ +

Vamos começar com o problema mais óbvio de todos, que é código comentado. Alguns desenvolvedores, durante uma correção de bug por exemplo, decidem comentar o código que está errado, em vez de removê-lo.

+ +

Não faça isso!

+ +

Código comentado não traz benefício para ninguém. É apenas desperdício. Confie no seu sistema de controle de versão. Ele vai lembrar das alterações feitas caso seja necessário revertê-las no futuro.

+ +

Comentários ‘Changelog’

+ +

Esta categoria de comentários ruins é parecida com a anterior, no sentido de ser causada por uma falta de confiança no sistema de controle de versões.

+ +

O que eu quero dizer por comentários changelog? Comentários que servem apenas para listar as alterações feitas a um arquivo.

+ + + +

Comentários desse tipo estão apenas fazendo o mesmo trabalho que seu controle de versão, mas de uma maneira desajeitada e propensa ao erro.

+ +

Não escreve comentários como esses. Use git e seja feliz.

+ +

Comentários redundantes

+ +

Esse tipo de comentário ruim é muito fácil de detectar e corrigir. Considere o código a seguir:

+ + + +

Eu acho que todos podemos concordar que esses comentários são inúteis. O código é perfeitamente claro sem eles, portanto, devem ser removidos.

+ +

Comentários delimitando fim de blocos

+ +

Você provavelmente já viu algum código assim antes:

+ + + +

Algumas pessoas escrevem comentários assim para não perderem o controle das chaves.

+ +

Se você precisa de comentários por essa razão, isso é indicativo de que seu método é muito longo e você tem muitos níveis de indentação.

+ +

Lembre-se do Princípio da Responsabilidade Única: cada método deve fazer apenas uma coisa. Divida o seu método em métodos menores e a necessidade desse tipo de comentários desaparece.

+ +

Comentários que delimitam seções dentro de um método

+ +

Esse é parecido com o anterior. Se você tem diversas seções dentro de um método, cada uma delas com um comentário explicativo em cima, então você provavelmente está violando o Princípio da Responsabilidade Única.

+ +

Extraia cada trecho para seu próprio método, usando o texto do comentário como o nome do novo método, e então remova os comentários.

+ +

Comentários desatualizados.

+ +

Um cenário comum:

+ +
    +
  • Bob escreve algumas linhas de código. Ele decide que o código não está claro o suficiente e adiciona alguns comentários para tornar a sua intenção mais clara.
  • +
  • Passam-se algumas semanas. Alguém descobre um bug no código de Bob. Mas ele está de férias, então Alice é encarregada de corrigir o bug.
  • +
  • Alice corrige o código em alguns minutos e comita suas alterações. Mas ela esquece de alterar os comentários para refletir as mudanças que ela fez no código.
  • +
+ +

O que nós temos agora? Comentários mentirosos!

+ +

Documentação que espalha mentiras é pior que não ter documentação alguma. É uma fonte de confusão para os desenvolvedores, e terreno fértil para bugs. Quando você ver um comentário desatualizado, não pense duas vezes: remova-o imediatamente, ou corrija-o. Mas na maioria das vezes você não deveria manter o comentário. Veja o próximo tópico para descobrir o porquê.

+ +

Comentários criados devido à falta de expressividade no código

+ +

Considere o código a seguir:

+ + + +

Talvez você não considere o comentário no trecho acima tão ruim. Tudo bem, não é péssimo. Mas pense na oportunidade perdida de extrair um método ou propriedade útil:

+ + + +

No novo código, nós extraímos o conceito de ser elegível para doar sangue para uma nova propriedade. As regras para elegibilidade para doação de sangue estão agora consolidadas em um único local; se elas mudarem algum dia, a quantidade de trabalho necessária para atualizá-las será mínima.

+ +

E nós ainda ganhamos o benefício adicional da legibilidade: a nova instrução if lê quase como linguagem natural.

+ +

Conclusão

+ +

Como vimos, há diversos tipos de comentários ruins com os quais você deve ficar alerta. Eles geralmente são sinais de que há algo errado no seu código. Talvez seus métodos são muito longos.Talvez você não escolheu bons nomes para suas variáveis.

+ +

Toda vez que você sentir a necessidade de escrever um comentário, pare e tente pensar em maneiras de melhorar o seu código para tornar o comentário desnecessário.

+ +

Nem todos os comentários são ruins. Em um post futuro, vou falar sobre os tipos de comentários que são úteis.

+ +

Até mais!

+ + + + + +

PS: Ainda não consegue ler em inglês? Meu novo curso, Inglês Para Desenvolvedores, pode ser a solução que você procura. Acesse o site, cadastre seu e-mail e fique por dentro das novidades!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/tipos-valor-referencia-em-csharp-parte-2/index.html b/pt/tipos-valor-referencia-em-csharp-parte-2/index.html new file mode 100644 index 00000000..c4f3194c --- /dev/null +++ b/pt/tipos-valor-referencia-em-csharp-parte-2/index.html @@ -0,0 +1,551 @@ + + + + + + + + Tipos de valor e referência em C#, Parte 2 - Por que DateTime não pode ser nulo? | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Tipos de valor e referência em C#, Parte 2 - Por que DateTime não pode ser nulo?

+ +
+ +
+

+ +

“Por que uma variável DateTime não pode receber null?” Esta é uma pergunta que vive aparecendo no StackOverflow e site similares. Às vezes escrita de modo um pouco diferente, às vezes com um tipo diferente, mas no fundo é a mesma dúvida. O que é natural, se você considerar que provavelmente milhares de pessoas entram na área a cada ano. +

+ +

A resposta curta é: porque DateTime/int/float/etc é um tipo de valor, e tipos de valor não podem nunca receber null. Apenas tipos de referência podem.

+ +

Legal, mas…por quê?

+ +

Em algum momento os projetistas do C# tiveram que tomar essa decisão. Eles deliberadamente decidiram que tipos de valor não poderiam receber null. Será que tem alguma coisa que naturalmente impede isso? Talvez tenha algo a ver com a pilha e a heap?

+ +

Eu acho que antes de tentarmos responder essas questões, seria interessar voltar um passo e pensar um pouco sobre outra questão.

+ +

O que exatamente é null?

+ +

Você provavelmente pensa em null como uma maneira de representar uma informação que está faltando. Algo desconhecido, ausente ou irrelevante. Talvez um dado que não está onde deveria ainda, mas talvez esteja no futuro.

+ +

Lembra do meu post anterior sobre tipos de valor e referência? Nele nós vimos que uma variável de um tipo de referência contém uma referência que aponta para uma instância daquele tipo específico. Mas quando a variável recebe null, seu conteúdo passa a ser o quê? Nada?

+ +

Não exatamente. Ainda que null essencialmente signifique nada, esse “nada” precisa ser representado de alguma forma na memória do computador.

+ +

No C#, a palavra reservada null representa uma referência nula, que é uma referência que não aponta para nenhum objeto. Na prática, essa referência é representada como um número (de 32 ou 64 bits, dependendo do sistema operacional) com todos os bits zerados.

+ +

É claro, tudo isso são detalhes de implementação. Isso poderia ter sido implementado de maneiras diferentes, ou seja, não é tão relevante assim pra gente agora. O que você realmente precisa entender é que você precisa de algo para representar nada. É necessário algum tipo de valor especial que significa “esse valor está faltando” ou “esse valor é desconhecido”.

+ +

Quando você entende isso, fica mais fácil enxergar qual é o problema com tipos de valor.

+ +

Como você representaria null para um tipo de valor?

+ +

Para entender qual é a dificuldade em fazer um tipo de valor ser nulo, você precisa considerar que tipos de valor geralmente têm um intervalo de valores possíveis que eles são capazes de representar.

+ +

É mais fácil de entender isso com um exemplo. Então, considere o tipo de valor byte.

+ +

Esse tipo representa um número inteiro sem sinal de 8 bits. Como 2 elevado a 8 é 256, é possível representar 256 valores. Como é um tipo “sem sinal”, ele só pode representar valores maiores ou igual a zero. Portanto, o range de valores possíveis para esse tipo é de 0 a 255.

+ +
00000000 => 0
+00000001 => 1
+00000010 => 2
+    .        .
+    .        .
+    .        .
+11111111 => 255
+
+ +

Agora vem a parte complicada. Se os projetistas do C# quisessem que o tipo byte fosse nulável, eles teriam que escolher um dos valores desse intervalo para elegê-lo como o valor nulo. Imagine que eles tivessem escolhido o zero. Nesse caso, nós nunca poderíamos usar o zero como um valor válido novamente!

+ +

Esse é todo o problema: para que um tipo de valor seja nulável, seria necessário sacrificar um dos possíveis valores do intervalo para representar o valor nulo.

+ +

Jon Skeet, autor do livro C# In Depth, é capaz de explicar bem melhor do que eu:

+ +
+

You’ve got to be able to store the values 0-255 in that variable; otherwise it’s useless for reading arbitrary binary data. With the 256 normal values +and one null value, you’d have to cope with a total of 257 values, and there’s no way of squeezing that many values into a single byte.

+ +

The designers could’ve decided that every value type would have an extra flag bit somewhere determining whether a value was null or contained real data, but the memory usage implications +are horrible, not to mention the fact that you’d have to check the flag every time you wanted the use the value.

+
+ +

Em tradução livre:

+ +
+

Você precisa ser capaz de armazenar os valores de 0 a 255 naquela variável; do contrário esse tipo seria inútil para ler dados binários arbitrários. Com os 256 valores normais e um valor nulo, você teria que lidar com um total de 257 valores, e não tem jeito de espremer tudo isso em um único byte.

+
+ +
+

Os projetistas poderiam ter decidido que todo tipo de valor teria um bit extra em algum lugar determinando se um valor é nulo ou contém dados reais, mas as implicações de uso de memória são horríveis, sem falar que você teria que checar esse bit toda vez que quisesse usar o valor.

+
+ +

Então, não há nada em princípio que impede que tipos de valor recebem nulo. É que seria tão complicado que os projetistas da linguagem decidiram que os benefícios de fazer isso não superam os custos.

+ +

Mas eu realmente preciso de um tipo de valor nulável. E agora?

+ +

Agora você entende as complicações envolvidas em representar null para um tipo de valor, e porque os projetistas do C# decidiram contra permitir isso. Mas, e se você realmente precisa fazer isso? Um cenário comum é quando você busca dados de um banco de dados relacional. O que é possível ser feito?

+ +

Felizmente há uma solução fácil. Ainda que tipos de valor “normais” não são nuláveis, a versão 2 do C# introduziu a estrutura Nullable<T>, que permite atribuir null a praticamente qualquer coisa.

+ +

Falarei sobre isso no próximo artigo da série. Como bônus, você vai aprender um pouco sobre outra feature interessante chamada generics.

+ +

Até lá!

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/tipos-valor-referencia-em-csharp/index.html b/pt/tipos-valor-referencia-em-csharp/index.html new file mode 100644 index 00000000..9049684d --- /dev/null +++ b/pt/tipos-valor-referencia-em-csharp/index.html @@ -0,0 +1,581 @@ + + + + + + + + Tipos de valor e referência em C# | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Tipos de valor e referência em C#

+ +
+ +
+

+ +

Este é o meu primeiro post pra valer aqui no meu blog, e eu decidi escrever sobre tipos de valor e tipos de referência em C#. Isso é um assunto relativamente básico, no sentido de que é algo que você já deveria entender caso você programe em C# profissionalmente. Mas ao mesmo tempo, é algo que pode ser um pouco contra-intuitivo caso você não seja um desenvolvedor experiente. +

+ +

Eu vou tentar deixar o post o mais simples e curto possível, então não vou falar hoje sobre imutabilidade de string, boxing, unboxing, e outras coisas com nomes chiques. +Vou escrever sobre essas coisas no futuro, mas por hoje vamos focar no básico.

+ +

Então, dê uma olhada no código a seguir:

+ +
int x = 10;
+int y = x;
+y++;
+Console.WriteLine($"O valor de x é {x}"); //Imprime "O valor de x é 10"
+Console.WriteLine($"O valor de y é {y}"); //Imprime "O valor de y é 11"
+ +

Nenhuma surpresa até aqui, esse é exatamente o comportamento que você esperaria. Agora, imagine que nós temos uma classe assim:

+ +
public class Pessoa
+{
+    public string Nome { get; set; }
+    public string Profissao {get; set; }
+
+    public Pessoa(string nome, string profissao)
+    {
+        Nome = nome;
+        Profissao = profissao;
+    }
+
+    public void DizerOi()
+    {
+        Console.WriteLine($"Oi! Meu nome é {Nome} e eu sou {Profissao}");
+    }
+}
+ +

Agora, faça o seguinte:

+ +
var pessoa = new Pessoa("Maria", "programadora");    
+pessoa.DizerOi(); // imprime "Oi! Meu nome é Maria e eu sou programadora"
+var pessoa2 = pessoa;
+pessoa2.Nome = "João";
+pessoa.Profissao = "músico";    
+pessoa.DizerOi(); // imprime "Oi! Meu nome é João e eu sou músico"  
+pessoa.DizerOi(); // imprime "Oi! Meu nome é João e eu sou músico"  
+ +

Esse é o momento no qual iniciantes costumam ficar confusos. “Isso não faz sentido”, eles dizem. “Eu mudei o valor de uma das variáveis, e a outra também mudou.” Bem, essa é a maneira errada de enxergar o que aconteceu. Na verdade, você não mudou o valor da varíavel, e esse é o ponto.

+ +

Lembra do primeiro exemplo? Vamos dar uma olhada nele novamente, dessa vez passo-a-passo:

+ +

A figura mostra um trecho de código C# no qual a variável é criada e lhe é atribuído o valor 10

+ +

Nós declaramos a primeira variável e atribuímos o valor 10 a ela. Agora, em algum lugar dentro da memória do computador, existe uma “caixa” com o nome de x, e dentro dessa caixa tem o valor 10.

+ +

A figura mostra um trecho de código C# no qual a variável y é criada e recebe o valor da variável x

+ +

Nós declaramos a segunda variável e atribuímos a ela o valor da primeira variável. Note que o valor é copiado de x para y. Agora nós temos duas caixas, uma chamada x e a outra y, e ambas guardam o valor 10.

+ +

A figura mostra um trecho de código em C# no qual o valor da variável y é incrementado em 1

+ +

Finalmente, nós incrementamos o valor da variável y em 1. Note que o valor de x permanece inalterado. Claro, por que eles realmente não tem nada a ver um com outro! Por outro lado, algo bem diferente acontece quando você está lidando com tipos de referência. Para entender isso, vamos repassar o segundo exemplo, também passo-a-passo:

+ +

A figura mostra um trecho de código C# no qual a variável pessoa é criada e recebe uma nova instância da classe Pessoa

+ +

Primeiramente, nós criamos uma variável chamada pessoa e atribuímos a ela uma nova instância da classe Pessoa. Agora, em algum lugar na memória do computador vive uma caixa chamada “pessoa”. Note, porém que nossa variável pessoa guarda uma referência que aponta para a instância da classe Pessoa, ao invés de guardar a própria instância!

+ +

A figura mostra a criação da variável pessoa2, que logo em seguida recebe o valor da variável pessoa

+ +

No segundo passo, criamos a variável “pessoa2” e atribuímos a ela o valor da variável “pessoa.” Assim como no exemplo anterior, o valor de uma variável é copiado para a outra. Nesse caso, o valor que é copiado é a referência que aponta para a instância de pessoa. Então agora nós temos duas variáveis cujos valores são referências que apontam para a mesma instância da classe Pessoa.

+ +

Agora, é claro que quando você mudar os dados do objeto (por exemplo, mudar o nome e/ou profissão da pessoa) parece que as duas variáveis foram alteradas. Na verdade, os valores das variáveis continuam exatamente o mesmo: o que foi realmente alterado é o objeto para o qual elas apontam.

+ +

Então, podemos resumir da seguinte forma: tipos de valor armazenam dados. Quando você atribuir o valor de uma variável a outra, o que é copiado são os próprios dados (como um número inteiro, por exemplo). Isso é parecido com quando você copia um arquivo de uma pasta em seu computador e cola em outro lugar. Você fez uma cópia, mas de agora em diante eles são arquivos independentes e não têm nada a ver um com o outro.

+ +

Tipos de referência armazenam uma referência, que apontam para os dados, que vivem em algum outro lugar na memória do computador. Quando você atribui o valor de uma variável de referência para outra, o que é copiado é a referência. Pode ser útil pensar nas referências como atalhos para arquivos. Se você tem um ou mais atalhos que apontam para um arquivo em particular no seu HD, quando você fizer alterações no arquivo, tais alterações serão visíveis quando você acessar o arquivo pelo atalho. Pois eles não passam disso, atalhos.

+ +

Quais tipos são tipos de valor?

+ +

De acordo com o MSDN, os tipos de valor são:

+ +
    +
  • Todos os tipos númericos
  • +
  • Boolean, Char, e Date
  • +
  • Todas as estruturas
  • +
  • Enumerações
  • +
+ +

Quais tipos são tipos de referência?

+ +

Novamente, de acordo com o MSDN:

+ +
    +
  • String
  • +
  • Todos os arrays
  • +
  • Classes
  • +
  • Delegates
  • +
+ +

Espera um pouco! String é um tipo de referência?!

+ +

Talvez você tenha se surpreendido em ver String listada como um tipo de referência. Afinal de contas, ela parece se comportar como um tipo de valor. Bom, a razão para isso é que a string é um tipo imutável. Como eu disse antes, não vou falar sobre isso hoje, mas em breve teremos um post inteiro sobre System.String.

+ +

Bom, por hoje é só. Espero que tenham gostado do post, e eu adoraria ter o feedback de vocês. Eu me expressei claramente? Eu disse algo um pouco impreciso - ou mesmo totalmente errado? Deixe um comentário aqui embaixo ou me chame no twitter.

+ +

Referências (em inglês):

+ + + + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/traducao-fases-estabilizacao/index.html b/pt/traducao-fases-estabilizacao/index.html new file mode 100644 index 00000000..571d7aee --- /dev/null +++ b/pt/traducao-fases-estabilizacao/index.html @@ -0,0 +1,551 @@ + + + + + + + + Fases de Estabilização | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + pt + + + +
+ + +
+
+
+ +
+

Fases de Estabilização

+ +
+ +
+

+ +

NOTA: O artigo a seguir foi originalmente escrito por Robert C. Martin, mais conhecido como Uncle Bob. Bob é um programador com décadas de experiência, autor de diversos livros (Código Limpo, por exemplo) e foi o organizador do encontro em 2001 que deu origem ao Manifesto Para Desenvolvimento Ágil de Software. Ele gentilmente me autorizou a fazer essa tradução. Caso lhe interesse, clique aqui para ler o artigo original. +

+
+ +

Enquanto tomava meu café de manhã e dava uma olhada no facebook em meu celular, fui inundado com updates de status de proprietários de veículos Tesla que estavam animados porque seus carros agora poderiam entrar na garagem de maneira autônoma. Minha resposta a esses posts no facebook talvez tenha sido um pouco cínica; mas eu disse a todos eles:

+ +
+

Vai demorar muito até eu confiar em um software para dirigir o carro no qual eu estou. +Porque eu – sei.

+
+ +

Eu sei o quê? Eu sei o quão difícil é testar software para cada imprevisto. +E eu sei como é fácil enganar a si próprio achando que você testou.

+ +

E isso me fez pensar sobre como você deveria testar o software de um carro autônomo.

+ +

E isso me fez pensar sobre como as pessoas de fato testam sistemas de software.

+ +

E isso finalmente me fez pensar sobre fases de estabilização.

+ +

Você sabe o que é uma fase de estabilização, não sabe? Uma fase de estabilização ocorre no final de uma release. Algum tempo é reservado para apenas deixar o sistema rodar. Por uma semana, ou um mês, todo mundo apenas assiste o sistema rodando. Eles o tratam como um bebê dormindo. Eles evitam barulhos altos, batidas de portas, e conversa alta. Eles andam nas pontas dos dedos, dando uma olhadinha de tempos em tempos, com a esperança de que ele não acorde e quebre.

+ +

OK, talvez isso seja um pouco exagarado. – Talvez. Eu imagino que a maioria dos times que usam fases de estabilização realmente trabalham muito duro para estressar seus sistemas. Pelo menos eu espero que eles façam isso. Eles deveriam estar inserindo muitos dados no dados sob condições diversas; incluindo dados incorretos, e que causaram problemas no passado.

+ +

Mas essa é a coisa importante sobre fases de estabilização:

+ +
Nós as usamos porque temos medo. 
+Nós temos medo porque não temos certeza do que o sistema irá fazer.
+
+ +

Há uma certa dissonância cognitiva entre dizer que somos profissionais, e sermos tão incertos sobre o que criamos que temos medo do que pode fazer. Geralmente se espera que uma equipe de profissionais tenha um alto grau de confiança e certeza.

+ +

Quanto maior o tempo de duração da fase de estabilização, menor é a certeza que o time tem sobre o sistema. As equipes que precisam de apenas um dia têm muito mais confiança em seus sistemas que as equipes que querem uma semana, ou um mês.

+ +

A falha lógica aqui é que tempo de execução indica qualidade. Mas tempo na verdade não é relacionado à qualidade. Tempo simplesmente cria falsa confiança.

+ +

O comportamento do sistema na fase de estabilização tem pouco ou nada a ver com o comportamento do sistema em produção; porque os dados entrando no sistema de produção são dados completamente novos. Os novos dados podem levar o sistema a percorrer caminhos que a fase de estabilização nunca executou.

+ +

Então fases de estabilização apenas criam falsa confiança. Elas são uma estratégia para “tirar o seu da reta.” Quando o sistema falha em produção, você pode pelo menos dizer que você fez o esforço devido de rodar o sistema por um mês na fase de estabilização; dessa forma exonerando a equipe da culpa de deixar um defeito crítico entrar no sistema.

+ +

O problema crucial é que a fase de estabilização existe porque o time de desenvolvimento produziu código no qual eles não confiam. Então eles rodam o sistema por um mês para criar suficiente falsa confiança para enfrentar a incerteza.

+ +

O que a equipe realmente precisa fazer é atacar sua incerteza diretamente. Não rodando o sistema inutilmente por um mês; mas sim corrigindo os problemas no seu processo de desenvolvimento que criaram essa incerteza. Considere o checklist seguinte:

+ +
    +
  • Você está executando ferramentas de cobertura? Você checa se cada if e while estão cobertos?
  • +
  • A cobertura de testes unitários é próxima de 100%?
  • +
  • Você precisa aumentar um pouco a cobertura escrevendo mais testes?
  • +
  • Você tem testes de aceitação automatizados escritos por (ou pelo menos validados por) pessoas de negócio e Garantia de Qualidade?
  • +
  • A cobertura de testes é alta o suficiente? Você precisa aumenta-la um pouco pedindo para a GQ considerar mais alguns casos extremos?
  • +
  • Você tem testes de integração automatizados escritos por arquitetos e desenvolvedores líderes?
  • +
  • Esses testes estressam os caminhos de comunicação entre os componentes?
  • +
  • Eles checam por casos excepctionais, problemas nos limites e timeouts?
  • +
  • Eles examinam o comportamento do sistema sob cargas variáveis?
  • +
  • Se você tem múltiplas threads, você tem uma estratégia para estressar essas threads durante seus testes unitários e testes de aceitação?
  • +
  • Por exemplo, você implementou ferramentas que introduzem delays aleatórios e cargas aleatórios para que as probabilidades de condições de corrida sejam aumentadas?
  • +
  • Melhor ainda, você está gradualmente eliminando a possbilidade de condições de corrida por meio da eliminação de estados mutáveis entre threads? Você desenhou todos os diagramas de sequência de mensagens e os examinou em busca de corridas em potencial?
  • +
+ +

Esse checklist é só um exemplo. Eu tenho certeza que você consegue pensar em mais coisas para acrescentar. O ponto é que é melhor ser proativo a respeito da sua incerteza, do que ser passivo a respeito dela. E fases de estabilização são passivas.

+ +

O objetivo de equipes de software que estão atualmente usando fases de estabilização deveria ser aumentar sua confiança com o tempo, e dessa forma reduzir a duração de suas fases de estabilização. Reduza de um mês, para uma semana. Então de uma semana para um dia. Então de um dia para uma hora.

+ +

E então, finalmente, aumenta sua confiança ao ponto de poder eliminar a fase de estabilização de uma vez por todas.

+ +

Uma historinha:

+ +

Eu recentemente fiz um test-drive com uma Tesla. É um carro divertido de se dirigir. Realmente divertido. +Eu testei a funcionalidade de piloto automático, que é facilmente ativada apertando um botão na coluna de direção. +O carro alegremente lhe informa que a partir de agora está dirigindo a si mesmo; e lhe alerta para manter as mãos no volante. Preste atenção nesse aviso!

+ +

O carro se saiu razoavelmente bem quando as marcas na estrada eram visíveis, mas parecia bastante disposto a me arrebentar em algumas barragens de construção. Não é seguro tirar suas mãos do volante ou seus olhos da pista. Para mim, isso torna a funcionalidade menos que inútil.

+ +

O vendedor estava sentado do meu lado. Em um certo momento nós estávamos indo a 70 km/h em direção à traseira de um carro parado no sinal fechado. O vendedor disse: “Confie no carro.” E eu pensei: “Até parece!” E eu freei o carro. +A tecnologia é interessante; mas perigosa. NUNCA “confie no carro”!

+ +

Talvez você tenha percebido que a perspectiva de carros autônomos não me enche de entusiasmo. Eu vou continuar pensando o que será que esses carros farão um segundo após 29 de fevereiro.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/pt/value-objects-ferramenta/index.html b/pt/value-objects-ferramenta/index.html new file mode 100644 index 00000000..f6216b92 --- /dev/null +++ b/pt/value-objects-ferramenta/index.html @@ -0,0 +1,584 @@ + + + + + + + + Value Objects: Uma Técnica Para Código Auto-Documentado E Menos Erros | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + en pt + + + +
+ + +
+
+
+ +
+

Value Objects: Uma Técnica Para Código Auto-Documentado E Menos Erros

+ +
+ +
+

+ +

*NOTA: Eu escrevi este post originalmente para o blog da NDepend. Você pode conferir o artigo original, em inglês, no site deles. *

+ +

Você já ouviu falar de value objects? Eu imagino que sim. Apesar de não se falar tanto a respeito deles como eu gostaria, eles ainda são mencionados o bastante para que muitos desenvolvedores tenham no mínimo alguma familiaridade com o termo.

+ +

Porém, “alguma familiaridade” não é bom o bastante. Então é isso que vamos consertar com esse post. Hoje vamos aprender o que value objects são e como você, por meio do C#, pode usar todo o poder deles para tornar seu código mais claro, auto-documentável e menos propenso a erros.

+ +

O que são Value Objects?

+ +

Value objects são um dos blocos fundamentais do DDD (Domain Driven Design, ou Projeto Guiado por Domínio, em tradução livre), conforme proposto por Eric Evans em seu livro Domain-Driven Design: Tackling Complexity in the Heart of Software.

+ +

Da maneira mais simples possível, um value object é um objeto que representa um valor. E sim, eu estou ciente de que isso soa óbvio e tedioso quando dito dessa forma. Então, por que tanto barulho por causa desse conceito?

+ +

Algumas Propriedades

+ +

Eu acho que é mais fácil de entender value objects se eu parar de tentar explicar o que eles são e, ao invés disso, falar sobre as suas características.

+ +

Value Objects Não Têm Identidade

+ +

Eu acho que é justo dizer que a principal característica dos value objects é que eles não possuem identidade. Mas o que isso realmente quer dizer na prática?

+ +

Digamos que você vá até o caixa eletrônico mais próximo e deposite uma nota de 50 reais em sua conta. Então você dirige umas duas horas até outra cidade, entra em uma agência bancária, e saca 50 reais.

+ +

Pergunta: faz alguma diferença para você o fato de que a nota que você tem em mãos não é a mesma que você depositou antes? É claro que não! Quando se trata de dinheiro o que as pessoas geralmente se importam é com seu valor, não com o veículo daquele valor.

+ +

Em outras palavras, nós não damos a mínima para a identidade daquela cédula em particular. A única coisa com a qual nós nos importamos é o seu valor.

+ +

Não é coincidência o fato de que dinheiro é um exemplo clássico de value object na literatura.

+ +

Value Objects São Imutáveis

+ +

Você consegue mudar o número cinco? Não. Não há nada que você (ou qualquer outra pessoa) possa fazer para mudar o valor do número 5. Se você adicionar 1, ele não muda. Você tem agora 6, que é um outro número.

+ +

É possível alterar uma data? Não, também não dá para fazer isso. Se você inicia com “2018-01-09” e adiciona um dia, você chega em “2018-01-10.” O valor original não é alterado de forma alguma. Na verdade, a imutabilidade de um value object é uma consequência direta do ponto anterior; como um value object não possui identidade, podemos dizer que o value object é o seu valor. Portanto, nem sequer faz sentido falar sobre mudá-lo.

+ +

A implicação disso no desenvolvimento é que value objects são intrinsecamente mais seguros e mais fáceis de serem compreendidos. Não tem perigo de mudar por acidente aquilo que você não pode mudar de jeito nenhum.

+ +

Value Objects Têm Igualdade Estrutural

+

Imagine que você pudesse magicamente transportar pessoas para qualquer lugar que você quisesse e, por alguma razão bizarra, você tenha decidido trocar dois homens chamados “João da Silva” durante a noite. Como você acha que as suas respectivas famílias reagiriam ao encontrar um estranho em casa na manhã seguinte?

+ +

Obviamente, pessoas não são intercambiáveis, mesmo que compartilhem uma ou mais características. Mesmo se nossos dois “Joães” (Joões?) tivessem não apenas o mesmo nome, mas também a mesma altura, peso, cor de pele e cabelo, eles ainda seriam duas pessoas completamente diferentes. Mesmo gêmeos idênticos (ou clones, caso você esteja numa onda meio Black Mirror) continuam sendo pessoas completamente diferentes, apesar de serem tão iguais um ao outro quanto é possível ser.

+ +

Por outro lado, as pessoas mudam constantemente durante a vida, mas continuam sendo as mesmas pessoas. Pelo menos (enquanto a gente não resolver filosofar com “um homem não entra no mesmo rio duas vezes” e coisas do tipo).

+ +

Você talvez esteja se perguntando se eu divaguei demais aqui, mas é tudo de propósito. Tudo isso serve apenas para ilustrar a diferença crucial entre entidades e value objects. Com as entidades, nós nos importamos com a sua identidade, não com o valor de seus atributos. Com value objects, é exatamente o oposto.

+ +

A implicação disso, em termos de programação, é que value objects tipicamente apresentam igualidade estrutural. Faz sentido compará-los pelos seus valores, não suas referências ou identidades. Então, quando for implementar um value object, sempre faça override dos métodos Equals e GetHashCode.

+ +

O que Você Ganha Com Isso?

+

A essa altura você já deve ter uma boa ideia do que value objects são. O que ainda não está claro é: por que você deveria usá-los? Para responder isso, vamos dar uma olhada na linha de código a seguir:

+ +
    double  distance  =  4.5;
+ +

Tem algo errado com a linha acima? Bom, eu poderia dar uma de Ben Kenobi e dizer que está errada “de um certo ponto de vista.” Mas eu não vou. Ao invés disso, vou dizer que está definitivamente, sem sombra de dúvidas, errada. Não importa que compila corretamente. Também não importa que funciona um pouco (ou até na maioria) do tempo.

+ +

O problema aqui é o code smell conhecido como “obsessão primitiva”, isto é, a modelagem de conceitos de domínio usando tipos primitivos. As próximas seções vão explicar melhor porque isso é um problema tão sério e como o uso de value objects podem ajudar.

+ +

Value Objects Proporcionam Contexto

+ +

Por que obsessão primitiva é algo ruim? Há várias razões, mas um dos principais problemas com a linha de código que você viu na seção anterior é que há uma informação extremamente importante faltando. Como você pode ver, o código atribui o valor 4.5 à variável. Mas 4.5 o que? Metros? Quilômetros? Milhas? Parsecs? Em outras palavras, falta uma unidade de medida.

+ +

Isso pode ser uma receita para o desastre. Tudo o que você precisa é alguém recuperar um valor do banco de dados ou de um arquivo, pensando que representa metros mas na verdade são quilômetros. Quando a pessoa resolve usar o valor em um cálculo, adicionando quilômetros com metros…silêncio. Você agora tem um programa que, no lugar de falhar rápido como deveria, se comporta de maneira errada silenciosamente enquanto corrompe dados e gera resultados inconsistentes. Ainda bem que você usa testes unitários…certo?

+ +

Tudo bem, nada impede você de colocar essa informação no próprio nome da variável:

+ +
	double  distanceInKilometers  =  4.5;
+ +

Certo, isso é um pouco melhor do que a versão anterior, mas ainda é uma solução muito frágil. A qualquer momento o valor pode ser atribuído a outra variável ou passado como argumento para uma função, e aí a unidade de medida é perdida.

+ +

Usando value objects, você pode eliminar esse problema facilmente. Você teria apenas que escolher uma unidade para ser a representação interna do tipo - para distância, faz sentido usar o metro, por ser uma unidade do Sistema Internacional de Medidas. E aí você pode implementar diversos métodos estáticos para fabricar valores para cada unidade necessária:

+ +
	var  distance  =  Distance.FromMeters(4000);
+	var  distance2  =  Distance.FromKilometers(4);
+	Assert.AreEqual(distance,  distance2);
+ +

Você poderia ainda sobrecarregar o operador “+” (ou criar um método Plus). Dessa forma seria possível somar duas distâncias que se originaram de diferentes unidades de medida já que a representação interna é a mesma.

+ +

Value Objects Apresentam Segurança de Tipo

+ +

Digamos que você tem um método com a seguinte assinatura:

+ +
	double  PerformSomeImportantCalculation(double  distance,  double  temperature);
+ +

O que aconteceria se você cometesse um erro e invertesse os valores ao chamar o método? O programa iria silenciosamente se comportar erro, e você nem ficaria sabendo. Com sorte, a sua empresa teria um bom processo de garantia de qualidade que poderia pegar esse erro antes de chegar no ambiente de produção. Mas ficar dependendo de sorte não é lá uma grande estratégia, concorda?

+ +

Pois acontece que esse é o tipo de problema que value objects são ótimos em evitar. Você teria apenas que usar tipos customizados para cada conceito em vez de tipos primitivos:

+ +
	double  PerformSomeImportantCalculation(Distance distance,  Temperature temperature);
+ +

Dessa forma, se torna impossível passar os parâmetros na ordem errada: o compilador simplesmente não deixa!

+ +

Value Objects Evitam Duplicação de Lógica de Domínio

+ +

Quando você usa tipos primitivos para modelar conceitos de domínio, a tendência é você ter um monte de código relacionado a esses conceitos espalhados por toda a aplicação. Imagine que você está criando um programa que tem o conceito de uma placa de carro, e você está usando strings para representá-las. É claro que nem todas as strings válidas são placas válidas. Então o seu código acaba entupido de validações de placas de carro por todo lugar.

+ +

Isso seria evitado criando uma classe chamada LicensePlate e fazendo todas as validações necessárias em seu construtor. Dessa forma você consolidaria todo o código de validação em apenas um lugar; se esse código precisar mudar no futuro, você tem que mudar em apenas um lugar.

+ +

Value Objects e Tipos de Valor Não São Sinônimos

+ +

Essa seção é necessária para clarificar um erro comum, que é confundir value objects com o conceito de value types (tipos de valor) que existe no C#. É assim: na linguagem C# nós temos duas categorias de tipos: tipos de referência e tipos de valor.

+ +

Sim, não há nada que impeça você de usar structs (tipos de valor) para implementar value objects - exemplos na Base Class Library (BCL) seriam o tipo DateTime ou os tipos numéricos primitivos. Mas você também pode usar classes tranquilamente.

+ +

Por outro lado, structs não podem ser considerados value objects automaticamente. Por exemplo, embora manter structs imutáveis seja uma prática recomendada, eles não são imutáveis por padrão.

+ +

Resumidamente, “tipo de valor” é um detalhe de implementação em C#/.NET e “value object” é um padrão de projeto. Mantenha isso em mente e consulte as diretrizes de design da Microsoft e tudo vai ficar bem.

+ +

Value Objects Valem a Pena!

+ +

O uso de value objects é uma técnica com um custo relativamente baixo que pode aumentar bastante a manutenibilidade e claridade do seu código. Colocando value objects em prática, você pode tornar seu código mais fácil de ser compreendido, criando interfaces que são auto-documentáveis, difíceis de serem usadas da maneira errada, e intrinsecamente type-safe.

+ + + + + + + Encontrou algum erro no post? Sugira uma edição + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/readings/index.html b/readings/index.html new file mode 100644 index 00000000..b27ca34b --- /dev/null +++ b/readings/index.html @@ -0,0 +1,202 @@ + + + + + + + + Interesting Readings | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en +
+ + +
+
+
+ +
+

Interesting Readings

+
+ +
+

Table of Contents

+ +
    +
  • Management +
      +
    • “Maker’s Schedule, Manager’s Schedule”, by Paul Graham
    • +
    +
  • +
  • Programming +
      +
    • “The Grug Brained Developer”
    • +
    +
  • +
  • Writing +
      +
    • “A blogging style guide”, by Robert Heaton
    • +
    • “A blogging style guide vol. 2”, by Robert Heaton
    • +
    +
  • +
+ +

The purpose of this page is to keep track of the interesting things that I had read. These things will be mostly blog posts, +but the list might include books, academic papers, and other forms of content at some point.

+ +

I copied the idea from here.

+ +

Management

+ + +

Programming

+
    +
  • “The Grug Brained Developer”: a humorous guide about software development learnings, collected over the author’s career. In a way, it’s a warning against unnecessary complexity.
  • +
+ +

Writing

+ + +
+ +
+ +
+
+ + + + + + + + diff --git a/rss.xml b/rss.xml new file mode 100644 index 00000000..a1190789 --- /dev/null +++ b/rss.xml @@ -0,0 +1,3209 @@ + + + + carlos schults / blog + Artigos sobre desenvolvimento de software e tecnologia. + https://carlosschults.net/ + + Fri, 02 Aug 2024 13:11:07 +0000 + Fri, 02 Aug 2024 13:11:07 +0000 + Jekyll v4.3.1 + + + + [Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg" alt="" /></p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + NOTA + </div> + <div class="callout-content"> + +<p>Este post é uma tradução, cuja publicação foi autorizada pelo autor. Caso tenha interesse, <a href="https://stenbrinke.nl/blog/configuration-and-secret-management-in-dotnet/">leia o artigo original, em inglês.</a>.</p> + +<p>Eu decidi não traduzir as imagens, pois achei que seria muito trabalhoso. Portanto, as figuras que você verá são as mesmas do artigo original, com as informações nelas em inglês.</p> + +<p>Em respeito ao autor, procurei deixar o artigo o mais próximo possível do original: mantive <em>call to actions</em> que o autor faz para suas palestras e conteúdos, e também mantive um pedido de contribução financeira ao final do artigo.</p> + +<p>A partir do índice, inicia-se o artigo de autoria de Sander ten Brinke. Após a conclusão do artigo, eu volto com algumas palavras antes de finalizar. Boa leitura!</p> + + + </div> +</div> + +<h2 id="índice">Índice</h2> + +<ul> + <li><a href="#introdução">Introdução</a></li> + <li><a href="#configuração-no-net">Configuração no .NET</a> + <ul> + <li><a href="#o-básico">O básico</a></li> + <li><a href="#acesso-a-dados-estruturados">Acesso a dados estruturados</a></li> + <li><a href="#como-tudo-isso-funciona">Como tudo isso funciona</a></li> + <li><a href="#tratando-a-configuração-como-código">Tratando a configuração como código</a></li> + </ul> + </li> + <li><a href="#options-pattern">options pattern</a> + <ul> + <li><a href="#injeção-de-dependência">Injeção de dependência</a></li> + <li><a href="#validação">Validação</a></li> + <li><a href="#tempos-de-vida-da-configuração">Tempos de vida da configuração</a></li> + </ul> + </li> + <li><a href="#gerenciamento-de-segredos-durante-o-desenvolvimento">Gerenciamento de segredos durante o desenvolvimento</a> + <ul> + <li><a href="#o-provedor-de-configuração-de-user-secrets">O provedor de configuração de user secrets</a></li> + <li><a href="#usando-user-secrets">Usando user secrets</a></li> + <li><a href="#configurando-um-projeto-que-usa-user-secrets">Configurando um projeto que usa user-secrets</a></li> + </ul> + </li> + <li><a href="#meu-modelo-para-gerenciamento-de-configuração">Meu modelo para gerenciamento de configuração</a> + <ul> + <li><a href="#appsettingsjson">appsettings.json</a></li> + <li><a href="#appsettingsdevelopmentjson">appsettings.Development.json</a></li> + <li><a href="#user-secrets">User Secrets</a></li> + </ul> + </li> + <li><a href="#usando-o-azure-para-armazenar-a-configuração">Usando o Azure para armazenar a configuração</a> + <ul> + <li><a href="#armazenamento-de-segredos-no-azure-key-vault">Armazenamento de segredos no Azure Key Vault</a></li> + <li><a href="#conectando-se-ao-azure-com-identidades-gerenciadas">Conectando-se ao Azure com identidades gerenciadas</a></li> + <li><a href="#armazenamento-da-configuração-na-configuração-de-aplicativo-do-azure">Armazenamento da configuração na Configuração de Aplicativo do Azure</a></li> + </ul> + </li> + <li><a href="#finalizando">Finalizando</a> + <ul> + <li><a href="#links-para-a-demo">Links para a demo</a></li> + <li><a href="#links-para-a-documentação-oficial">Links para a documentação oficial</a></li> + </ul> + </li> + <li><a href="#carlos-de-volta">Carlos de volta</a></li> +</ul> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Este post é um complemento da minha palestra <a href="https://sessionize.com/s/sander-ten-brinke/keep-it-secret-keep-it-safe-with-.net/48314">Keep it secret, keep it safe with .NET</a>! Se você não puder assistir a uma sessão dessa palestra, poderá ler este post em vez disso! Dessa forma, o maior número possível de pessoas poderá aprender sobre o sistema de configuração do .NET e como manter os segredos em segurança!</p> + +<p>Minha palestra oferece algumas informações mais detalhadas, portanto, se quiser saber mais, dê uma olhada na minha página <a href="https://stenbrinke.nl/speaking">Speaking</a> para ver quando e onde darei essa palestra novamente! Você também pode <a href="https://stenbrinke.nl/about/#contact-details">entrar em contato</a> se quiser que eu dê essa palestra em seu evento!</p> + + </div> +</div> + +<h2 id="introdução">Introdução</h2> + +<p>Se você já escreve código há algum tempo, provavelmente já usou configuração de alguma forma. Pense em feature flags, configurações de log, configurações de autenticação etc. Talvez você tenha usado um arquivo de configuração com algumas configurações para o seu aplicativo ou talvez tenha usado variáveis de ambiente. Talvez você tenha usado ambos!</p> + +<p>Também é provável que você tenha interagido com segredos, que também considero parte de um sistema de configuração. Pense em strings de conexão e chaves de API. Elas devem ser sempre seguras!</p> + +<p>A configuração no .NET mudou radicalmente desde a introdução do .NET Core. Já se foi o tempo em que se usavam vários arquivos <code class="language-plaintext highlighter-rouge">Web.config</code> e agora temos um sistema muito mais flexível. No entanto, um sistema flexível também pode ser um sistema complexo. É por isso que eu quis criar uma palestra e uma publicação no blog em que você aprenderá como funciona o sistema de configuração do .NET e como usá-lo de forma otimizada. Você também aprenderá a manter seus segredos seguros, tanto localmente quanto em produção, usando o poder da nuvem do Azure!</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Este post contém <strong>tudo</strong> que você precisa saber sobre configuração e gerenciamento de segredos no .NET. Ela não aborda todos os detalhes, mas abrange tudo o que acredito que um desenvolvedor .NET tem que saber. Considere-o um guia de bolso útil que você pode usar ou enviar a outras pessoas quando elas tiverem dúvidas sobre configuração e gerenciamento de segredos no .NET.</p> + +<p>Acho que esta post é muito útil porque são necessárias <strong>múltiplas horas</strong> para <em>encontrar</em> e ler completamente a documentação da Microsoft sobre esses tópicos. Se quiser saber mais, você encontrará links para a documentação oficial no final do post.</p> + + </div> +</div> + +<p>Vamos começar!</p> + +<h2 id="configuração-no-net">Configuração no .NET</h2> + +<p>O sistema de configuração do .NET é muito flexível! Você pode usar vários provedores de configuração, sendo que cada um deles pode ter um formato de configuração diferente:</p> + +<p><img src="/img/configuracao-dotnet/configuration-overview.webp" alt="Uma imagem que mostra uma visão geral do sistema de configuração do .NET com a interface IConfiguration e vários provedores" /></p> + +<p>Uma visão geral do sistema de configuração do .NET.<br /> +<a href="https://learn.microsoft.com/dotnet/core/extensions/configuration?WT.mc_id=DT-MVP-5005050#concepts-and-abstractions">Extraído da documentação oficial</a></p> + +<p>Outras fontes podem ser arquivos como <code class="language-plaintext highlighter-rouge">.xml</code>, <code class="language-plaintext highlighter-rouge">.ini</code> e muito mais. Você pode até mesmo conectar seu sistema de configuração à nuvem, o que faremos mais adiante!</p> + +<h3 id="o-básico">O Básico</h3> + +<p>Como você pode ver, toda a sua configuração pode ser acessada usando a interface <code class="language-plaintext highlighter-rouge">IConfiguration</code>. Com isso, você pode recuperar seus valores de uma maneira fortemente tipada. Um exemplo:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="n">IConfiguration</span> <span class="n">Configuration</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + +<span class="k">public</span> <span class="kt">string</span> <span class="nf">GetApiKey</span><span class="p">()</span> +<span class="p">{</span> + <span class="c1">// GetValue&lt;&gt; permite que você passe o tipo de retorno</span> + <span class="kt">string</span> <span class="n">method1</span> <span class="p">=</span> <span class="n">Configuration</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="err">“</span><span class="n">ApiKey</span><span class="err">”</span><span class="p">);</span> + + <span class="c1">// A variante do indexador sempre retorna uma string</span> + <span class="kt">string</span> <span class="n">method2</span> <span class="p">=</span> <span class="n">Configuration</span><span class="p">[</span><span class="err">“</span><span class="n">ApiKey</span><span class="err">”</span><span class="p">];</span> + + <span class="k">return</span> <span class="n">method1</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Você perceberá que não estamos especificando qual provedor deve ser usado para recuperar a <code class="language-plaintext highlighter-rouge">ApiKey</code>. Isso ocorre porque isso não deveria importar; a <code class="language-plaintext highlighter-rouge">IConfiguration</code> esconde toda essa complexidade de nós e, portanto, cria flexibilidade. O sistema de configuração decide qual provedor usar com base na ordem dos provedores. Falaremos mais sobre isso mais tarde!</p> + +<h3 id="acesso-a-dados-estruturados">Acesso a dados estruturados</h3> + +<p>Um recurso muito avançado do sistema de configuração do .NET é o fato de ele oferecer suporte a dados estruturados. Isso é muito útil porque permite que você agrupe valores de configuração relacionados. Todos os provedores oferecem suporte a dados estruturados, mas se você já trabalhou com um projeto ASP.NET Core, provavelmente reconhecerá o mais comum, que é <code class="language-plaintext highlighter-rouge">appsettings.json</code>. O JSON a seguir é um exemplo de um arquivo desse tipo:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ + “Logging": { + “LogLevel": { + “Default” (Padrão): “Informações”, + “Microsoft.AspNetCore": “Warning” + } + }, + “AllowedHosts": “*”, + + “ConnectionStrings": { + “Banco de dados": “CONNECTIONSTRING_HERE” + }, + + “Features” (Recursos): { + “EnableNewUI": false + } +} +</code></pre></div></div> + +<p>Você pode imaginar o objeto raiz e as seções <code class="language-plaintext highlighter-rouge">Logging</code>, <code class="language-plaintext highlighter-rouge">ConnectionStrings</code> e <code class="language-plaintext highlighter-rouge">Features</code> como “dados estruturados”.</p> + +<p>Para interagir com essas seções no .NET, você pode usar o código a seguir.</p> + +<div class="callout callout-warning"> + <div class="callout-title"> + <span class="callout-icon">⚠️</span> + Aviso + </div> + <div class="callout-content"> + +<p>O código a seguir não é a melhor maneira de interagir com dados estruturados! Falaremos sobre maneiras melhores (usando o padrão Options) <a href="#options-pattern">mais adiante</a>.</p> + + </div> +</div> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="n">IConfiguration</span> <span class="n">Configuration</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + +<span class="c1">// ...</span> + +<span class="k">public</span> <span class="n">IConfigurationSection</span> <span class="nf">GetFeaturesSection</span><span class="p">()</span> +<span class="p">{</span> + <span class="c1">// GetSection retorna nulo quando a seção não pode ser encontrada</span> + <span class="kt">var</span> <span class="n">method1</span> <span class="p">=</span> <span class="n">Configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="err">“</span><span class="n">Features</span><span class="err">”</span><span class="p">);</span> + + <span class="c1">// GetRequiredSection dispara uma exceção quando a seção não pode ser encontrada.</span> + <span class="c1">// SEMPRE prefira esse método ao GetSection para evitar bugs desagradáveis!</span> + <span class="kt">var</span> <span class="n">method2</span> <span class="p">=</span> <span class="n">Configuration</span><span class="p">.</span><span class="nf">GetRequiredSection</span><span class="p">(</span><span class="err">“</span><span class="n">Features</span><span class="err">”</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">method2</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">public</span> <span class="kt">bool</span> <span class="nf">GetEnableNewUI</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">Configuration</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">bool</span><span class="p">&gt;(</span><span class="err">“</span><span class="n">Features</span><span class="p">:</span><span class="n">EnableNewUI</span><span class="err">”</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>A <code class="language-plaintext highlighter-rouge">IConfigurationSection</code> fornece a mesma API que a <code class="language-plaintext highlighter-rouge">IConfiguration</code>, portanto, você pode chamar <code class="language-plaintext highlighter-rouge">featuresSection.GetValue&lt;bool&gt;(“EnableNewUI”)</code> para obter o valor dessa seção. Também é possível acessar diretamente um valor de configuração que existe dentro de uma seção usando um <code class="language-plaintext highlighter-rouge">:</code>, que pode ser visto em uso no método <code class="language-plaintext highlighter-rouge">GetEnableNewUI</code>.</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Os dados estruturados não se limitam aos arquivos JSON. Todos os provedores são compatíveis com eles, embora a sintaxe para especificar uma seção possa ser diferente. Por exemplo, para fornecer um valor para <code class="language-plaintext highlighter-rouge">EnableNewUI</code> usando uma variável de ambiente, você terá que criar uma chamada <code class="language-plaintext highlighter-rouge">Features__EnableNewUI</code>.</p> + + </div> +</div> + +<h3 id="como-tudo-isso-funciona">Como tudo isso funciona?</h3> + +<p>Estamos usando <code class="language-plaintext highlighter-rouge">IConfiguration</code> em alguns exemplos. Você deve estar se perguntando como tudo isso funciona nos bastidores; como criar uma instância de <code class="language-plaintext highlighter-rouge">IConfiguration</code> e como configurá-la? Vamos dar uma olhada!</p> + +<p>Para criar uma instância de <code class="language-plaintext highlighter-rouge">IConfiguration</code>, você precisará usar a classe <code class="language-plaintext highlighter-rouge">ConfigurationBuilder</code> (ou outra classe que implemente <code class="language-plaintext highlighter-rouge">IConfigurationBuilder</code>). Essa classe usa o padrão Builder para que você possa adicionar vários provedores. No final, você chama <code class="language-plaintext highlighter-rouge">Build()</code> e acaba com um <code class="language-plaintext highlighter-rouge">IConfigurationRoot</code>. É a mesma coisa que <code class="language-plaintext highlighter-rouge">IConfiguration</code>, mas também tem uma lista de todos os provedores que você adicionou. Você nunca deve usar o <code class="language-plaintext highlighter-rouge">IConfigurationRoot</code> diretamente, pois não deve acessar os provedores por baixo do pano. Um exemplo:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ConfigurationBuilder</span><span class="p">();</span> + +<span class="n">builder</span><span class="p">.</span><span class="nf">AddJsonFile</span><span class="p">(</span><span class="err">“</span><span class="n">sharedsettings</span><span class="p">.</span><span class="n">json</span><span class="err">”</span><span class="p">);</span> +<span class="n">builder</span><span class="p">.</span><span class="nf">AddJsonFile</span><span class="p">(</span><span class="err">“</span><span class="n">appsettings</span><span class="p">.</span><span class="n">json</span><span class="err">”</span><span class="p">);</span> +<span class="n">builder</span><span class="p">.</span><span class="nf">AddEnvironmentVariables</span><span class="p">();</span> +<span class="c1">// E assim por diante...</span> + +<span class="n">IConfigurationRoot</span> <span class="n">configuration</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span></code></pre></figure> + +<p>A ordem desses provedores é muito importante porque se trata de um sistema em camadas. Dê uma olhada na imagem a seguir:</p> + +<p><img src="/img/configuracao-dotnet/configuration-providers-layers.webp" alt="Uma imagem que mostra a importância da ordem dos provedores de configuração" /></p> + +<p>Uma visão geral da importância da ordem dos provedores de configuração.<br /> +<a href="https://www.manning.com/books/asp-net-core-in-action-second-edition">ASP.NET Core in Action, Second Edition (Permissão concedida pelo autor Andrew Lock)</a></p> + +<p>Imagine que <code class="language-plaintext highlighter-rouge">sharedsettings.json</code> tenha um valor para todos os valores de configuração usados pelo aplicativo. O <code class="language-plaintext highlighter-rouge">appsettings.json</code> e as <code class="language-plaintext highlighter-rouge">Variáveis de ambiente</code> contêm um subconjunto desses valores. Como o provedor para as variáveis de ambiente foi adicionado por último, ele tem a prioridade mais alta. Portanto, se você quiser recuperar um valor de configuração chamado <code class="language-plaintext highlighter-rouge">ApiKey</code>, o sistema examinará primeiro as variáveis de ambiente. Se ele existir, será retornado, mesmo que outros provedores também contenham um valor para <code class="language-plaintext highlighter-rouge">ApiKey</code>. No entanto, se as variáveis de ambiente não contiverem um valor para <code class="language-plaintext highlighter-rouge">ApiKey</code>, ele passará para o provedor que foi adicionado antes dele e pesquisará lá, e assim por diante.</p> + +<h4 id="os-valores-default">Os valores default</h4> + +<p>Talvez você esteja um pouco confuso neste ponto. Eu certamente estava quando aprendi sobre o <code class="language-plaintext highlighter-rouge">IConfigurationBuilder</code> e a importância dessas camadas. Por quê? Bem, percebi que estava usando o <code class="language-plaintext highlighter-rouge">IConfiguration</code> em muitos projetos, mas nunca tinha ouvido falar do <code class="language-plaintext highlighter-rouge">IConfigurationBuilder</code> antes. Então, como eu poderia estar usando o <code class="language-plaintext highlighter-rouge">IConfiguration</code>?</p> + +<p>Isso funciona porque, se você trabalhar em um aplicativo .NET que <a href="https://learn.microsoft.com/dotnet/core/extensions/generic-host?WT.mc_id=DT-MVP-5005050">usa um Host</a>, ele definirá todo um sistema de configuração para você por padrão! Por exemplo, <a href="https://learn.microsoft.com/aspnet/core/fundamentals/host/generic-host?WT.mc_id=DT-MVP-5005050">projetos ASP.NET Core</a> e <a href="https://learn.microsoft.com/dotnet/core/extensions/workers?WT.mc_id=DT-MVP-5005050#worker-service-template">workers services</a> usam um <code class="language-plaintext highlighter-rouge">Host</code>, portanto, na maioria dos projetos, isso será feito para você! Agora vamos dar uma olhada em como isso funciona.</p> + +<p>Em um aplicativo ASP.NET Core padrão, o seguinte é configurado para você.</p> + +<table> + <thead> + <tr> + <th>Provedor</th> + <th>Exemplo</th> + <th>Notas</th> + </tr> + </thead> + <tbody> + <tr> + <td>appsettings.json</td> + <td>{ “Key”: “default value” }</td> + <td> </td> + </tr> + <tr> + <td>appsettings.{ENVIRONMENT}.json</td> + <td>{ “Key”: “development value” }</td> + <td> </td> + </tr> + <tr> + <td>user secrets (desenvolvimento)</td> + <td>dotnet user-secrets set “key” “development value”</td> + <td>Também pode ser definido em IDEs. Mais sobre isso posteriormente.</td> + </tr> + <tr> + <td>Variáveis de ambiente</td> + <td>Powershell: setx key “valor do ambiente” <br /> Bash: export key=‘valor do ambiente’</td> + <td>Também pode ser definido em IDEs. Muito popular em implantações do Docker/Kubernetes.</td> + </tr> + <tr> + <td>Argumentos da linha de comando</td> + <td>dotnet run –key “important value”</td> + <td>Também pode ser definido nos IDEs.</td> + </tr> + </tbody> +</table> + +<p>O item no topo tem a prioridade mais baixa. Portanto, se você chamar <code class="language-plaintext highlighter-rouge">Configuration[“key”]</code>, obterá como resultado <code class="language-plaintext highlighter-rouge">important value</code>, mesmo que o User Secrets também forneça um valor.</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>O provedor User secrets só é adicionado quando o <em>Environment</em> é definido como <em>Development</em>. Os ambientes serão tratados a seguir. Os user secrets são tratados em profundidade <a href="#user-secrets">mais adiante</a>.</p> + + </div> +</div> + +<p>O Visual Studio (e outros IDEs, como o JetBrains Rider) oferecem suporte à configuração de variáveis de ambiente/argumentos de linha de comando em seu IDE quando você acessa as propriedades do projeto. No entanto, aconselho <strong>contra</strong> o uso disso durante o desenvolvimento. Eu nunca uso variáveis de ambiente ou argumentos de linha de comando durante o desenvolvimento porque é mais difícil editá-los do que simplesmente abrir um arquivo. Armazená-los em <code class="language-plaintext highlighter-rouge">appsettings.Development.json</code> (que será abordado a seguir) é mais conveniente para você e seus colegas.</p> + +<h4 id="configuração-e-ambientes">Configuração e Ambientes</h4> + +<p>O provedor <em>appsettings.{<strong>ENVIRONMENT</strong>}.json</em> é um pouco diferente dos outros provedores. Isso ocorre porque ele depende do <a href="https://learn.microsoft.com/aspnet/core/fundamentals/environments?WT.mc_id=DT-MVP-5005050">ambiente do aplicativo</a>. O ambiente atual do aplicativo é lido a partir do valor da variável de ambiente <code class="language-plaintext highlighter-rouge">DOTNET_ENVIRONMENT</code> ou <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code>. Se o seu projeto não for um projeto ASP.NET Core, o aplicativo verificará apenas <code class="language-plaintext highlighter-rouge">DOTNET_ENVIRONMENT</code>. Os projetos ASP.NET Core retornam para <code class="language-plaintext highlighter-rouge">DOTNET_ENVIRONMENT</code> quando <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code> não existe.</p> + +<p>O ambiente será considerado como <code class="language-plaintext highlighter-rouge">Production</code> quando essas variáveis de ambiente não existirem.</p> + +<p>Quando você cria um projeto ASP.NET Core, um arquivo chamado <code class="language-plaintext highlighter-rouge">launchSettings.json</code> será criado na pasta <code class="language-plaintext highlighter-rouge">Properties</code>. Aqui, você pode ver que a variável de ambiente <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code> está definida como <code class="language-plaintext highlighter-rouge">Development</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ + // Muitos outros detalhes foram removidos desse arquivo para fins de brevidade + “$schema": “https://json.schemastore.org/launchsettings.json”, + “profiles": { + “MY_PROJECT": { + “commandName": “MY_PROJECT”, + “applicationUrl": “https://localhost:7237;http://localhost:5292”, + “environmentVariables": { + “ASPNETCORE_ENVIRONMENT": “Development” + } + } + } +} + +</code></pre></div></div> + +<p>O resultado do sistema de configuração trabalhando em conjunto com o ambiente do aplicativo resulta em um recurso muito poderoso, pois permite que você crie arquivos de configuração diferentes para cada ambiente.</p> + +<p>Você pode armazenar valores padrão em <code class="language-plaintext highlighter-rouge">appsettings.json</code> e substituí-los em <code class="language-plaintext highlighter-rouge">appsettings.Development.json</code>, <code class="language-plaintext highlighter-rouge">appsettings.Test.json</code>, <code class="language-plaintext highlighter-rouge">appsettings.Staging.json</code> e <code class="language-plaintext highlighter-rouge">appsettings.Production.json</code>.</p> + +<p>Por exemplo, digamos que você tenha terminado o novo design de uma página de checkout de uma loja virtual. Ele ainda precisa ser testado e revisado por outras pessoas em um ambiente de teste, mas ainda não deve entrar em produção. Esse parece ser um caso de uso perfeito para feature flags! Você poderia criar um feature flag chamado <code class="language-plaintext highlighter-rouge">EnableNewCheckoutUI</code> e defini-lo como <code class="language-plaintext highlighter-rouge">false</code> em <code class="language-plaintext highlighter-rouge">appsettings.json</code> como o valor padrão. Em seguida, você pode substituir esses valores em <code class="language-plaintext highlighter-rouge">appsettings.Development.json</code> e <code class="language-plaintext highlighter-rouge">appsettings.Test.json</code> para que eles sejam ativados somente lá:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// appsettings.json +{ + “FeatureFlags": { + “EnableNewCheckoutUI": false + } +} + +// appsettings.Development.json e appsettings.Test.json +{ + “FeatureFlags": { + “EnableNewCheckoutUI": true + } +} + +</code></pre></div></div> + +<p>Você não está limitado aos nomes de ambiente mencionados acima; eles são apenas os padrões que o .NET usa. Se quiser usar um nome diferente, configure a variável de ambiente <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code> com o nome de sua escolha e crie um arquivo <code class="language-plaintext highlighter-rouge">appsettings.ENV_NAME.json</code> correspondente. A única outra coisa que você precisa fazer é garantir que o ambiente em que você executa seu aplicativo tenha <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code> ou <code class="language-plaintext highlighter-rouge">DOTNET_ENVIRONMENT</code> definido com o valor correto.</p> + +<h3 id="tratando-a-configuração-como-código">Tratando a Configuração Como Código</h3> + +<p>Anteriormente, elogiei o sistema de configuração do .NET e o <code class="language-plaintext highlighter-rouge">IConfiguration</code> por serem flexíveis e ricos em recursos. Falei sobre seu suporte a dados estruturados e sobre a recuperação de valores de uma hierarquia de configuração mais profunda. Mas você sabia que pode fazer muito mais com dados estruturados?</p> + +<p>Digamos que nosso aplicativo se comunique com uma API externa usando HTTP. Para isso, precisamos de um <code class="language-plaintext highlighter-rouge">ApiUrl</code>, <code class="language-plaintext highlighter-rouge">ApiKey</code> e talvez queiramos configurar um <code class="language-plaintext highlighter-rouge">TimeoutInMilliseconds</code>. Do ponto de vista do código, talvez queiramos armazenar esses valores em uma classe (ou <code class="language-plaintext highlighter-rouge">record</code>) porque eles pertencem um ao outro:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="k">class</span> <span class="nc">ExternalApiSettings</span> +<span class="p">{</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiKey</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">int</span> <span class="n">TimeoutInMilliseconds</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Em seguida, teríamos uma classe <code class="language-plaintext highlighter-rouge">ExternalApiClient</code> que usa a configuração e a classe que acabamos de criar:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="k">class</span> <span class="nc">ExternalApiClient</span> +<span class="p">{</span> + <span class="k">private</span> <span class="k">readonly</span> <span class="n">IConfiguration</span> <span class="n">_configuration</span><span class="p">;</span> + + <span class="k">public</span> <span class="nf">Foo</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">CallExternalApi</span><span class="p">()</span> + <span class="p">{</span> + <span class="n">IConfigurationSection</span> <span class="n">externalApiSettingsSection</span> <span class="p">=</span> <span class="n">_configuration</span><span class="p">.</span><span class="nf">GetRequiredSection</span><span class="p">(</span><span class="err">“</span><span class="n">ExternalApiSettings</span><span class="err">”</span><span class="p">);</span> + + <span class="c1">// Método 1 (Get&lt;TType&gt;() obtém os valores dessa seção e os mapeia em uma nova instância da classe fornecida)</span> + <span class="n">ExternalApiSettings</span> <span class="n">settings1</span> <span class="p">=</span> <span class="n">externalApiSettingsSection</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">ExternalApiSettings</span><span class="p">&gt;();</span> + + <span class="c1">// Método 2 (Bind() espera uma instância existente de um tipo e mapeará os valores para essa instância existente)</span> + <span class="n">ExternalApiSettings</span> <span class="n">settings2</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> + <span class="n">_configuration</span><span class="p">.</span><span class="nf">GetRequiredSection</span><span class="p">(</span><span class="err">“</span><span class="n">ExternalApiSettings</span><span class="err">”</span><span class="p">).</span><span class="nf">Bind</span><span class="p">(</span><span class="n">settings2</span><span class="p">);</span> + + <span class="c1">// Faça algo com essas configurações aqui...</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Isso parece bem legal, certo? Em vez de realizar 3 chamadas para obter cada propriedade de configuração relacionada à API individualmente, podemos mapeá-las em um objeto fortemente tipado. Agora podemos tratar nossa configuração como código! Poderíamos até criar métodos em nossa classe <code class="language-plaintext highlighter-rouge">ExternalApiSettings</code> para torná-la ainda mais poderosa!</p> + +<p>No entanto, há algumas desvantagens importantes nessa abordagem.</p> + +<h4 id="desvantagens">Desvantagens</h4> + +<ul> + <li>A primeira desvantagem é que o nosso <code class="language-plaintext highlighter-rouge">ExternalApiClient</code> requer uma instância de <code class="language-plaintext highlighter-rouge">IConfiguration</code> para funcionar. Essa é uma dependência muito grande e um grande desperdício, considerando que ele usa apenas 3 valores de configuração! Além disso, essa classe agora pode acessar outros valores de configuração, como uma string de conexão a um banco de dados, configurações de registro, feature flags etc., mesmo que não precise dessas informações.</li> + <li>A segunda desvantagem é que essa classe está violando o princípio da responsabilidade única. Ela não é responsável apenas por chamar a API externa, mas também por interagir com o sistema de configuração para poder chamar essa API externa.</li> + <li>Como essa classe interage diretamente com o sistema de configuração, ela depende de sua estrutura e, portanto, está fortemente acoplada. Qualquer alteração na seção de configuração <code class="language-plaintext highlighter-rouge">ExternalApiSettings</code> (como o nome ou os nomes de seus filhos) causaria problemas em tempo de execução.</li> +</ul> + +<p>Então, o que podemos fazer em relação a isso? Reescrevê-la em Rust 🦀? Não, podemos usar o options pattern!</p> + +<h2 id="options-pattern">Options Pattern</h2> + +<p>O <em>options pattern</em> (“padrão de opções”) permite que você faça um uso ainda melhor do sistema de configuração do .NET 🚀! Ele permite a você desacoplar seu aplicativo do sistema de configuração e adiciona muitos recursos poderosos a esse sistema, como:</p> + +<ul> + <li>Injeção de dependência</li> + <li>Validação</li> + <li>Diferentes tempos de vida de configuração</li> + <li>E muito mais!</li> +</ul> + +<p>Para começar a usar o options pattern de forma eficaz, é necessário criar classes/records das suas seções de configuração. Já fizemos isso no exemplo anterior, portanto, vamos continuar com ele:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="k">class</span> <span class="nc">ExternalApiSettings</span> +<span class="p">{</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiKey</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">int</span> <span class="n">TimeoutInMilliseconds</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="injeção-de-dependência">Injeção de dependência</h3> + +<p>O options pattern funciona muito bem com a injeção de dependência! Para isso, basta registrar sua classe/record de opções na coleção de serviços. Dependendo do seu projeto, o ponto de entrada para isso pode ser o método <code class="language-plaintext highlighter-rouge">Startup.cs -&gt; ConfigureServices(IServiceCollection services)</code> ou em algum lugar em seu <code class="language-plaintext highlighter-rouge">Program.cs</code>.</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">ExternalApiSettings</span><span class="p">&gt;(</span><span class="n">configuration</span><span class="p">);</span> <span class="c1">// Passe em uma instância existente de IConfiguration</span></code></pre></figure> + +<p>Isso adicionará uma instância de <code class="language-plaintext highlighter-rouge">IOptions&lt;ExternalApiSettings&gt;</code> ao seu contêiner de injeção de dependência. Para ver os benefícios dessa abordagem, vamos dar uma olhada em como poderíamos melhorar nosso <code class="language-plaintext highlighter-rouge">ExternalApiClient</code> de antes:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="k">class</span> <span class="nc">ExternalApiClient</span> +<span class="p">{</span> + <span class="k">private</span> <span class="k">readonly</span> <span class="n">ExternalApiSettings</span> <span class="n">_externalApiSettings</span><span class="p">;</span> + + <span class="k">public</span> <span class="nf">ExternalApiClient</span><span class="p">(</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">ExternalApiSettings</span><span class="p">&gt;</span> <span class="n">options</span><span class="p">)</span> + <span class="p">{</span> + <span class="c1">// Importante: o padrão Options é “preguiçoso”. Isso significa que as opções são mapeadas somente quando você as solicita chamando .Value!</span> + <span class="c1">// Isso é feito apenas uma vez, portanto, você não precisa se preocupar com o desempenho.</span> + <span class="n">_externalApiSettings</span> <span class="p">=</span> <span class="n">options</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">CallExternalApi</span><span class="p">()</span> + <span class="p">{</span> + <span class="c1">// Faz algo com essas configurações aqui...</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Isso eliminou todas as desvantagens de antes! Nosso <code class="language-plaintext highlighter-rouge">ExternalApiClient</code> não tem mais uma dependência do <code class="language-plaintext highlighter-rouge">IConfiguration</code> e não está mais acoplado ao sistema de configuração. Ele também não precisa mais se preocupar com a estrutura do sistema de configuração.</p> + +<p>Você pode argumentar que temos uma dependência indireta do sistema de configuração por causa da chamada <code class="language-plaintext highlighter-rouge">.Configure&lt;&gt;(configuration)</code> de antes, mas você não é obrigado a usar esse método para configurar suas opções. Você pode criar uma instância de <code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code> usando <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Options.Options.Create()</code> se precisar criar uma instância manualmente, e pode passar quaisquer dados que desejar. Você pode até mesmo criar opções com base em outras dependências usando o método <code class="language-plaintext highlighter-rouge">Configure&lt;TDep1,...&gt;()</code> do <code class="language-plaintext highlighter-rouge">OptionsBuilder</code>, que será discutido a seguir.</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Talvez você se pergunte por que precisamos envolver nossa classe de configurações com uma interface <code class="language-plaintext highlighter-rouge">IOptions&lt;&gt;</code>. Isso ocorre porque ela permite que você use alguns recursos mais avançados sobre os quais falaremos a seguir.</p> + + </div> +</div> + +<h3 id="validação">Validação</h3> + +<p>Meu recurso favorito do sistema de configuração do .NET é a facilidade com que é possível validar sua configuração! Acredito que essa seja uma das partes mais importantes de qualquer aplicativo, e não vejo que ela seja usada com frequência. O motivo pelo qual acredito que a configuração é uma das partes mais importantes de qualquer aplicativo é porque ela abriga definições muito importantes do seu aplicativo.</p> + +<p>Um aplicativo configurado incorretamente pode ter resultados desastrosos. Na pior das hipóteses, imagine que o seu ambiente de teste esteja se conectando acidentalmente aos recursos do ambiente de produção. Agora imagine que você testaria uma função de exclusão em massa e acidentalmente excluiria todos os seus dados de produção. Isso seria um desastre!</p> + +<p>É por isso que queremos validar nossa configuração. Se o nosso aplicativo for iniciado com um sistema de configuração incorreto, queremos sair imediatamente.</p> + +<p>Então, como configuramos isso? É mais fácil do que você imagina. Eu gosto de usar <a href="https://www.infoworld.com/article/3543302/how-to-use-data-annotations-in-c-sharp.html">Data Annotations</a> para minhas validações de opções quando não preciso de regras de validação complexas, portanto, vamos modificar nosso <code class="language-plaintext highlighter-rouge">ExternalApiSettings</code> desta forma:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="k">class</span> <span class="nc">ExternalApiSettings</span> +<span class="p">{</span> + <span class="p">[</span><span class="n">Required</span><span class="p">]</span> <span class="c1">// Se o ApiUrl não estiver definido, a configuração é inválida</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + + <span class="p">[</span><span class="n">Required</span><span class="p">]</span> <span class="c1">// Se a ApiKey não for definida, a configuração será inválida</span> + <span class="k">public</span> <span class="kt">string</span> <span class="n">ApiKey</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + + <span class="p">[</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="n">_000_00</span><span class="p">)]</span> <span class="c1">// Se o TimeoutInMilliseconds não for definido (o padrão é 0) ou for maior que 100000, a configuração será inválida</span> + <span class="k">public</span> <span class="kt">int</span> <span class="n">TimeoutInMilliseconds</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Agora, vamos alterar a forma como registramos essas opções no contêiner de injeção de dependência:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">services</span> + <span class="p">.</span><span class="n">AddOptions</span><span class="p">&lt;</span><span class="n">ExternalApiSettings</span><span class="p">&gt;()</span> + <span class="p">.</span><span class="nf">BindConfiguration</span><span class="p">(</span><span class="err">“</span><span class="n">ExternalApiSettings</span><span class="err">”</span><span class="p">)</span> + <span class="p">.</span><span class="nf">ValidateDataAnnotations</span><span class="p">()</span> <span class="c1">// Lança uma OptionsValidationException se a configuração for inválida</span> + <span class="p">.</span><span class="nf">ValidateOnStart</span><span class="p">();</span> <span class="c1">// Altamente recomendado!</span></code></pre></figure> + +<p>Em vez de usar <code class="language-plaintext highlighter-rouge">Configure&lt;TType&gt;(configuration)</code>, agora usamos <code class="language-plaintext highlighter-rouge">AddOptions&lt;TType&gt;()</code>. Isso retorna um <code class="language-plaintext highlighter-rouge">OptionsBuilder</code> e nos permite usar alguns métodos poderosos.</p> + +<ol> + <li>O primeiro que usamos é o <code class="language-plaintext highlighter-rouge">BindConfiguration()</code>. Esse método recupera o <code class="language-plaintext highlighter-rouge">IConfiguration</code> do contêiner de injeção de dependência e vincula a seção que passamos. Isso é útil porque não precisamos mais passar manualmente nossa configuração.</li> + <li>Em seguida, chamamos <code class="language-plaintext highlighter-rouge">ValidateDataAnnotations()</code>. Isso validará nossa seção de configuração com base nos atributos que definimos nas propriedades. + <ol> + <li>Observação: você precisa instalar o pacote nuget <a href="https://www.nuget.org/packages/Microsoft.Extensions.Options.DataAnnotations">Microsoft.Extensions.Options.DataAnnotations</a> se não tiver esse método disponível.</li> + </ol> + </li> + <li>Por fim, chamamos <code class="language-plaintext highlighter-rouge">ValidateOnStart()</code>. Essa etapa é <strong>muito</strong> importante! Por padrão, suas opções só serão validadas quando você chamar <code class="language-plaintext highlighter-rouge">.Value</code> nelas em algum lugar, como em uma classe onde elas são injetadas. Isso significa que seu aplicativo NÃO lançaria um erro e sairia na inicialização quando sua configuração fosse inválida! O <code class="language-plaintext highlighter-rouge">ValidateOnStart()</code> validará sua configuração depois que o aplicativo terminar de se inicializar.</li> +</ol> + +<p>Você também pode validar seu código de muitas outras maneiras. Você pode usar a interface <code class="language-plaintext highlighter-rouge">IValidatableOptions&lt;&gt;</code> para implementar uma lógica de validação complexa ou pode chamar <code class="language-plaintext highlighter-rouge">Validate(Func&lt;TOptions, bool&gt; validation)</code> para escrever uma lógica de validação personalizada como parte do construtor de opções. Você pode até mesmo <a href="https://andrewlock.net/adding-validation-to-strongly-typed-configuration-objects-using-flentvalidation/">integrá-lo ao FluentValidation</a>!</p> + +<h3 id="tempos-de-vida-da-configuração">Tempos de vida da configuração</h3> + +<p>Por fim, gostaria de falar sobre o tempo de vida do padrão Options. O <code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code> é um singleton. Isso significa que, se um de seus <a href="https://learn.microsoft.com/dotnet/core/extensions/configuration-providers?WT.mc_id=DT-MVP-5005050#json-configuration-provider">provedores de configuração for atualizado em tempo de execução</a>, as opções não serão atualizadas. Isso ocorre porque as opções são mapeadas apenas uma vez quando você chama <code class="language-plaintext highlighter-rouge">.Value</code> sobre elas.</p> + +<p>Isso pode ser considerado positivo, pois significa que seu aplicativo não mudará repentinamente de comportamento quando a configuração for alterada. No entanto, você também pode dizer que isso é ruim porque talvez não queira ter que fazer deploy ou reiniciar o aplicativo quando alterar a configuração. Nesse caso, é melhor usar <code class="language-plaintext highlighter-rouge">IOptionsSnapshot&lt;T&gt;</code> ou <code class="language-plaintext highlighter-rouge">IOptionsMonitor&lt;T&gt;</code>.</p> + +<p><img src="/img/configuracao-dotnet/options-lifetimes.webp" alt="Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor" /></p> + +<p>Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor</p> + +<h4 id="ioptionssnapshot">IOptionsSnapshot</h4> + +<p>Em vez de injetar <code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code> em uma de suas classes, você pode injetar <code class="language-plaintext highlighter-rouge">IOptionsSnapshot&lt;T&gt;</code>. Isso recarregará esse tipo específico de opções a cada <a href="https://learn.microsoft.com/dotnet/core/extensions/dependency-injection?WT.mc_id=DT-MVP-5005050#scoped">scope</a>. Um escopo no .NET é um termo abstrato. Um escopo pode ser uma solicitação HTTP, por exemplo. Portanto, para cada solicitação HTTP, ele recarregaria as opções e elas permaneceriam consistentes para toda a solicitação. Isso significa que, se você alterar sua configuração, ela só será atualizada em uma nova solicitação.</p> + +<div class="callout callout-warning"> + <div class="callout-title"> + <span class="callout-icon">⚠️</span> + Aviso + </div> + <div class="callout-content"> + +<p>Usar <code class="language-plaintext highlighter-rouge">IOptionsSnapshot&lt;T&gt;</code> pode causar <a href="https://github.com/dotnet/runtime/issues/53793">desempenho ruim.</a></p> + + </div> +</div> + +<h4 id="ioptionsmonitor">IOptionsMonitor</h4> + +<p>O <code class="language-plaintext highlighter-rouge">IOptionsMonitor&lt;T&gt;</code> não funciona com escopos. Em vez disso, você precisa chamar <code class="language-plaintext highlighter-rouge">.CurrentValue</code> (em vez de <code class="language-plaintext highlighter-rouge">.Value</code>) para recuperar a versão atual. No entanto, é preciso ter cuidado com a forma como você acessa a sua configuração! Imagine um cenário em que sua configuração é alterada no meio de uma solicitação HTTP. Chamar <code class="language-plaintext highlighter-rouge">.CurrentValue</code> no início e no final de uma solicitação resultaria em valores diferentes, o que cria um risco de sincronização. Você pode registrar uma chamada de retorno usando <code class="language-plaintext highlighter-rouge">OnChange()</code> para ser notificado sobre esses eventos.</p> + +<p>Essa interface é mais útil em um cenário de trabalho em segundo plano que é instanciado apenas uma vez, mas que se beneficiaria da capacidade de lidar com alterações de configuração.</p> + +<h2 id="gerenciamento-de-segredos-durante-o-desenvolvimento">Gerenciamento de segredos durante o desenvolvimento</h2> + +<p>Se você vai tirar alguma conclusão dEste post, que seja a seguinte:</p> + +<div class="callout callout-error"> + <div class="callout-title"> + <span class="callout-icon">❌</span> + Importante + </div> + <div class="callout-content"> + +<p>Nunca armazene segredos em seu repositório git! Considere o uso de uma ferramenta de verificação de código como <a href="https://docs.github.com/en/enterprise-cloud@latest/get-started/learning-about-github/about-github-advanced-security">GitHub Advanced Security</a>, <a href="https://azure.microsoft.com/products/devops/github-advanced-security?WT.mc_id=DT-MVP-5005050">GitHub Advanced Security for Azure DevOps</a> ou <a href="https://www.gitguardian.com/">GitGuardian</a> para evitar que segredos sejam vazados.</p> + + </div> +</div> + +<p>Se você armazenar segredos em seu repositório git e o repositório for comprometido, seus segredos também serão comprometidos. Acho que não preciso explicar por que isso é ruim. Então, como podemos evitar que isso aconteça com o .NET?</p> + +<p>Usando o provedor de configuração de user secrets (segredos de usuário).</p> + +<h3 id="o-provedor-de-configuração-de-user-secrets">O provedor de configuração de user secrets</h3> + +<p>Mencionei o provedor de configuração de user secrets <a href="#os-valores-default">anteriormente</a>. Esse provedor de configuração foi criado para desenvolvimento local <em>somente</em>. Ele permite que você armazene segredos em seu computador local sem precisar se preocupar com o risco de eles serem versionados no repositório git, pois são armazenados em um local diferente:</p> + +<ul> + <li>Windows: <code class="language-plaintext highlighter-rouge">%APPDATA%\Microsoft\UserSecrets\&lt;user_secrets_id&gt;\secrets.json</code></li> + <li>Mac e Linux: <code class="language-plaintext highlighter-rouge">~/.microsoft/usersecrets/&lt;user_secrets_id&gt;/secrets.json</code></li> +</ul> + +<p>Esse arquivo é muito semelhante ao provedor <code class="language-plaintext highlighter-rouge">appsettings.json</code>. Basta inserir JSON nele e você poderá acessá-lo com o sistema de configuração do .NET. Quando seu aplicativo for iniciado e sua variável de ambiente <code class="language-plaintext highlighter-rouge">ASPNETCORE_ENVIRONMENT</code> ou <code class="language-plaintext highlighter-rouge">DOTNET_ENVIRONMENT</code> estiver definida como <code class="language-plaintext highlighter-rouge">Development</code>, ele carregará automaticamente o provedor de configuração de user secrets <em>desde que seu projeto esteja configurado para usar esse provedor</em>.</p> + +<div class="callout callout-warning"> + <div class="callout-title"> + <span class="callout-icon">⚠️</span> + Aviso + </div> + <div class="callout-content"> + +<p>Mesmo que esse provedor tenha o nome “secret”, esteja avisado! O conteúdo do arquivo <code class="language-plaintext highlighter-rouge">secrets.json</code> não é criptografado. Se você trabalha em um ambiente em que armazenar segredos na própria máquina é arriscado, considere usar <a href="#using-the-key-vault-during-local-development">um armazenamento de segredos externo como o Azure KeyVault durante o desenvolvimento</a>.</p> + + </div> +</div> + +<p>Esse provedor de configuração pode ser acessado usando a CLI ou seu IDE favorito. Talvez seja necessário instalar o pacote <a href="https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets">Microsoft.Extensions.Configuration.UserSecrets</a> caso você não use um <code class="language-plaintext highlighter-rouge">Host</code> ou tenha uma configuração personalizada.</p> + +<h3 id="usando-user-secrets">Usando User Secrets</h3> + +<h4 id="cli">CLI</h4> + +<p>Você pode usar o <code class="language-plaintext highlighter-rouge">dotnet</code> cli para interagir com user-secrets abrindo um terminal no diretório em que reside o <code class="language-plaintext highlighter-rouge">*.csproj</code> do seu projeto.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Necessário apenas quando as user-secrets ainda não foram inicializadas +dotnet user-secrets init + +# Você pode usar dados estruturados usando dois pontos (:) para separar as chaves +dotnet user-secrets set “ConnectionStrings:Database” “Data Source=...” +dotnet user-secrets set “AdminPassword” “hunter2” +# Outros comandos como “list”, “remove” e “clear” também estão disponíveis + +</code></pre></div></div> + +<h4 id="visual-studio">Visual Studio</h4> + +<p>Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione <code class="language-plaintext highlighter-rouge">Manage User Secrets</code>. Um arquivo <code class="language-plaintext highlighter-rouge">secrets.json</code> será aberto, no qual você poderá inserir seus segredos.</p> + +<h4 id="visual-studio-code">Visual Studio Code</h4> + +<p>Instale a extensão <a href="https://marketplace.visualstudio.com/items?itemName=adrianwilczynski.user-secrets">.NET Core User Secrets Visual Studio Code</a>. Em seguida, você pode clicar com o botão direito do mouse em um arquivo <code class="language-plaintext highlighter-rouge">*.csproj</code> e selecionar <code class="language-plaintext highlighter-rouge">Manage User Secrets</code>. Um arquivo <code class="language-plaintext highlighter-rouge">secrets.json</code> será aberto, no qual você poderá inserir seus segredos.</p> + +<h4 id="jetbrains-rider">JetBrains Rider</h4> + +<p>Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione <code class="language-plaintext highlighter-rouge">Tools</code> &gt; <code class="language-plaintext highlighter-rouge">Manage User Secrets</code>. Um arquivo <code class="language-plaintext highlighter-rouge">secrets.json</code> será aberto, no qual você poderá inserir seus segredos.</p> + +<h3 id="configurando-um-projeto-que-usa-user-secrets">Configurando um projeto que usa user-secrets</h3> + +<p>Uma desvantagem de usar segredos de usuário durante o desenvolvimento é que, se o seu projeto exigir alguns segredos para ser executado, será necessário executar algumas etapas de configuração após a clonagem do projeto. Tenho duas recomendações para lidar com isso:</p> + +<ul> + <li>Você pode criar um script que recupere os segredos do seu local de armazenamento de segredos e, em seguida, armazene-os em user-secrets, canalizando esses valores para <code class="language-plaintext highlighter-rouge">dotnet user-secrets set</code>. Agora você só precisa executar esse script uma vez após clonar o projeto e pronto!</li> + <li>Como alternativa, recomendo atualizar seu <code class="language-plaintext highlighter-rouge">README.MD</code> incluindo instruções de configuração que informem ao usuário quais user-secrets devem ser definidos e de onde obter esses valores. Sinta-se à vontade para criar um link para Este post se quiser explicar o que são user-secrets 😉.</li> +</ul> + +<h2 id="meu-modelo-para-gerenciamento-de-configuração">Meu modelo para gerenciamento de configuração</h2> + +<p>Agora que abordamos os conceitos básicos e o uso avançado do sistema de configuração do .NET e como incorporar o gerenciamento de segredos locais, gostaria de mostrar minha “configuração” para o gerenciamento de configuração em um projeto .NET. Quando crio um novo projeto .NET, uso a seguinte configuração:</p> + +<h3 id="appsettingsjson">appsettings.json</h3> + +<p>O sistema de configuração do .NET permite que você seja muito flexível com todos os diferentes provedores. Isso é ótimo, mas também pode causar confusão quando seu aplicativo estiver usando valores de configuração que você não esperava ou quando não conseguir descobrir de onde vem um valor de configuração específico.</p> + +<div class="callout callout-tip"> + <div class="callout-title"> + <span class="callout-icon">💡</span> + Dica + </div> + <div class="callout-content"> + +<p>Use o método <code class="language-plaintext highlighter-rouge">IConfigurationRoot.GetDebugView()</code> quando estiver tendo problemas com os valores de configuração. Para fazer isso, obtenha uma instância <code class="language-plaintext highlighter-rouge">IConfiguration</code>, converta-a em <code class="language-plaintext highlighter-rouge">IConfigurationRoot</code> e inspecione o resultado de <code class="language-plaintext highlighter-rouge">GetDebugView()</code>.</p> + +<p>Para obter mais informações, consulte o <a href="https://andrewlock.net/debugging-configuration-values-in-aspnetcore/#exposing-the-debug-view-in-your-application">fantástico post de Andrew Lock</a> sobre isso.</p> + + </div> +</div> + +<p>Eu uso <code class="language-plaintext highlighter-rouge">appsettings.json</code> para armazenar um modelo de todos os valores de configuração que meu projeto usa e de onde os valores são recuperados. Esse arquivo também pode conter valores reais quando o arquivo <code class="language-plaintext highlighter-rouge">appsettings.json</code> é o único provedor para esse valor de configuração. Gosto muito dessa configuração porque ela me permite ver todos os valores de configuração que meu projeto usa em um só lugar.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ + “Logging": { + “LogLevel": { + “Default” (Padrão): “Informações”, + “Microsoft.AspNetCore": “Warning” + } + }, + + “ConnectionStrings": { + “Database”: “&lt;from-azure-keyvault&gt;” // O Azure Key Vault será discutido na próxima seção + }, + + “ExternalApiSettings": { + “ApiUrl": “&lt;from-environment-variables&gt;”, + “ApiKey": “&lt;from-azure-keyvault&gt;”, + “TimeoutInMilliseconds": 5000 + } +} + +</code></pre></div></div> + +<h3 id="appsettingsdevelopmentjson">appsettings.Development.json</h3> + +<p>A seguir, temos o arquivo <code class="language-plaintext highlighter-rouge">appsettings.Development.json</code>. Esse arquivo pode conter valores de configuração que substituem os valores do <code class="language-plaintext highlighter-rouge">appsettings.json</code>, como configurações de registro. Além disso, esse arquivo <strong>nunca</strong> deve conter segredos! Em vez disso, ele faz referência ao provedor de configuração de user secrets. Isso torna menos provável que as pessoas insiram segredos nesse arquivo, pois elas são levadas a usar o provedor de configuração de user secrets.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ + “Logging": { + “LogLevel": { + “Default”: “Debug”, // As configurações de log são 100% de preferência pessoal, fique à vontade para usar o que quiser + “Microsoft.AspNetCore": “Warning” + } + }, + + “ConnectionStrings": { + “Database”: “&lt;from-user-secrets&gt;” // Cada desenvolvedor pode usar sua própria string de conexão de banco de dados local + }, + + “ExternalApiSettings": { + “ApiUrl": “dev.externalapi.example.com”, + “ApiKey": “&lt;from-user-secrets&gt;” + // Não forneço um valor para TimeoutInMilliseconds porque não tenho problemas com o valor de appsettings.json + } +} + +</code></pre></div></div> + +<h3 id="user-secrets">User Secrets</h3> + +<p>Por fim, uso o provedor de configuração user secrets para armazenar segredos locais <em>e</em> substituir a configuração não secreta que não quero enviar para o repositório git, como alterar as configurações de log no caso de precisar me aprofundar em um bug. Se eu alterasse esses valores de configuração no arquivo <code class="language-plaintext highlighter-rouge">appsettings.Development.json</code>, teria que me lembrar de reverter essas alterações antes de fazer o commit do meu código. Ao usar o provedor de configuração de user secrets, não preciso me preocupar com isso.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ + “Logging": { + “LogLevel": { + “Microsoft.AspNetCore": “Information” + } + }, + + “ConnectionStrings": { + “Database”: “Data Source=...” + }, + + “ExternalApiSettings": { + “ApiKey": “abc123def456ghi7” + } +} + +</code></pre></div></div> + +<div class="callout callout-question"> + <div class="callout-title"> + <span class="callout-icon">❓</span> + Pergunta + </div> + <div class="callout-content"> + +<p>Como é a sua configuração? O que você acha da minha? Deixe sua opinião nos comentários abaixo!</p> + + </div> +</div> + +<h2 id="usando-o-azure-para-armazenar-a-configuração">Usando o Azure para armazenar a configuração</h2> + +<p>Agora que sabemos como armazenar a configuração e os segredos localmente, é hora de falar sobre a execução de seus aplicativos em ambientes reais. Há muitas maneiras diferentes de configurar a configuração e o gerenciamento de segredos para ambientes não locais, portanto, tudo se resume a conhecer as vantagens e desvantagens dessas abordagens e escolher o que funciona melhor para você. Neste post, você aprenderá a usar o Azure para armazenar sua configuração e seus segredos com segurança.</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Embora esta seção seja sobre o Azure, os conceitos também se aplicam a outros provedores de nuvem. O equivalente do Azure App Configuration no AWS é chamado de <a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html">AWS Systems Manager Parameter Store</a>. O Azure Key Vault tem um equivalente no AWS chamado <a href="https://aws.amazon.com/secrets-manager/">AWS Secrets Manager</a> e o equivalente do Google é chamado <a href="https://cloud.google.com/secret-manager">Google Secret Manager</a>.</p> + +<p>Se quiser hospedar seu gerenciamento de segredos por conta própria, dê uma olhada em <a href="https://www.vaultproject.io/">Hashicorp Vault</a>.</p> + + + </div> +</div> + +<h3 id="armazenamento-de-segredos-no-azure-key-vault">Armazenamento de segredos no Azure Key Vault</h3> + +<p>Como dissemos anteriormente, não é possível usar o provedor de configuração User Secrets em ambientes não locais. Portanto, temos que encontrar uma maneira diferente de armazenar nossos segredos quando estivermos implantando nossos aplicativos. O <a href="https://azure.microsoft.com/services/key-vault/?WT.mc_id=DT-MVP-5005050">Azure Key Vault</a> é um ótimo serviço para armazenar segredos, chaves e certificados de forma barata, fácil e segura.</p> + +<p>No início deste post, mencionei que é possível conectar o sistema de configuração do .NET à nuvem, o que <a href="https://learn.microsoft.com/aspnet/core/security/key-vault-configuration?WT.mc_id=DT-MVP-5005050">é possível com o Key Vault</a>. Essa é uma ótima abordagem para o gerenciamento de segredos porque você pode simplesmente tratar o Key Vault como um provedor de configuração e não precisa mais fazer coisas complicadas no pipeline de lançamento.</p> + +<p>Para adicioná-lo como um provedor de configuração, instale os pacotes <a href="https://www.nuget.org/packages/Azure.Extensions.AspNetCore.Configuration.Secrets">Azure.Extensions.AspNetCore.Configuration.Secrets</a> e <a href="https://www.nuget.org/packages/Azure.Identity">Azure.Identity</a>. Em seguida, você só precisará adicionar algumas linhas de código ao seu <code class="language-plaintext highlighter-rouge">Program.cs</code> quando criar uma API mínima, por exemplo:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">using</span> <span class="nn">Azure.Identity</span><span class="p">;</span> + +<span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span> + +<span class="n">builder</span><span class="p">.</span><span class="n">Host</span><span class="p">.</span><span class="nf">ConfigureAppConfiguration</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span> <span class="p">=&gt;</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(!</span><span class="n">context</span><span class="p">.</span><span class="n">HostingEnvironment</span><span class="p">.</span><span class="nf">IsDevelopment</span><span class="p">())</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">keyVaultUrl</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="err">“</span><span class="n">KeyVaultUrl</span><span class="err">”</span><span class="p">));</span> + <span class="n">config</span><span class="p">.</span><span class="nf">AddAzureKeyVault</span><span class="p">(</span><span class="n">keyVaultUrl</span><span class="p">,</span> <span class="k">new</span> <span class="nf">ManagedIdentityCredential</span><span class="p">());</span> <span class="c1">// Há outras opções de credenciais disponíveis. As Managed Identities serão abordadas em breve!</span> + <span class="p">}</span> +<span class="p">});</span></code></pre></figure> + +<p>O Key Vault agora é adicionado como o provedor final e, portanto, tem <a href="#os-valores-default">a prioridade mais alta</a>. Portanto, mesmo que outros provedores tenham um valor configurado para um segredo, o Key Vault será usado em seu lugar!</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Os segredos estruturados devem ser armazenados no Key Vault com 2 traços (<code class="language-plaintext highlighter-rouge">--</code>) em vez de 2 sublinhados ou dois pontos devido a limitações de nomenclatura. Por exemplo, <code class="language-plaintext highlighter-rouge">ExternalApiSettings--ApiKey</code> em vez de <code class="language-plaintext highlighter-rouge">ExternalApiSettings:ApiKey</code> ou <code class="language-plaintext highlighter-rouge">ExternalApiSettings__ApiKey</code>.</p> + + </div> +</div> + +<h4 id="usando-o-key-vault-durante-o-desenvolvimento-local">Usando o Key Vault durante o desenvolvimento local</h4> + +<p>Anteriormente neste post, mencionei brevemente que você pode estar em um cenário em que não é possível armazenar segredos em seu computador por motivos de segurança, por exemplo. Nesse caso, usar o Key Vault durante o desenvolvimento local resolveria esse problema. Você pode pegar o exemplo de código da seção anterior e modificá-lo da seguinte forma:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">using</span> <span class="nn">Azure.Identity</span><span class="p">;</span> + +<span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span> + +<span class="n">builder</span><span class="p">.</span><span class="n">Host</span><span class="p">.</span><span class="nf">ConfigureAppConfiguration</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span> <span class="p">=&gt;</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">keyVaultUrl</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="n">GetValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="err">“</span><span class="n">KeyVaultUrl</span><span class="err">”</span><span class="p">));</span> + <span class="n">config</span><span class="p">.</span><span class="nf">AddAzureKeyVault</span><span class="p">(</span><span class="n">keyVaultUrl</span><span class="p">,</span> <span class="k">new</span> <span class="nf">DefaultAzureCredential</span><span class="p">());</span> <span class="c1">// Esses tipos de credenciais serão abordados a seguir!</span> +<span class="p">});</span></code></pre></figure> + +<p>Agora, seu aplicativo sempre se conectará ao Key Vault, mesmo durante o desenvolvimento. O resultado é que você não precisa mais armazenar segredos em seu computador, pois eles são sempre recuperados do Key Vault. Uma desvantagem dessa abordagem é que você sempre precisa de uma conexão com a Internet para se conectar à nuvem!</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Devido aos benefícios que essa solução traz, considere o uso dessa abordagem mesmo em cenários em que o armazenamento de segredos localmente seria aceitável. Um grande benefício dessa abordagem é que você pode simplesmente clonar um projeto e, desde que tenha as permissões corretas, pode executá-lo sem precisar configurar nenhum segredo em sua máquina, pois eles são simplesmente recuperados da nuvem!</p> + + </div> +</div> + +<h3 id="conectando-se-ao-azure-com-identidades-gerenciadas">Conectando-se ao Azure com identidades gerenciadas</h3> + +<p>Nos exemplos de código anteriores, você viu alguns tipos estranhos de credenciais: <code class="language-plaintext highlighter-rouge">ManagedIdentityCredential</code> e <code class="language-plaintext highlighter-rouge">DefaultAzureCredential</code>. Antes de discutirmos isso, considere o seguinte:</p> + +<p>Queremos nos conectar a um provedor de armazenamento seguro de segredos para obter segredos com os quais executar nosso aplicativo. Para nos conectarmos a esse provedor, precisaremos passar algumas credenciais para que o provedor possa autorizar nossa solicitação. <strong>Mas essas credenciais também são segredos, então onde as armazenamos</strong>? Poderíamos armazená-las em outro provedor de configuração, mas isso não anula todo o propósito de ter um provedor secreto? Se essas credenciais vazassem, alguém poderia acessar nossos segredos de qualquer forma! <strong>Para resumir, estamos lidando com um problema de galinha e ovo</strong>.</p> + +<p>Felizmente, algumas pessoas inteligentes da Microsoft descobriram isso! Para o desenvolvimento local, você pode usar o <code class="language-plaintext highlighter-rouge">DefaultAzureCredential</code> para se comunicar com os serviços do Azure. Esse tipo de credencial tentará se autenticar <a href="https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?WT.mc_id=DT-MVP-5005050#defaultazurecredential">usando vários métodos</a>, como a conta da Microsoft com a qual você está conectado ao seu IDE, suas credenciais da CLI do Azure (<code class="language-plaintext highlighter-rouge">az</code>) e muito mais.</p> + +<p><img src="/img/configuracao-dotnet/azure-identity.webp" alt="Uma visão geral de como a Identidade do Azure funciona" /></p> + +<p>A Identidade do Azure usa vários métodos para autenticar a conta do Azure de um desenvolvedor.</p> + +<p>Para ambientes de produção, a Microsoft recomenda <a href="https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview">Managed Identities</a> para <a href="https://learn.microsoft.com/dotnet/azure/sdk/authentication/?WT.mc_id=DT-MVP-5005050">autenticar com recursos do Azure</a>. As identidades gerenciadas são um recurso do Microsoft Entra (anteriormente conhecido como Azure Active Directory) que permite criar uma identidade para seu aplicativo no Microsoft Entra. Essa identidade pode ser usada para autenticação em outros serviços do Azure, como o Key Vault. A vantagem dessa abordagem é que você não precisa mais armazenar nenhuma credencial no aplicativo, pois a identidade é gerenciada pelo Azure AD.</p> + +<p><img src="/img/configuracao-dotnet/azure-managed-identities.webp" alt="Um diagrama de como as Identidades Gerenciadas funcionam.&lt;/br&gt;" /></p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>As Managed Identities podem ser bastante difíceis de entender em um primeiro momento. Dê uma olhada na parte inferior do post para ver alguns links com mais informações sobre Managed Identities.</p> + + </div> +</div> + +<h3 id="armazenamento-da-configuração-na-configuração-de-aplicativo-do-azure">Armazenamento da configuração na Configuração de Aplicativo do Azure</h3> + +<p>Por último, mas não menos importante, quero falar sobre a oferta de nuvem do Azure para gerenciamento de <em>configuração</em>. Enquanto o Azure Key Vault abrange o gerenciamento de segredos, o <a href="https://azure.microsoft.com/products/app-configuration/?WT.mc_id=DT-MVP-5005050">Azure App configuration</a> é uma oferta de SaaS que o ajudará a gerenciar sua configuração. Esses dois serviços funcionam muito bem juntos quando você vincula o Azure App Configuration ao Azure Key Vault. Se optar por usar esse serviço, você só precisará adicionar o <a href="https://learn.microsoft.com/azure/azure-app-configuration/quickstart-aspnet-core-app?WT.mc_id=DT-MVP-5005050">Azure App Configuration como um provedor de configuração</a> e, em seguida, poderá usar o sistema de configuração do .NET para acessar todas as suas configurações E segredos da nuvem!</p> + +<p>Ele também tem muitos outros recursos, portanto, vale a pena dar uma olhada!</p> + +<div class="callout callout-info"> + <div class="callout-title"> + <span class="callout-icon">ℹ️</span> + Info + </div> + <div class="callout-content"> + +<p>Considere a possibilidade de usar <a href="https://learn.microsoft.com/pt-br/azure/azure-app-configuration/howto-integrate-azure-managed-service-identity?WT.mc_id=DT-MVP-5005050&amp;pivots=framework-dotnet">identidades gerenciadas para acessar a Configuração de Aplicativos</a> para aumentar a segurança!</p> + + + </div> +</div> + +<h2 id="finalizando">Finalizando</h2> + +<p>Você chegou até o fim! Este post levou muito tempo para ser escrito, e estou feliz por finalmente ter sido concluído! Abaixo, você encontrará mais informações se quiser saber mais sobre os conceitos que abordei neste post. Se você tiver alguma dúvida, fique à vontade para deixar um comentário abaixo. Se quiser saber quando e onde darei a versão de palestra deste post, confira minha página <a href="https://stenbrinke.nl/speaking">Speaking</a>.</p> + +<h3 id="links-para-a-demo">Links para a demo</h3> + +<p>Mencionei que o post é um complemento de uma de minhas sessões. Essa sessão contém várias demonstrações que mostram os conceitos discutidos nEste post. Você pode encontrar as demonstrações <a href="https://github.com/sander1095/secure-secret-storage-with-asp-net-core/">aqui</a>.</p> + +<h3 id="links-para-a-documentação-oficial">Links para a documentação oficial</h3> + +<ul> + <li><a href="https://learn.microsoft.com/dotnet/core/extensions/configuration?WT.mc_id=DT-MVP-5005050">Configuração</a></li> + <li><a href="https://learn.microsoft.com/aspnet/core/fundamentals/configuration?WT.mc_id=DT-MVP-5005050">Configuração (especificações do ASP.NET Core)</a></li> + <li><a href="https://learn.microsoft.com/aspnet/core/fundamentals/configuration/options?WT.mc_id=DT-MVP-5005050">options pattern</a></li> + <li><a href="https://docs.microsoft.com/aspnet/core/security/app-secrets">user secrets</a></li> + <li><a href="https://azure.microsoft.com/en-us/products/key-vault/?WT.mc_id=DT-MVP-5005050">Azure KeyVault</a></li> + <li><a href="https://devblogs.microsoft.com/devops/demystifying-service-principals-managed-identities/?WT.mc_id=DT-MVP-5005050">Mais informações sobre Managed Identities</a></li> +</ul> + +<hr /> + +<p>Você gostou deste post? <a href="https://ko-fi.com/stenbrinke"><img src="https://stenbrinke.nl/images/kofi_button_blue.webp" alt="Faça uma doção para o autor original em https://ko-fi.com/stenbrinke.nl" /></a></p> + +<h2 id="carlos-de-volta">Carlos de volta</h2> + +<p>Carlos Schults de volta aqui. Espero que tenham gostado bastante do post, e sugiro que o coloquem nos favoritos para ser um recurso útil de consulta toda vez que surgir alguma dúvida referente ao gerenciamento de secrets e configuração.</p> + +<p>Agradeço a Sander ten Brinke, autor do artigo original, que gentilmente me autorizou a traduzí-lo. O <a href="https://stenbrinke.nl/">blog dele</a> é fantástico, tem muitos artigos extremamente bem escritos sobre diversos tópicos relacionados a .NET. Para quem sabe inglês, recomendo fortemente a visita.</p> + +<p>Gostaria de agradecer também a <a href="https://andrewlock.net/about/">Andrew Lock</a>, o autor do livro <a href="https://www.manning.com/books/asp-net-core-in-action-third-edition">ASP.NET Core in Action</a>, por ter concedido autorização para reproduzir uma imagem de seu livro.</p> + +<p>A você que leu o artigo - todo ou apenas uma parte — deixo também um agradecimento e um pedido: me dê seu feedback. É extremamente importante saber se as pessoas gostam desse tipo de conteúdo, pois me motiva a continuar produzindo.</p> + +<p>Até a próxima!</p> + + Tue, 23 Jul 2024 00:00:00 +0000 + https://carlosschults.net/pt/configuracao-dotnet + https://carlosschults.net/pt/configuracao-dotnet + + csharp + + dotnet + + configuracao + + traducoes + + tutorial + + + + + + C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg" alt="" /> +<em>NOTA: Eu originalmente escrevi esse post para o blog da empresa Stackify. Você pode <a href="https://stackify.com/c-regex-how-regular-expressions-work-in-c-with-examples/">ler o artigo original, em inglês, no site deles</a>.</em></p> + +<p>A manipulação de texto é uma das tarefas mais comuns na programação, sendo que praticamente todas as principais linguagens de programação oferecem suporte a regex (expressão regular) por meio de suas bibliotecas padrão. O C# não é exceção, portanto, hoje trazemos a você um guia de regex do C#.</p> + +<p>Você aprenderá o que são expressões regulares, por que você deseja usá-las e como começar de uma maneira abrangente e acessível. Dessa forma, você poderá começar a usar expressões regulares para resolver problemas reais o mais rápido possível.</p> + +<p>Prepare-se para sua jornada de aprendizado de regex, que começa agora!</p> + +<h2 id="o-que-é-regex">O Que é Regex?</h2> +<p>Uma expressão regular (também chamadas de regex, abreviação para <em>regular expression</em>) é uma expressão que contém um ou vários caracteres que expressam um determinado padrão no texto. Se isso parecer um pouco vago, um exemplo vai ajudar. Considere uma data no seguinte formato:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>28-JUL-2023 +</code></pre></div></div> + +<p>Usando um regex, podemos expressar esse formato da seguinte forma:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0-9]{2}-[A-Z]{3}-[0-9]{4} +</code></pre></div></div> + +<p>Observe que a expressão regular acima expressa um padrão com:</p> + +<ul> + <li>dois dígitos numéricos seguidos de um hífen</li> + <li>três letras maiúsculas seguidas de um hífen</li> + <li>mais quatro números</li> +</ul> + +<p>Você saberá mais sobre o significado de cada parte de uma regex em um minuto. Por enquanto, lembre-se de que a regex acima não <em>sabe</em> nada sobre datas. Acontece que conseguimos criar uma expressão regular que corresponde ao padrão ou ao formato da data. Todos os itens a seguir correspondem a essa regex, mesmo que não sejam datas válidas:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>32-ABC-7894 +30-FEV-1978 +00-AAA-9999 +</code></pre></div></div> + +<h2 id="existe-regex-no-c">Existe Regex no C#?</h2> + +<p>Sim, é claro. Mas isso não vem da própria linguagem. Em vez disso, o suporte a regex vem da <a href="https://learn.microsoft.com/pt-br/dotnet/standard/class-library-overview">.NET’s BCL (Base Class Library),</a> que é essencialmente a biblioteca padrão do C#.</p> + +<h2 id="por-que-usar-regex-em-c">Por Que Usar Regex em C#?</h2> + +<p>Como você viu, regex é algo a ser usado para expressar um padrão que pode corresponder a um determinado texto.</p> + +<p>Na prática, todos os usos de regex em C# ou em outras linguagens se resumem a três motivos: validação, manipulação e extração.</p> + +<h3 id="validação">Validação</h3> + +<p>Um caso de uso incrivelmente comum para regex é a validação de dados. Por exemplo, digamos que você tenha um formulário da Web e queira garantir que um determinado campo só aceite entradas em um formato específico. Como resolver isso? O Regex vem em seu socorro.</p> + +<h3 id="manipulação">Manipulação</h3> + +<p>Às vezes, você precisa alterar informações dentro do texto. Vamos voltar ao exemplo anterior. Imagine que, por motivos de compliance, você precise remover todos os números de telefone desse corpo de texto e substituí-los pela palavra “REDACTED”. Novamente, as expressões regulares seriam perfeitas para essa situação.</p> + +<p>É interessante notar que as linguagens de programação não são as únicas a usar expressões regulares para resolver problemas. Até mesmo os editores de texto, como o Notepad++, oferecem recursos de localizar e substituir com o auxílio de expressões regulares.</p> + +<h2 id="extração">Extração</h2> + +<p>Digamos que você tenha uma quantidade considerável de texto. Esse texto contém números de telefone que você precisa extrair. Você conhece o formato desses números e o fato de que eles estão dentro do texto, mas esse é o limite do seu conhecimento.</p> + +<p>Como você faria para extrair essas informações? Um regex C# bem feito certamente seria útil nessa situação.</p> + +<h2 id="como-usar-o-regex-em-c-primeiros-passos-na-prática">Como usar o Regex em C#: Primeiros passos na prática</h2> + +<p>O C# é uma <a href="https://stackify.com/oop-concepts-c-sharp/">linguagem orientada a objetos</a>, portanto, não é de surpreender que você use uma classe para trabalhar com regex no C#. Mais especificamente, a classe de que estou falando é apropriadamente chamada de <code class="language-plaintext highlighter-rouge">Regex</code> e reside no namespace <code class="language-plaintext highlighter-rouge">System.Text.RegularExpressions</code>.</p> + +<h3 id="c-regex-um-exemplo-de-validação">C# Regex: Um exemplo de validação</h3> + +<p>Vamos começar com um exemplo simples de validação sobre como usar regex para validar se várias cadeias de caracteres correspondem a um determinado padrão. A primeira etapa é adicionar a seguinte instrução <strong>using</strong> ao seu código:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">using</span> <span class="nn">System.Text.RegularExpressions</span><span class="p">;</span></code></pre></figure> + +<p>Agora, vamos criar um array de strings e preenchê-la com alguns valores:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">candidates</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> +<span class="p">{</span> + <span class="s">"28-JUL-2023"</span><span class="p">,</span> + <span class="s">"whatever"</span><span class="p">,</span> + <span class="s">"89-ABC-1234"</span><span class="p">,</span> + <span class="s">"11-JUN-2022"</span><span class="p">,</span> + <span class="s">"11-JUN-2022, uma data e outras coisas"</span><span class="p">,</span> + <span class="s">"Isso certamente não é uma data"</span> +<span class="p">};</span></code></pre></figure> + +<p>Por fim, percorreremos os valores e usaremos o método estático <code class="language-plaintext highlighter-rouge">IsMatch</code> da classe <code class="language-plaintext highlighter-rouge">Regex</code> para verificar qual das cadeias de caracteres corresponde ao padrão desejado:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">"[0-9]{2}-[A-Z]{3}-[0-9]{4}"</span><span class="p">;</span> +<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">c</span> <span class="k">in</span> <span class="n">candidates</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">Regex</span><span class="p">.</span><span class="nf">IsMatch</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">pattern</span><span class="p">))</span> + <span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"A string '</span><span class="p">{</span><span class="n">c</span><span class="p">}</span><span class="s">' corresponde ao padrão '</span><span class="p">{</span><span class="n">pattern</span><span class="p">}</span><span class="s">'"</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Antes de prosseguir, vamos detalhar o padrão parte por parte:</p> + +<ul> + <li><strong>[0-9]{2}</strong>: A primeira parte significa “Corresponde exatamente a dois caracteres, que devem ser dígitos de 0 a 9”.</li> + <li><strong>-</strong>: Esse caractere corresponde exatamente a um hífen.</li> + <li><strong>[A-Z]{3}</strong>: Aqui, a expressão diz: “Vamos corresponder exatamente a três caracteres, que podem ser qualquer uma das letras de A a Z.”</li> + <li><strong>-</strong>: Isso corresponde a outro hífen</li> + <li><strong>[0-9]{4}</strong>: Isso já deve ser fácil de entender, certo? Exatamente quatro números.</li> +</ul> + +<p>Agora, vamos executar o código e ver o que obtemos:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A string '28-JUL-2023' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +A string '89-ABC-1234' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +A cadeia de caracteres '11-JUN-2022' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +A cadeia de caracteres '11-JUN-2022, a date plus other stuff' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}' +</code></pre></div></div> + +<p>Os três primeiros resultados provavelmente não o surpreenderam. Eu até incluí algo que não é uma data, mas que corresponde ao padrão que estamos usando para realmente enfatizar que as expressões regulares tratam de padrões e formas e não de qualquer semântica dos dados que estamos procurando.</p> + +<p>Entretanto, o quarto resultado pode tê-lo surpreendido. O texto de fato começa com dados que correspondem ao padrão que estamos procurando, mas depois tem algum texto adicional. E mesmo assim, essa string correspondeu!</p> + +<p>A explicação para esse comportamento é simples e está explicada para nós no <a href="https://learn.microsoft.com/pt-br/dotnet/api/system.text.regularexpressions.regex.ismatch?view=net-7.0#system-text-regularexpressions-regex-ismatch(system-string-system-string)">summary</a> do método <code class="language-plaintext highlighter-rouge">IsMatch</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Indica se a expressão regular especificada encontra uma correspondência na cadeia de caracteres de entrada especificada. +</code></pre></div></div> + +<p>A expressão regular de fato encontrou uma correspondência na string de entrada especificada (“11-JUN-2022, a date plus other stuff”), e é por isso que foi considerada uma correspondência.</p> + +<p>Mas e se quiséssemos uma correspondência exata? Nesse caso, seria necessário alterar o padrão, adicionando um acento circunflexo (“^”) ao início do padrão e um cifrão (“$”) ao seu final. Em outras palavras, veja como o padrão deve ficar agora:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">"^[0-9]{2}-[A-Z]{3}-[0-9]{4}$"</span><span class="p">;</span></code></pre></figure> + +<p>Se executarmos o código agora, ele exibirá apenas as cadeias de caracteres que são uma correspondência exata com o padrão:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A string '28-JUL-2023' corresponde ao padrão '^[0-9]{2}-[A-Z]{3}-[0-9]{4} +</code></pre></div></div> + +<h3 id="c-regex-um-exemplo-de-manipulação">C# Regex: Um exemplo de manipulação</h3> + +<p>Considere que você tem um texto que contém dados sensíveis do usuário. Devido a questões de privacidade/compliance, você deseja excluir esses dados. Felizmente para você, é muito fácil usar uma regex para isso.</p> + +<p>Vamos começar criando uma matriz contendo nomes e números de telefone de pessoas fictícias:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">contacts</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> + <span class="s">"Emily Johnson,(555) 123-4567"</span><span class="p">,</span> + <span class="s">"Benjamin Williams,(555) 987-6543"</span><span class="p">,</span> + <span class="s">"Olivia Davis,(555) 222-3333"</span><span class="p">,</span> + <span class="s">"Alexander Smith,(555) 444-5555"</span><span class="p">,</span> + <span class="s">"Sophia Brown,(555) 777-8888"</span><span class="p">,</span> + <span class="s">"William Anderson,(555) 111-2222"</span><span class="p">,</span> + <span class="s">"Ava Martinez,(555) 666-7777"</span><span class="p">,</span> + <span class="s">"James Thompson,(555) 888-9999"</span><span class="p">,</span> + <span class="s">"Isabella Wilson,(555) 333-4444"</span><span class="p">,</span> + <span class="s">"Michael Taylor,(555) 777-1111"</span> +<span class="p">};</span></code></pre></figure> + +<p>Em seguida, vamos criar o padrão para corresponder aos números de telefone:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">@"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}"</span><span class="p">;</span></code></pre></figure> + +<p>O padrão acima é um pouco mais complexo do que os que usamos anteriormente, mas ainda é simples. No entanto, há alguns elementos novos:</p> + +<ul> + <li><strong>A barra invertida (\):</strong> Precisamos dela aqui para escapar dos parênteses de abertura e fechamento, que é um caractere com significado em uma expressão regular. Nesse caso, queremos de fato corresponder a um caractere “(“, portanto, precisamos escapar dele.</li> + <li><strong>O caractere \s:</strong> corresponde a um único espaço.</li> +</ul> + +<p>Por fim, vamos percorrer essa matriz e, para cada item, usar o método <code class="language-plaintext highlighter-rouge">Regex.Replace</code> para gerar uma nova string na qual o número de telefone é substituído por todos os zeros:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">contact</span> <span class="k">in</span> <span class="n">contacts</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span> + <span class="n">Regex</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="n">contact</span><span class="p">,</span> <span class="n">pattern</span><span class="p">,</span> <span class="s">"(000) 000-0000"</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Usar o método estático <code class="language-plaintext highlighter-rouge">Replace</code> é fácil. Embora ele tenha várias sobrecargas, a que usamos recebe apenas três argumentos:</p> + +<ul> + <li>a string de entrada</li> + <li>o padrão que você deseja corresponder</li> + <li>a string de substituição</li> +</ul> + +<p>Depois de executar o código, eis o resultado que obtemos:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Emily Johnson,(000) 000-0000 +Benjamin Williams,(000) 000-0000 +Olivia Davis,(000) 000-0000 +Alexander Smith,(000) 000-0000 +Sophia Brown,(000) 000-0000 +William Anderson,(000) 000-0000 +Ava Martinez,(000) 000-0000 +James Thompson,(000) 000-0000 +Isabella Wilson,(000) 000-0000 +Michael Taylor,(000) 000-0000 +</code></pre></div></div> + +<h3 id="c-regex-um-exemplo-de-extração">C# Regex: Um exemplo de extração</h3> + +<p>Para o nosso último exemplo, vamos extrair dados de uma string usando uma expressão regular. Vamos começar convertendo o array do exemplo anterior em uma única string:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">contacts</span> <span class="p">=</span> + <span class="s">"Emily Johnson+(555) 123-4567"</span> <span class="p">+</span> + <span class="s">"\nBenjamin Williams+(555) 987-6543"</span> <span class="p">+</span> + <span class="s">"\nOlivia Davis+(555) 222-3333"</span> <span class="p">+</span> + <span class="s">"\nAlexander Smith+(555) 444-5555"</span> <span class="p">+</span> + <span class="s">"\nSophia Brown+(555) 777-8888"</span> <span class="p">+</span> + <span class="s">"\nWilliam Anderson+(555) 111-2222"</span> <span class="p">+</span> + <span class="s">"\nAva Martinez+(555) 666-7777"</span> <span class="p">+</span> + <span class="s">"\nJames Thompson+(555) 888-9999"</span> <span class="p">+</span> + <span class="s">"\nIsabella Wilson+(555) 333-4444"</span> <span class="p">+</span> + <span class="s">"\nMichael Taylor+(555) 777-1111"</span><span class="p">;</span></code></pre></figure> + +<p>Em seguida, definimos o padrão novamente (o mesmo) e usamos o método estático <code class="language-plaintext highlighter-rouge">Matches</code> para obter todas as correspondências da string:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">pattern</span> <span class="p">=</span> <span class="s">@"\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}"</span><span class="p">;</span> +<span class="n">MatchCollection</span> <span class="n">matches</span> <span class="p">=</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">contacts</span><span class="p">,</span> <span class="n">pattern</span><span class="p">);</span></code></pre></figure> + +<p>A classe <code class="language-plaintext highlighter-rouge">MatchCollection</code> contém todas as cadeias de caracteres que corresponderam ao padrão que fornecemos ao método. Esse objeto é enumerável, portanto, podemos fazer um loop sobre ele com um foreach:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"Aqui estão os números de telefone extraídos:"</span><span class="p">);</span> +<span class="k">foreach</span> <span class="p">(</span><span class="n">Match</span> <span class="n">match</span> <span class="k">in</span> <span class="n">matches</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>E, finalmente, nossos resultados:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">Aqui</span> <span class="n">est</span><span class="err">ã</span><span class="n">o</span> <span class="n">os</span> <span class="n">n</span><span class="err">ú</span><span class="n">meros</span> <span class="n">de</span> <span class="n">telefone</span> <span class="n">extra</span><span class="err">í</span><span class="n">dos</span><span class="p">:</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">123</span><span class="p">-</span><span class="m">4567</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">987</span><span class="p">-</span><span class="m">6543</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">222</span><span class="p">-</span><span class="m">3333</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">444</span><span class="p">-</span><span class="m">5555</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">777</span><span class="p">-</span><span class="m">8888</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">111</span><span class="p">-</span><span class="m">2222</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">666</span><span class="p">-</span><span class="m">7777</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">888</span><span class="p">-</span><span class="m">9999</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">333</span><span class="p">-</span><span class="m">4444</span> +<span class="p">(</span><span class="m">555</span><span class="p">)</span> <span class="m">777</span><span class="p">-</span><span class="m">1111</span></code></pre></figure> + +<h2 id="c-regex-uma-ferramenta-indispensável">C# Regex: Uma Ferramenta Indispensável</h2> + +<p>Como dissemos na introdução, a manipulação de texto é um elemento básico da programação, e as expressões regulares facilitam essa tarefa. Neste guia de regex em C#, você aprendeu o que são expressões regulares, seus cenários de uso mais comuns e como começar a usar expressões regulares em C#.</p> + +<p>Antes de ir embora, algumas dicas:</p> + +<ul> + <li>Faça mais experimentos com a classe <code class="language-plaintext highlighter-rouge">Regex</code>. Ela oferece muitos recursos, e os métodos que usamos hoje têm muitas sobrecargas com recursos úteis.</li> + <li>Saiba mais e pratique a escrita de expressões regulares. <a href="https://regexr.com/">Aqui está um ótimo site</a> que você pode usar.</li> + <li>Informe-se sobre as considerações de desempenho do C# regex. Por exemplo, leia este <a href="https://learn.microsoft.com/pt-br/dotnet/standard/base-types/compilation-and-reuse-in-regular-expressions?redirectedfrom=MSDN">artigo da Microsoft sobre a compilação e a reutilização de expressões regulares</a>.</li> +</ul> + +<p>Por fim, se quiser saber mais sobre o C# em geral, o blog da Stackify está repleto de recursos úteis. Como sugestão, dê uma olhada em <a href="https://stackify.com/unit-test-frameworks-csharp/">os prós e contras dos 3 principais frameworks de teste de unidade para C#</a>, <a href="https://stackify.com/csharp-catch-all-exceptions/">como capturar exceções e localizar erros de aplicativos em C#</a> e <a href="https://stackify.com/what-is-c-reflection/">como funciona a reflexão em C#</a>.</p> + +<p>Obrigado pela leitura!</p> + + Tue, 07 May 2024 00:00:00 +0000 + https://carlosschults.net/pt/csharp-expressoes-regulares + https://carlosschults.net/pt/csharp-expressoes-regulares + + csharp + + regex + + expressoes_regulares + + tutorial + + + + + + Git Criar Branch: 4 Maneiras Diferentes + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><em>NOTA: Eu escrevi este post originalmente para o blog da Cloudbees. Você pode <a href="https://www.cloudbees.com/blog/git-create-branch">conferir o artigo original, em inglês, no site deles</a>. Eu optei por deixar os exemplos de código em inglês.</em></p> + +<p>Se você trabalha escrevendo software, posso dizer com segurança que você conhece o Git. A ferramenta criada por Linus Torvalds tornou-se sinônimo de controle de versão. E, sem dúvida, um dos melhores recursos do Git é a forma como ele elimina a dificuldade de ramificar (branch) e mesclar (merge). Há várias maneiras de criar uma branch (branch) no Git. Neste artigo, vamos analisar algumas delas. Então, a gente finaliza com uma reflexão sobre o modelo de branching do Git, e a ideia de branching em geral.</p> + +<h2 id="criando-um-branch-a-partir-de-main">Criando Um Branch A Partir de Main</h2> + +<p>Você cria branches no Git, como era de se esperar, usando o comando <code class="language-plaintext highlighter-rouge">branch</code>. Como muitos outros comandos do Git, o <code class="language-plaintext highlighter-rouge">branch</code> é muito poderoso e flexível. Além de criar branches, ele também pode ser usado para listá-las e excluí-las, e você pode personalizar ainda mais o comando empregando uma ampla lista de parâmetros. Começaremos com a primeira maneira de criar uma branch. Digamos que você queira criar uma nova pasta chamada “my-app”, entrar nela e iniciar um novo repositório Git. É exatamente assim que você faria isso:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir my-app +cd my-app +git init +</code></pre></div></div> + +<p>Agora você tem um repositório Git novo e vazio. Mas repositórios vazios são chatos. Então, que tal criar um novo arquivo markdown com “Hello World!” escrito nele?</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo Hello World! &gt; file.md +</code></pre></div></div> + +<p>Se você executar <code class="language-plaintext highlighter-rouge">git status</code>, verá uma mensagem dizendo que o arquivo não foi rastreado:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git status +On branch main +Untracked files: + (use "git add &lt;file&gt;..." to include in what will be committed) + + file.md + +nothing added to commit but untracked files present (use "git add" to track) +</code></pre></div></div> +<p><a href="https://www.cloudbees.com/blog/git-remove-untracked-files">Arquivos não rastreados não têm graça nenhuma.</a> Então, bora rastreá-los:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add file.md +</code></pre></div></div> + +<p>E, finalmente, vamos criar nosso primeiro commit:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit -m "First commit" +</code></pre></div></div> + +<p>Agora temos um repositório com uma branch, que tem exatamente um commit. Isso pode não parecer a coisa mais empolgante do mundo (porque realmente não é), mas certamente é menos entediante do que ter um repositório sem nenhum commit, certo? Agora, digamos que, por qualquer motivo, você precise alterar o conteúdo do arquivo.</p> + +<p>Mas você não está muito a fim de fazer isso. E se algo der errado e você, de alguma forma, estragar o belo e puro conteúdo do seu arquivo? (Sim, eu sei que é apenas um arquivo com “Hello World!”, mas use os maravilhosos poderes de sua imaginação e pense no arquivo como um proxy para um projeto muito mais complexo). A solução para esse dilema é, obviamente, criar uma nova branch:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch exp +</code></pre></div></div> + +<p>Portanto, agora temos uma nova branch chamada “exp”, para experimentação. Algumas pessoas que estão acostumadas a usar sistemas de controle de versão diferentes, especialmente os centralizados, poderiam dizer que as branches têm o mesmo “conteúdo”. No entanto, isso não é totalmente exato quando se trata do Git. Pense nas branches como referências que apontam para um determinado commit.</p> + +<h2 id="criando-uma-branch-a-partir-de-um-commit">Criando uma branch a partir de um commit</h2> + +<p>Suponha que, por qualquer motivo, desistimos do nosso experimento sem adicionar um único commit à nova branch. Vamos voltar para <code class="language-plaintext highlighter-rouge">main</code> e excluir a branch <code class="language-plaintext highlighter-rouge">exp</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout main +git branch -d exp +</code></pre></div></div> + +<p>Agora que voltamos a ter uma única branch, vamos adicionar alguns commits a ela, para simular o trabalho que está sendo feito:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo a new line &gt;&gt; file.md +git commit -a -m "Add a new line" +echo yet another line &gt;&gt; file.md +git commit -a -m "Add yet another line" +echo one more line &gt;&gt; file.md +git commit -a -m "Add one more line" +echo this is the last line i promise &gt;&gt; file.md +git commit -a -m "Add one last line" +</code></pre></div></div> + +<p>Imagine que, depois de fazer todo esse “trabalho”, você descobre que, por qualquer motivo, precisa voltar no tempo para quando havia apenas duas linhas no arquivo e criar novas alterações a partir de então. Mas, ao mesmo tempo, você precisa preservar o progresso que já fez. Em outras palavras, você deseja criar uma branch a partir de um commit anterior. Como você faria isso? No Git, cada commit tem um identificador exclusivo. Portanto, você pode ver isso facilmente usando o comando <code class="language-plaintext highlighter-rouge">git log</code>. Para criar uma nova branch com base em um commit específico, basta passar seu hash como parâmetro para o comando <code class="language-plaintext highlighter-rouge">branch</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch new-branch 7e4decb +</code></pre></div></div> + +<p>Além disso, na maioria das vezes, você nem precisa do hash inteiro. Apenas os primeiros cinco ou seis caracteres são suficientes.</p> + +<h2 id="criar-uma-branch-a-partir-de-uma-tag">Criar Uma Branch a Partir de Uma Tag</h2> + +<p>Se você tem um pouco mais de experiência com o Git, deve estar familiarizado com o conceito de <a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging">tags</a>. Você usa tags para indicar que um determinado commit é importante ou especial de alguma forma. Por exemplo, as tags são geralmente usadas para indicar as versões de um produto. Se você está trabalhando em seu aplicativo há algum tempo e acredita que é hora de lançar a versão 1.0, o que você normalmente faz é aumentar os números de versão sempre que necessário, commitando essas alterações e, em seguida, adicionando uma tag a esse ponto específico no tempo. Para criar uma tag, você normalmente executa algo como o seguinte:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git tag -a v1.0 -m "First major version" +</code></pre></div></div> + +<p>O parâmetro “-a” indica que essa será uma tag do tipo <em>annotated</em>. Ao contrário de uma tag <em>lightweight</em>, essa é um objeto Git completo, contendo informações como o nome e o e-mail do committer, o registro de data e hora e uma mensagem. Agora você tem uma tag, uma indicação de que esse ponto específico da história é especial e tem um nome.</p> + +<p>Legal. Você pode continuar trabalhando, como de costume, criando e enviando alterações que farão parte da versão 1.1. Até que chega um relatório de bug. Alguns clientes que foram atualizados para a versão 1.0 do produto dizem que um recurso de importação não está funcionando como pretendido.</p> + +<p>Bem, teoricamente, você poderia corrigir o bug na branch <code class="language-plaintext highlighter-rouge">main</code> e fazer o deploy da correção. Mas, nesse caso, os clientes receberiam recursos que possivelmente não foram testados e estão incompletos. Isso não é bom.</p> + +<p>Então, o que você faz?</p> + +<p>A resposta: Você cria uma nova branch a partir da tag que criou para indicar a versão principal. Você corrige o problema lá, faz o build e deploy. E, provavelmente, você deve mesclar (merge) a correção de volta à branch <code class="language-plaintext highlighter-rouge">main</code> depois, para que as próximas versões contenham a correção. Como você faria isso? Fácil:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch &lt;NAME-OF-THE-BRANCH&gt; &lt;TAG&gt; +</code></pre></div></div> + +<p>Mais especificamente, usando nosso exemplo anterior:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch fix-bug-123 v1.0 +</code></pre></div></div> + +<p>Depois disso, você pode ir para sua nova branch como de costume. Ou melhor ainda, você pode fazer tudo em uma única etapa:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout -b fix-bug-1234 v1.0 +</code></pre></div></div> + +<h2 id="criando-uma-branch-no-estado-detached-head">Criando uma branch no estado “DETACHED HEAD”</h2> + +<p>Alguma vez você já desejou voltar no tempo? Com o Git, isso é possível… pelo menos no que diz respeito aos arquivos em nosso repositório. Você pode, a qualquer momento, dar <em>checkout</em> em um commit se souber seu hash:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout &lt;SHA1&gt; +</code></pre></div></div> + +<p>Depois de executar isso, o Git mostrará uma mensagem meio esquisita:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You are in 'detached HEAD' state. You can look around, make experimental +changes and commit them, and you can discard any commits you make in this +state without impacting any branches by performing another checkout. +</code></pre></div></div> + +<p>Em tradução livre:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Você está no estado 'detached HEAD'. Você pode dar uma olhada, fazer alterações experimentais +experimentais e fazer o commit delas, e você pode descartar quaisquer commits que fizer nesse +estado sem afetar nenhuma branch, executando outro checkout. +</code></pre></div></div> + +<p>Quando você faz o <em>checkout</em> de um commit, entra em um estado especial chamado, como você pode ver, “<a href="https://www.cloudbees.com/blog/git-detached-head">detached HEAD</a>”, ou “cabeça desanexada.” Embora você possa fazer commit de alterações nesse estado, esses commits não pertencem a nenhuma branch e ficarão inacessíveis assim que você mudar de branch. Mas e se você quiser manter esses commits? A resposta, sem surpresa, é usar o comando <code class="language-plaintext highlighter-rouge">checkout</code> novamente para criar uma nova branch:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout &lt;sha1&gt; #now you're in detached head state +# do some work and stage it +git commit -m "add some work while in detached head state" +git branch new-branch-to-keep-commits +git checkout new-branch-to-keep-commits +</code></pre></div></div> + +<p>E, é claro, agora você já sabe que pode escrever as duas últimas linhas como um único comando:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout -b new-branch-to-keep-commits +</code></pre></div></div> + +<p>Muito fácil, certo?</p> + +<h2 id="só-porque-você-pode-não-significa-que-você-deva">Só porque você pode… não significa que você deva</h2> + +<p>O modelo de branch do Git é um dos seus principais atrativos. Ele transforma em uma moleza o que em outros sistemas de controle de código-fonte é um processo lento e doloroso. Pode-se dizer que o Git democratizou com sucesso a ramificação.</p> + +<p>Mas há um sério perigo. Devido ao baixo custo de trabalhar com branches no Git, alguns desenvolvedores podem cair na armadilha de trabalhar com <a href="https://rollout.io/blog/pitfalls-feature-branching/">branches de vida extremamente longa</a> ou empregar fluxos de trabalho ou modelos de branch que atrasam a integração.</p> + +<p>Nós, como setor, já passamos por isso. Fizemos isso. Não funciona. Em vez disso, adote fluxos de trabalho que utilizem branches de vida extremamente curta. Você terá uma <em>sandbox</em> segura para codificar sem medo de quebrar coisas ou desperdiçar o tempo de seus colegas de trabalho. Mas isso faz com que você se pergunte: “Como posso fazer deploy de código com recursos parcialmente concluídos?” Nesse caso, tem uma ótima alternativa: <a href="https://rollout.io/blog/ultimate-feature-flag-guide/">as ferramentas de <em>feature flag</em></a>.</p> + +<p>As branches do Git são uma ferramenta poderosa. Use-as com sabedoria e não abuse. E quando não forem suficientes, empregue entrega contínua/integração contínua juntamente com ferramentas de feature flag para que suas aplicações possam chegar ao próximo nível.</p> + + Wed, 21 Feb 2024 00:00:00 +0000 + https://carlosschults.net/pt/git-criar-branch + https://carlosschults.net/pt/git-criar-branch + + git + + tutorial + + + + + + Operador 'Join' do LINQ: Um Tutorial Completo + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1617641333/reduce-cyclomatic-complexity/reduce-cyclomatic-complexity-1038x437.jpg" alt="" /></p> + +<p><em>NOTA: Eu escrevi este artigo, originalmente, para o blog da Stackify. Caso lhe interesse, você pode <a href="https://stackify.com/the-linq-join-operator-a-complete-tutorial/">ver o artigo original, em inglês, no site deles</a>.</em></p> + +<p>Acho que a maioria dos desenvolvedores C# concordaria que o LINQ é parte essencial da experiência de escrever código com a linguagem. O LINQ oferece uma maneira fluente, intuitiva e consistente de consultar conjuntos de dados. Neste artigo, ajudaremos você a dominar o LINQ, abordando o operador <code class="language-plaintext highlighter-rouge">join</code>.</p> + +<p>Vou abrir o post com uma definição do próprio LINQ, para que estejamos todos na mesma página. Depois disso, você verá uma explicação das operações de join no LINQ. Depois, é hora de arregaçar as mangas e colocar a mão na massa com nosso guia prático sobre o operador de <code class="language-plaintext highlighter-rouge">join</code>.</p> + +<p>Vamos começar.</p> + +<h2 id="o-quê-é-linq">O Quê é LINQ?</h2> +<p><a href="https://learn.microsoft.com/pt-br/dotnet/csharp/linq/">LINQ</a> significa <em>Language Integrated Query</em>. É um recurso do C# que oferece uma sintaxe única e consistente para consultar conjuntos de dados, independentemente da origem deles. A principal vantagem do LINQ é que você pode usar a mesma sintaxe para consultar dados na memória, em um banco de dados, em arquivos XML e assim por diante.</p> + +<p>O LINQ está disponível em dois “sabores” diferentes: a sintaxe de consulta (query syntax) e a sintaxe de método (method syntax).</p> + +<p>A sintaxe de consulta utiliza palavras-chave especiais para criar uma sintaxe que é familiar a qualquer pessoa que tenha trabalhado com SQL. Aqui está um exemplo que consulta uma sequência de números, filtrando os maiores que 5:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">int</span><span class="p">[]</span> <span class="n">numbers</span> <span class="p">=</span> <span class="p">{</span> <span class="m">2</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">9</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">5</span> <span class="p">};</span> +<span class="kt">var</span> <span class="n">largerThanFive</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">num</span> <span class="k">in</span> <span class="n">numbers</span> + <span class="k">where</span> <span class="n">num</span> <span class="p">&gt;</span> <span class="m">5</span> + <span class="k">select</span> <span class="n">num</span><span class="p">;</span></code></pre></figure> + +<p>A syntaxe de método usa métodos de extensão para realizar a mesma consulta:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">int</span><span class="p">[]</span> <span class="n">numbers</span> <span class="p">=</span> <span class="p">{</span> <span class="m">2</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">4</span><span class="p">,</span> <span class="m">9</span><span class="p">,</span> <span class="m">3</span><span class="p">,</span> <span class="m">6</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="m">5</span> <span class="p">};</span> +<span class="kt">var</span> <span class="n">largerThanFive</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span> <span class="p">&gt;</span> <span class="m">5</span><span class="p">);</span></code></pre></figure> + +<h2 id="o-que-é-o-operador-linq-join">O que é o operador LINQ Join?</h2> + +<p>Ao trabalhar com dados, um cenário comum é ter duas fontes de dados que você deseja combinar com base em alguns critérios. Por exemplo, você pode ter uma tabela <code class="language-plaintext highlighter-rouge">Books</code> (Livros) e uma tabela <code class="language-plaintext highlighter-rouge">Authors</code> (Autores) em seu banco de dados, com um relacionamento de um para muitos entre elas, ou seja, um autor pode ser autor de muitos livros, mas cada livro tem apenas um autor. Se você precisar compilar uma lista de livros que contenha o nome do autor, precisará executar uma junção para fazer a correspondência entre cada linha da tabela <code class="language-plaintext highlighter-rouge">Books</code> e sua contraparte na tabela <code class="language-plaintext highlighter-rouge">Authors</code>.</p> + +<p>Uma junção no LINQ é essencialmente a mesma coisa: uma operação em que você pode mesclar duas coleções de acordo com alguns critérios que você define.</p> + +<h2 id="o-operador-linq-join-na-prática">O operador LINQ Join na prática</h2> + +<p>Os exemplos sempre deixam as coisas mais claras. Então, vamos ver como usar o operador <code class="language-plaintext highlighter-rouge">join</code> na prática.</p> + +<h3 id="iniciando-com-um-problema"><strong>Iniciando com um problema</strong></h3> + +<p>Digamos que você tenha um aplicativo de comércio eletrônico com alguns dados sobre categorias:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Electronics</td> + </tr> + <tr> + <td>4</td> + <td>Toys</td> + </tr> + <tr> + <td>5</td> + <td>Stationery</td> + </tr> + <tr> + <td>7</td> + <td>Books</td> + </tr> + <tr> + <td>10</td> + <td>Clothes</td> + </tr> + </tbody> +</table> + +<p>Agora, vamos ver alguns produtos:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Category_Id</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Amazon Kindle</td> + <td>1</td> + </tr> + <tr> + <td>2</td> + <td>Refactoring</td> + <td>7</td> + </tr> + <tr> + <td>3</td> + <td>C# in Depth</td> + <td>7</td> + </tr> + <tr> + <td>4</td> + <td>Legal Pad 50 sheets</td> + <td>5</td> + </tr> + </tbody> +</table> + +<p>Você já entendeu aonde isso vai, né? A próxima coisa que você deseja fazer é produzir uma única coleção, com a lista de produtos e os nomes das categorias às quais eles pertencem. Em outras palavras, uma visualização como esta:</p> + +<table> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Category</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>Amazon Kindle</td> + <td>Electronics</td> + </tr> + <tr> + <td>2</td> + <td>Refactoring</td> + <td>Books</td> + </tr> + <tr> + <td>3</td> + <td>C# in Depth</td> + <td>Books</td> + </tr> + <tr> + <td>4</td> + <td>Legal Pad 50 sheets</td> + <td>Stationery</td> + </tr> + </tbody> +</table> + +<h3 id="resolvendo-o-problema-executando-um-linq-inner-join">Resolvendo o problema: executando um LINQ Inner Join</h3> + +<p>Como seria essa operação no código? Em primeiro lugar, precisamos de código para representar nossas categorias e produtos. Graças ao recurso de <code class="language-plaintext highlighter-rouge">record</code> do C#, duas linhas de código são suficientes para isso:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">public</span> <span class="n">record</span> <span class="nf">Product</span><span class="p">(</span><span class="kt">int</span> <span class="n">Id</span><span class="p">,</span> <span class="kt">string</span> <span class="n">Name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">CategoryId</span><span class="p">);</span> +<span class="k">public</span> <span class="n">record</span> <span class="nf">Category</span><span class="p">(</span><span class="kt">int</span> <span class="n">Id</span><span class="p">,</span> <span class="kt">string</span> <span class="n">Name</span><span class="p">);</span></code></pre></figure> + +<p>Agora, vamos ter uma lista de cada tipo:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">categories</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Category</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Electronics"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Toys"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Stationery"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">7</span><span class="p">,</span> <span class="s">"Books"</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="s">"Clothes"</span> <span class="p">(</span><span class="n">Categoria</span> <span class="m">10</span><span class="p">,</span> <span class="s">"Roupas"</span><span class="p">)</span> +<span class="p">};</span> + +<span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Amazon Kindle"</span><span class="p">,</span> <span class="m">1</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="s">"Refactoring"</span><span class="p">,</span> <span class="m">7</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="s">"C# In Depth"</span><span class="p">,</span> <span class="m">7</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Legal Pad 50 Sheets"</span><span class="p">,</span> <span class="m">5</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Surgical Gloves"</span><span class="p">,</span> <span class="m">12</span><span class="p">)</span> +<span class="p">};</span></code></pre></figure> + +<p>Como você pode ver, a lista de produtos tem um produto adicional (luvas cirúrgicas) cujo ID de categoria não corresponde a nenhuma das categorias disponíveis. Tenha isso em mente, pois será relevante em um momento.</p> + +<p>Agora, vamos escrever o código para realizar essa união. Vou mostrar o código de uma só vez e depois eu explico:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span> + +<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">line</span> <span class="k">in</span> <span class="n">query</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">line</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>Agora, a explicação:</p> + +<p><strong>from p in products</strong> -&gt; estamos definindo a origem de uma de nossas fontes de dados</p> +<ul> + <li><strong>join c in categories</strong> -&gt; Aqui, estamos dizendo que queremos juntar a coleção anterior com esta +*on p.CategoryId equals c.Id** -&gt; Essa é a condição para a união: o CategoryId em cada produto deve corresponder ao Id de uma categoria</li> + <li><strong>select new…</strong> -&gt; Aqui, estamos aproveitando o recurso de objetos anônimos do C# para criar um novo objeto em tempo real, que tem as propriedades que desejamos</li> +</ul> + +<p>O resultado dessa consulta é um <code class="language-plaintext highlighter-rouge">IEnumerable</code> do nosso objeto anônimo. Em seguida, iteramos por cada item dessa coleção, exibindo-o no console. Este é o resultado: +`</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ Id = 1, Name = Amazon Kindle, Category = Electronics } +{ Id = 2, Name = Refactoring, Category = Books } +{ Id = 3, Name = C# In Depth, Category = Books } +{ Id = 4, Name = Legal Pad 50 Sheets, Category = Stationery } +</code></pre></div></div> + +<p>Aqueles que se lembram das aulas de banco de dados perceberão que a junção LINQ que realizamos é equivalente a uma junção interna (<em>inner join</em>) no SQL. Em outras palavras, somente os itens que têm uma correspondência são retornados. Em SQL, a consulta equivalente seria a seguinte:</p> + +<figure class="highlight"><pre><code class="language-sql" data-lang="sql"><span class="k">SELECT</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> <span class="k">c</span><span class="p">.</span><span class="n">Name</span> <span class="k">AS</span> <span class="n">Category</span> +<span class="k">FROM</span> <span class="n">products</span> <span class="k">AS</span> <span class="n">p</span> +<span class="k">JOIN</span> <span class="n">categories</span> <span class="k">AS</span> <span class="k">c</span> <span class="k">ON</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="o">=</span> <span class="k">c</span><span class="p">.</span><span class="n">Id</span></code></pre></figure> + +<h3 id="executando-uma-junção-externa-outer-join-no-linq">Executando uma junção externa (OUTER JOIN) no LINQ</h3> + +<p>E se você quisesse executar o equivalente a um <code class="language-plaintext highlighter-rouge">OUTER JOIN</code> do SQL? Ou seja, você deseja recuperar todos os produtos, mesmo aqueles que não correspondem a nenhuma categoria. Como fazer isso?</p> + +<p>Aqui está a consulta atualizada:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> <span class="k">into</span> <span class="n">joinedCategories</span> + <span class="k">from</span> <span class="n">c</span> <span class="k">in</span> <span class="n">joinedCategories</span><span class="p">.</span><span class="nf">DefaultIfEmpty</span><span class="p">()</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">?.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>Parece semelhante, mas há duas diferenças:</p> + +<ul> + <li><strong>on p.CategoryId equals c.Id into joinedCategories</strong> -&gt; aqui, depois de unir produtos com categorias, enviamos o resultado, como uma sequência agrupada, para a variável de intervalo <strong>joinedCategories</strong></li> + <li><strong>from c in joinedCategories.DefaultIfEmpty()</strong> -&gt; Em seguida, recuperamos os itens da groupedSequence, usando o método DefaultIfEmpty() para retornar o valor padrão quando nenhuma correspondência for encontrada</li> + <li><strong>Category = c?.Name</strong> -&gt; Por fim, ao atribuir o nome da categoria à propriedade Category do nosso objeto anônimo, precisamos usar o operador condicional nulo para evitar uma exceção de referência nula (já que o valor padrão de Category é nulo porque é um <a href="https://carlosschults.net/pt/tipos-valor-referencia-em-csharp/">tipo de referência</a>).</li> +</ul> + +<p>O resultado agora é diferente:</p> + +<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Amazon</span><span class="w"> </span><span class="err">Kindle</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Electronics</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Refactoring</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Books</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">C#</span><span class="w"> </span><span class="err">In</span><span class="w"> </span><span class="err">Depth</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Books</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Legal</span><span class="w"> </span><span class="err">Pad</span><span class="w"> </span><span class="mi">50</span><span class="w"> </span><span class="err">Sheets</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Stationery</span><span class="w"> </span><span class="p">}</span><span class="w"> +</span><span class="p">{</span><span class="w"> </span><span class="err">Id</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="err">Name</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">Surgical</span><span class="w"> </span><span class="err">Gloves</span><span class="p">,</span><span class="w"> </span><span class="err">Category</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="p">}</span></code></pre></figure> + +<p>Como você pode ver, o produto “Surgical Gloves” (Luvas cirúrgicas) agora aparece, mesmo que não tenha uma categoria correspondente.</p> + +<h3 id="inner-join-do-linq-com-a-condição-where">Inner Join do LINQ com a condição <code class="language-plaintext highlighter-rouge">Where</code></h3> + +<p>Realizar uma junção com uma cláusula <code class="language-plaintext highlighter-rouge">where</code> é muito fácil. Neste exemplo, realizaremos uma junção interna, filtrando apenas os produtos cujo id seja igual ou maior que 3:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">where</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span> <span class="p">&gt;=</span> <span class="m">3</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<h3 id="inner-join-do-linq-com-várias-condições">Inner Join do LINQ com várias condições</h3> + +<p>Se você quiser usar várias condições em sua junção, basta usar mais de uma cláusula where. Vamos atualizar nossa consulta mais uma vez:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span> <span class="k">equals</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span> + <span class="k">where</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span> <span class="p">&gt;=</span> <span class="m">3</span> + <span class="k">where</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">EndsWith</span><span class="p">(</span><span class="sc">'s'</span><span class="p">)</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>Aqui, estamos filtrando apenas as categorias cujos nomes terminam com a letra “s”.`</p> + +<h3 id="linq-join-com-chave-composta">LINQ Join com chave composta</h3> + +<p>Até agora, todos os nossos exemplos usaram chaves únicas para fazer a correspondência. Você também pode usar chaves compostas, ou seja, mais de um valor, para fazer a correspondência.</p> + +<p>Suponha que as nossas classes <code class="language-plaintext highlighter-rouge">Product</code> e <code class="language-plaintext highlighter-rouge">Category</code> tenham adquirido uma nova propriedade chamada <code class="language-plaintext highlighter-rouge">Status</code>, que é um enum que pode variar entre três estados: <code class="language-plaintext highlighter-rouge">Pending</code> (pendente), <code class="language-plaintext highlighter-rouge">Active</code> (ativo) e <code class="language-plaintext highlighter-rouge">Archived</code> (arquivado). Agora, a propriedade Status também precisa ser usada para a correspondência.</p> + +<p>Todos os nossos produtos estão ativos, mas nem todas as categorias:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">categories</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Category</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Electronics"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Toys"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Stationery"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Archived</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span> <span class="p">(</span><span class="m">7</span><span class="p">,</span> <span class="s">"Books"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Pending</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Category</span> <span class="p">(</span><span class="m">10</span><span class="p">,</span> <span class="s">"Clothes"</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">)</span> +<span class="p">};</span> + +<span class="kt">var</span> <span class="n">products</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Product</span><span class="p">&gt;</span> +<span class="p">{</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Amazon Kindle"</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="s">"Refactoring"</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="s">"C# In Depth"</span><span class="p">,</span> <span class="m">7</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="s">"Legal Pad 50 Sheets"</span><span class="p">,</span> <span class="m">5</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">),</span> + <span class="k">new</span> <span class="nf">Product</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="s">"Surgical Gloves"</span><span class="p">,</span> <span class="m">12</span><span class="p">,</span> <span class="n">Status</span><span class="p">.</span><span class="n">Active</span><span class="p">)</span> +<span class="p">};</span></code></pre></figure> + +<p>Fica assim a consulta atualizada:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> + <span class="k">from</span> <span class="n">p</span> <span class="k">in</span> <span class="n">products</span> + <span class="k">join</span> <span class="n">c</span> <span class="k">in</span> <span class="n">categories</span> + <span class="k">on</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">CategoryId</span><span class="p">,</span> <span class="n">Status</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Status</span> <span class="p">}</span> + <span class="k">equals</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> <span class="n">Status</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Status</span> <span class="p">}</span> + <span class="k">select</span> <span class="k">new</span> + <span class="p">{</span> + <span class="n">Id</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> + <span class="n">Category</span> <span class="p">=</span> <span class="n">c</span><span class="p">.</span><span class="n">Name</span> + <span class="p">};</span></code></pre></figure> + +<p>Não é muito mais complicado do que antes. A diferença é que, agora, usamos um objeto anônimo para realizar a comparação usando as propriedades id e status.</p> + +<p>Um único resultado é exibido a partir dessa consulta:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="p">{</span> <span class="n">Id</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">Name</span> <span class="p">=</span> <span class="n">Amazon</span> <span class="n">Kindle</span><span class="p">,</span> <span class="n">Category</span> <span class="p">=</span> <span class="n">Electronics</span> <span class="p">}</span></code></pre></figure> + +<h2 id="conclusão">Conclusão</h2> + +<p>Como vimos, o LINQ é uma parte essencial do trabalho com o C#. Você pode aproveitar o LINQ em muitos cenários diferentes, desde o trabalho com dados na memória até XML e SQL. Você pode usar o LINQ em ORMs, como <a href="https://stackify.com/entity-framework-core-nhibernate/">NHibernate e Entity Framework</a>.</p> + +<p>As equipes que desejam tornar suas experiências com LINQ ainda melhores podem usar as ferramentas à sua disposição. Por exemplo, <a href="https://stackify.com/prefix/">Stackify’s Prefix</a> e <a href="https://stackify.com/retrace-code-profiling/">Retrace</a> oferecem recursos avançados de rastreamento, criação de perfil e registro centralizado que ajudam as equipes a inspecionar seu código para encontrar oportunidades de melhorias de desempenho, o que inclui consultas LINQ.</p> + + Tue, 06 Feb 2024 00:00:00 +0000 + https://carlosschults.net/pt/operador-linq-join + https://carlosschults.net/pt/operador-linq-join + + csharp + + linq + + dotnet + + + + + + Git Bisect: Uma Introdução Para Iniciantes + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><span>Foto por <a href="https://unsplash.com/@yancymin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yancy Min</a> on <a href="https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p>Se você está tentando melhorar seu <em>git-fu</em>, uma boa dica é aprender o <code class="language-plaintext highlighter-rouge">git bisect</code>. O git tem a sua quota injusta de comandos complicados, isso é verdade. A boa notícia é que, diferente desses, o <code class="language-plaintext highlighter-rouge">git bisect</code> é bem fácil de entender e usar, pelo menos em sua forma mais básica. A notícia ainda melhor é que ele é super útil para ajudá-lo a corrigir bugs.</p> + +<h2 id="pré-requisitos">Pré-requisitos</h2> + +<p>Antes de começarmos, vamos rever alguns pré-requisitos que você precisará para acompanhar o post:</p> +<ul> + <li>Ter o git instalado em sua máquina</li> + <li>Conhecer pelo menos os comandos básicos do git</li> + <li>Ter o Node.js instalado na sua máquina (mais adiante você vai usar uma aplicação exemplo fornecida por mim, e ela é escrita em JavaScript).</li> +</ul> + +<p>Tem tudo isso? Show, vamos em frente.</p> + +<h2 id="o-que-é-o-git-bisect-por-que-você-precisa-dele">O que é o Git Bisect? Por que você precisa dele?</h2> + +<p>O <code class="language-plaintext highlighter-rouge">Git bisect</code> é um comando que permite realizar uma busca binária no seu histórico de commits. Por que fazer isso?</p> + +<p>Aqui está um cenário comum durante o desenvolvimento. Alguém relata um bug. Você vai dar uma olhada e descobre que, duas semanas atrás, a funcionalidade estava funcionando muito bem.</p> + +<p>Para corrigir o bug, seria útil descobrir quando exatamente ele foi introduzido. Uma vez que você conhece um commit que você tem certeza que é “bom” - isto é, que não contém o bug - você podia ir fazendo o <code class="language-plaintext highlighter-rouge">git checkout</code> até lá, voltando um commit de cada vez e testando para ver se a aplicação funciona.</p> + +<p>Isso iria funcionar, mas pode potencialmente levar muito tempo, dependendo do número de commits que você teria que verificar e onde está o problema. Para aqueles que se lembram das aulas de Ciência da Computação, a abordagem descrita acima é uma <a href="https://en.wikipedia.org/wiki/Linear_search">busca linear</a>, que não é a melhor maneira de procurar um valor dentro de uma lista.</p> + +<p>Sabe o que é mais eficiente? Uma pesquisa binária. Se você tem, digamos, 50 commits que você precisa verificar, e você testa o 25º e não encontra o bug, o que isso significa? Pode ignorar os primeiros 25 commits e continuar a sua pesquisa nos 25 commits posteriores. Continue o processo, sempre dividindo pela metade, e você encontrará o erro em muito menos verificações do que seria necessário com uma busca linear.</p> + +<p>Fazer isso manualmente seria muito chato. E é aí que o <code class="language-plaintext highlighter-rouge">git bisect</code> ajuda. Ele tem uma sintaxe fácil que permite que você especifique tanto um commit bom quanto um ruim, e então o git irá executar as partições binárias pra você. Em cada passo, terá de testar a sua aplicação e informar o git se esse commit é bom ou ruim. Depois, o git calcula o próximo passo, leva você até lá e o processo termina quando encontrar o culpado.</p> + +<h2 id="como-usar-o-git-bisect-na-prática">Como usar o <code class="language-plaintext highlighter-rouge">Git Bisect</code> na prática?</h2> + +<p>Hora de aprender a usar o <code class="language-plaintext highlighter-rouge">git bisect</code> na prática. Para praticar este comando, é necessário um repositório com pelo menos alguns commits, e que tenha um bug. Ia levar um tempo para você configurar um repositório assim então eu já fiz um para você - pode falar, eu sei que eu sou legal.</p> + +<h3 id="obtendo-a-aplicação-de-exemplo">Obtendo a aplicação de exemplo</h3> +<p>Basta <a href="https://github.com/carlosschults/git-bisect-intro">clonar este repositório do GitHub</a> e você está pronto para começar.</p> + +<p>O repositório contém uma aplicação JavaScript que implementa algumas das regras do <a href="https://osherove.com/tdd-kata-1">String Calculator Kata proposto por Roy Osherov</a>. Aqui está o que a aplicação deve fazer:</p> +<ul> + <li>depois de executá-la, a aplicação pedirá uma lista de números, separados por vírgula;</li> + <li>o usuário fornece os números;</li> + <li>a soma dos números é apresentada.</li> + <li>Os números maiores que 1000 são ignorados. Assim, a string “1,2,1000” deve produzir o resultado 1003, mas “1,2,1001” deve resultar em 3.</li> + <li>os números negativos não devem ser permitidos. Se informar um ou mais números negativos, a aplicação deve lançar um erro com a mensagem “Negativos não permitidos”, seguido dos números negativos que foram introduzidos.</li> +</ul> + +<p>Depois de clonar o repositório, vamos testar a aplicação. Acesse sua pasta através da linha de comandos, execute <code class="language-plaintext highlighter-rouge">node index.js</code> e, quando lhe forem pedidos os números, digite “1,2,3” e dê enter.</p> + +<p>Vixi, parece que deu ruim.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: . + at C:\repos\git-bisect-intro\index.js:11:11 + at [_onLine] [as _onLine] (node:internal/readline/interface:423:7) + at [_line] [as _line] (node:internal/readline/interface:886:18) + at [_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1264:22) + at ReadStream.onkeypress (node:internal/readline/interface:273:20) + at ReadStream.emit (node:events:513:28) + at emitKeys (node:internal/readline/utils:357:14) + at emitKeys.next (&lt;anonymous&gt;) + at ReadStream.onData (node:internal/readline/emitKeypressEvents:64:36) + at ReadStream.emit (node:events:513:28) + +Node.js v18.12.1 +</code></pre></div></div> +<p>A aplicação não funciona. Ela gera o erro “negatives not allowed” (negativos não permitidos) mesmo que nenhum negativo tenha sido inserido. Se você quiser ver a aplicação funcionando, facilitei as coisas para você: Criei uma tag chamada <code class="language-plaintext highlighter-rouge">good-commit</code> que faz referência a um ponto no histórico que é garantidamente bom. Basta ir até lá e verificar:</p> + +<p><code class="language-plaintext highlighter-rouge">git checkout good-commit</code></p> + +<p>Após executar o comando acima, é possível que você veja algumas mensagens sobre <a href="https://www.cloudbees.com/blog/git-detached-head">detached HEAD</a> e outras coisas. Simplesmente ignore-as. Execute a aplicação novamente e <em>voilá</em>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> + +<p>Massa, agora vamos testar a regra de que números maiores do que 1000 devem ser ignorados:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,1000, 1001 +The sum of the entered numbers is 1003. +</code></pre></div></div> + +<p>Show de bola. Como esperado, o número 1000 é considerado, mas 1001 é ignorado. Para um teste final, vamos verificar a proibição de números negativos:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3,-5,-4,-7 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -4, -7. +</code></pre></div></div> + +<p>Muito bom. Agora, vamos para a próxima etapa. Mas, primeiro, execute <code class="language-plaintext highlighter-rouge">git checkout main</code> para retornar ao último commit.</p> + +<h3 id="hora-de-arregaçar-as-mangas">Hora de arregaçar as mangas</h3> +<p>Para começar a usar o comando <code class="language-plaintext highlighter-rouge">git bisect</code>, você precisa iniciar uma <em>sessão bisect</em>. Para isso, basta executar o comando <code class="language-plaintext highlighter-rouge">git bisect start</code>. Em seguida, você verá a seguinte mensagem:</p> + +<p><code class="language-plaintext highlighter-rouge">status: waiting for both good and bad commits</code></p> + +<p>Agora, você precisa informar ao git sobre um commit que é conhecido por ser “bom” - ou seja, não contém o bug - e um commit que contém o bug. Vamos começar com o bom:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect good good-commit</code></p> + +<p>Como eu disse antes, criei uma tag para apontar para um commit bom conhecido para facilitar as coisas para você. Mas você não está restrito às tags quando se trata de apontar para um commit em uma sessão de bissecção. Os nomes de branches também funcionam, assim como os SHAs dos commits e praticamente todas as referências que levam a um commit.</p> + +<p>De qualquer forma, depois de executar o comando, você verá o seguinte: +<code class="language-plaintext highlighter-rouge">status: waiting for bad commit, 1 good commit known</code></p> + +<p>Agora é hora de apontar para um commit ruim. Tenho certeza de que você já adivinhou a sintaxe: <code class="language-plaintext highlighter-rouge">git bisect bad &lt;REFERENCE-TO-COMMIT&gt;</code>. Mas como o commit em que estamos - em outras palavras, a ponta do <code class="language-plaintext highlighter-rouge">main</code> - é sabidamente ruim, você pode simplesmente executar:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect bad</code></p> + +<p>Agora começa a diversão! O Git exibirá uma mensagem, mostrando o status da operação de bissecção. Ele lhe dirá quantas revisões restam para testar, quantas etapas seriam necessárias e para qual commit ele “transportou” você:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 11 revisions left to test after this (roughly 4 steps) +[e159647d4d142c410894aaf10c1e11e2208848d7] Edit to negative rule +</code></pre></div></div> + +<p>Seu trabalho agora é testar a aplicação e informar ao git se esse é um commit bom ou ruim. Então, vamos executar o <code class="language-plaintext highlighter-rouge">node index.js</code> e fornecer alguns números:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: . +</code></pre></div></div> + +<p>Cortei parte da saída para ser breve, mas de qualquer forma: a aplicação não está funcionando. Então, diga isso ao git:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect bad</code></p> + +<p>Isso o levará a um commit diferente:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 5 revisions left to test after this (roughly 3 steps) +[0b8f71999bed054d8a95d9da3be6f0c831074cd7] Update README.md - Commit 6 +</code></pre></div></div> + +<p>Vamos repetir o teste com <code class="language-plaintext highlighter-rouge">node index.js</code>:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> + +<p>Fantástico! Neste commit, a aplicação parece funcionar bem. Vamos fazer um teste diferente, usando números negativos:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enter a list of numbers separated by comma: +1,2,3,-5,-4,-10 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -4, -10. +</code></pre></div></div> + +<p>Perfeito: ele está gerando um erro, como deveria fazer nesse cenário. Portanto, execute <code class="language-plaintext highlighter-rouge">git bisect good</code> para marcar esse commit como bom.</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 2 revisions left to test after this (roughly 2 steps) +[e6413a915c7ca92871394b01a8497c8df3fc46ae] Update README.md - Commit 9 +</code></pre></div></div> + +<p>Mais um commit, mais um teste:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. +</code></pre></div></div> +<p>Vamos testar os negativos:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +10,20,-5 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5. +</code></pre></div></div> + +<p>Tudo parece bem, vamos marcá-lo como bom: +<code class="language-plaintext highlighter-rouge">git bisect good</code></p> + +<p>E o resultado:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bisecting: 0 revisions left to test after this (roughly 1 step) +[053207649aefdb09cd255567df673cadbe2e38e3] Restore README +</code></pre></div></div> + +<p>Estamos chegando perto! Vamos testar:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node index.js +Enter a list of numbers separated by comma: +1,2,3 +The sum of the entered numbers is 6. + +node index.js +Enter a list of numbers separated by comma: +1,2,3,-5,-6 +node:internal/readline/emitKeypressEvents:74 + throw err; + ^ + +Error: Negatives not allowed: -5, -6. +</code></pre></div></div> + +<p>Marcando-o como bom: <code class="language-plaintext highlighter-rouge">git bisect good</code>. E, tcharam!, aqui está nossa resposta:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e159647d4d142c410894aaf10c1e11e2208848d7 is the first bad commit +commit e159647d4d142c410894aaf10c1e11e2208848d7 +Author: Carlos Schults &lt;carlos.schults@gmail.com&gt; +Date: Tue Jan 9 08:53:47 2024 -0300 + + Edit to negative rule + + index.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +</code></pre></div></div> + +<h3 id="e-agora">E agora?</h3> +<p>Ok, agora você sabe que o commit <code class="language-plaintext highlighter-rouge">e159647d4d142c410894aaf10c1e11e2208848d7</code> foi o que introduziu o bug. O que você deve fazer agora?</p> + +<p>Em resumo, você precisa ver os detalhes desse commit, para saber quais alterações ele faz e entender o que causou o problema. Vamos usar o comando <code class="language-plaintext highlighter-rouge">git show</code> para isso:</p> + +<p><code class="language-plaintext highlighter-rouge">git show e159647d4d142c410894aaf10c1e11e2208848d7</code></p> + +<p>Esse comando exibirá várias informações sobre o commit, incluindo autor, data e mensagem. Vou reproduzir apenas a parte que me interessa, que é a diferença:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diff --git a/index.js b/index.js +index 5f351e0..4e65e0c 100644 +--- a/index.js ++++ b/index.js +@@ -6,7 +6,7 @@ const readline = require('readline').createInterface({ + readline.question('Enter a list of numbers separated by comma:\n', numbers =&gt; { + let integers = numbers.split(',').map(x =&gt; parseInt(x) || 0); + let negatives = integers.filter(x =&gt; x &lt; 0); +- if (negatives.length &gt; 0) { ++ if (negatives.length &gt;= 0) { + throw new Error(`Negatives not allowed: ${negatives.join(', ')}.`); + } +</code></pre></div></div> + +<p>E agora como uma imagem, para que você possa ver as cores:</p> + +<p><img src="/img/diff.png" alt="" /></p> + +<p>Como você pode ver, esse commit fez uma alteração na instrução <code class="language-plaintext highlighter-rouge">if</code> que testa números negativos, adicionando um sinal de igual à comparação. Dessa forma, o erro será lançado independentemente do fato de o array <code class="language-plaintext highlighter-rouge">negatives</code> ter elementos.</p> + +<p>Agora que você sabe como o erro foi introduzido, é muito fácil corrigi-lo. Para encerrar a sessão de bisect, execute <code class="language-plaintext highlighter-rouge">git bisect reset</code>. Assim, você voltará ao commit/branch onde você estava originalmente.</p> + +<h2 id="uma-observação-sobre-bom-e-ruim">Uma observação sobre “bom” e “ruim”</h2> + +<p>Leitores atentos devem ter notado que, embora esse comando use termos como “bom”, “ruim” e “bug”, não há nada que o impeça de usar o <code class="language-plaintext highlighter-rouge">git bisect</code> para descobrir o ponto no tempo em que qualquer propriedade da base de código foi alterada. Afinal de contas, o Git não tem como saber como o seu código <em>deveria</em> funcionar; foi você, o tempo todo, quem o testou.</p> + +<p>Até mesmo a <a href="https://git-scm.com/docs/git-bisect#_alternate_terms">documentação do comando</a> reconhece esse fato:</p> + +<blockquote> + <p>Às vezes, você não está procurando o commit que introduziu uma quebra, mas sim um commit que causou uma alteração entre algum outro estado “antigo” e o estado “novo”. Por exemplo, você pode estar procurando o commit que introduziu uma correção específica. Ou pode estar procurando o primeiro commit em que os nomes de arquivo do código-fonte foram finalmente convertidos para o padrão de nomenclatura da sua empresa. Ou qualquer outra coisa.</p> +</blockquote> + +<p>Nesse cenário, seria estranho usar os termos “good” e “bad”. A boa notícia é que, em vez disso, você pode usar <em>new</em> e <em>old</em>: o commit <em>novo</em> é aquele que contém a propriedade que você está procurando, e o <em>antigo</em> não contém essa propriedade.</p> + +<p>Para usar essa terminologia, basta iniciar uma sessão de bisect normalmente e, em seguida, executar <code class="language-plaintext highlighter-rouge">git bisect old &lt;COMMIT&gt;</code> para indicar o commit antigo e <code class="language-plaintext highlighter-rouge">git bisect new &lt;COMMIT&gt;</code> para indicar o novo.</p> + +<p>Lembre-se de que você pode usar good/bad ou old/new, mas não pode misturar os dois. A qualquer momento durante uma sessão, você pode executar <code class="language-plaintext highlighter-rouge">git bisect terms</code> para ser lembrado dos termos que está usando.</p> + +<p>O comando é ainda mais flexível do que isso: você pode escolher seus próprios termos! Basta iniciar uma sessão executando o seguinte:</p> + +<p><code class="language-plaintext highlighter-rouge">git bisect start --term-old &lt;term-old&gt; --term-new &lt;term-new&gt;</code></p> + +<h2 id="git-bisect-quais-os-próximos-passos">Git Bisect: Quais Os Próximos Passos?</h2> + +<p>Não são dados estatísticos, mas, a partir de minhas observações, eu diria que o <code class="language-plaintext highlighter-rouge">git bisect</code> é um comando subutilizado. O que é muito triste, considerando que o <code class="language-plaintext highlighter-rouge">git bisect</code> é a) incrivelmente útil e b) fácil de entender e usar, pelo menos em seu caso de uso mais básico.</p> + +<p>Se você já estiver familiarizado com os comandos mais comuns do git - ou seja, <code class="language-plaintext highlighter-rouge">status</code>, <code class="language-plaintext highlighter-rouge">log</code>, <code class="language-plaintext highlighter-rouge">commit</code>, <code class="language-plaintext highlighter-rouge">add</code>, <code class="language-plaintext highlighter-rouge">pull</code>, <code class="language-plaintext highlighter-rouge">push</code>, <code class="language-plaintext highlighter-rouge">checkout</code> - e quiser dar um passo adiante, aprender o <code class="language-plaintext highlighter-rouge">git bisect</code> é um ótimo ponto de partida.</p> + +<p>Então, você aprendeu o básico sobre esse comando com a introdução que escrevi. Massa demais, mas o que você deve fazer a partir daqui? Tenho algumas sugestões:</p> + +<ul> + <li>Coloque-o em prática o mais rápido possível. Mesmo que não esteja caçando bugs no momento, pense em <em>alguma</em> característica da sua aplicação e encontre o commit em que ela foi introduzida usando o <code class="language-plaintext highlighter-rouge">git bisect</code>.</li> + <li>Aprofunde-se mais no comando e procure casos de uso mais avançados. Por exemplo, é possível <a href="https://dev.to/emilysamp/how-to-run-an-automated-git-bisect-with-rspec-3dm3">automatizar o <code class="language-plaintext highlighter-rouge">git bisect</code></a> para que você não precise testar manualmente a fim de separar os commits bons dos ruins!</li> + <li>Leia a <a href="https://git-scm.com/docs/git-bisect">documentação</a> do <code class="language-plaintext highlighter-rouge">git bisect</code>. Volte a ela de tempos em tempos, e você certamente aprenderá algo novo e útil.</li> +</ul> + +<p>Isso é tudo por hoje. Espero que você tenha gostado e agradeço muito qualquer feedback. Obrigado pela leitura!</p> + + Mon, 22 Jan 2024 00:00:00 +0000 + https://carlosschults.net/pt/git-bisect-intro/ + https://carlosschults.net/pt/git-bisect-intro/ + + git + + + + + + Os Cinco Níveis de Código Legível + <p><img src="/img/levels.jpg" alt="" /></p> + +<p><span>Foto por <a href="https://unsplash.com/@greysonjoralemon?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Greyson Joralemon</a> no site <a href="https://unsplash.com/photos/w000nNe9Xq8?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></span></p> + +<p>Recentemente, tenho pensado bastante sobre a legibilidade do código. O que significa para um trecho de código ser legível? É possível definir a legibilidade de forma objetiva? Deveríamos tentar fazer isso?</p> + +<p>Essas são algumas das perguntas sobre as quais tenho pensado e, nesta publicação, apresento minhas respostas na tentativa de iniciar uma conversa sobre legibilidade.</p> + +<p>Aqui está a versão TL;DR: sim, acredito que definir objetivamente a legibilidade do código é possível e desejável e, neste artigo, sugiro um modelo para avaliar a legibilidade.</p> + +<h2 id="a-importância-de-uma-definição-de-legibilidade-de-código">A Importância de Uma Definição de Legibilidade de Código</h2> + +<p>A legibilidade sempre vai ser um pouco subjetiva e, até certo ponto, essa subjetividade é inofensiva. Entretanto, ela <em>pode</em> causar problemas em alguns cenários.</p> + +<p>Se estivermos trabalhando em uma equipe, é importante definir pelo menos algumas diretrizes objetivas em relação à legibilidade do código, e isso se deve às revisões de código (code reviews). Se o time não conseguir chegar a um consenso sobre o que é código legível, o feedback dos reviews fica parecendo arbitrário.</p> + +<p>Em resumo: as equipes precisam de convenções. Uma equipe deve ter uma visão sobre o que constitui um código bom e legível.</p> + +<h2 id="um-framework-para-pensar-sobre-a-legibilidade-do-código-níveis">Um Framework Para Pensar Sobre a Legibilidade Do Código: Níveis</h2> + +<p>Há pouco tempo, comecei a pensar na legibilidade do código em termos de níveis. Os níveis representam preocupações específicas com relação à legibilidade e são ordenados em termos de prioridade.</p> + +<p>Ou seja, o nível 1 representa as coisas mais básicas que você precisa resolver primeiro, antes de avançar para os níveis mais altos. Arrume o básico e depois vá para o avançado. Tipo a <a href="https://pt.wikipedia.org/wiki/Hierarquia_de_necessidades_de_Maslow">hierarquia de necessidades de Maslow</a>, mas para código.</p> + +<p>Você vai ver alguns exemplos de código, em C#. Mas o que vou mostrar aqui se aplica a qualquer linguagem, a menos que eu diga explicitamente o contrário.</p> + +<p>Sem mais delongas, aqui estão os cinco níveis de código legível.</p> + +<h2 id="nível-1-seu-código-faz-o-mínimo-necessário">Nível 1: Seu Código Faz O Mínimo Necessário</h2> + +<p>(Sim, nível um. Por favor, não me enche com isso de que “os programadores começam a contar no zero”).</p> + +<p>O nível 1 de código legível refere-se ao código que faz o mínimo necessário. Pense em diretrizes simples de legibilidade, como:</p> + +<ul> + <li>Escolher <a href="https://carlosschults.net/pt/como-escolher-bons-nomes/">nomes descritivos</a> para variáveis, funções, classes e assim por diante.</li> + <li>Evitar muitos níveis de indentação.</li> + <li>Manter a <a href="https://carlosschults.net/pt/reduzir-complexidade-ciclomatica/">complexidade ciclomática baixa</a>.</li> + <li>Evitar <a href="https://carlosschults.net/pt/tipos-de-comentarios-a-evitar/">comentários que não agregam nenhum valor</a>.</li> + <li>Manter <a href="https://blog.ploeh.dk/2019/11/04/the-80-24-rule/">funções e outros blocos de código pequenos</a>.</li> + <li>Evitar <a href="https://pt.wikipedia.org/wiki/N%C3%BAmero_m%C3%A1gico_(programa%C3%A7%C3%A3o_de_sistemas)">números mágicos</a>.</li> +</ul> + +<p>Não é difícil aprender esses tipos de práticas recomendadas. Você pode aprender a maioria delas por meio da experiência, ouvindo o feedback de desenvolvedores mais experientes durante as revisões de código ou lendo livros e até mesmo publicações em blogs como os listados acima.</p> + +<h2 id="nível-2-seu-código-é-idiomático">Nível 2: Seu Código é Idiomático</h2> + +<p>Considere a seguinte classe C#:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span> +<span class="p">{</span> + <span class="k">private</span> <span class="kt">string</span> <span class="n">_name</span><span class="p">;</span> + <span class="k">private</span> <span class="kt">int</span> <span class="n">_age</span><span class="p">;</span> + + <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span> + <span class="n">_age</span> <span class="p">=</span> <span class="n">age</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">SetName</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_name</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetName</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_name</span><span class="p">;</span> + + <span class="k">public</span> <span class="k">void</span> <span class="nf">SetAge</span><span class="p">(</span><span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">_age</span> <span class="p">=</span> <span class="n">age</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">int</span> <span class="n">GetAge</span> <span class="p">=&gt;</span> <span class="n">_age</span><span class="p">;</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>Não há nada de errado com a classe acima, pelo menos não tecnicamente. O compilador a compila sem problemas e a classe funciona como deveria.</p> + +<p>Entretanto, se você tem pelo menos alguma experiência com o C#, notou algo estranho quando viu o código: os métodos getter e setter. A equipe de desenvolvimento do C# transformou os conceitos de getters e setters em um “cidadão de primeira classe” da linguagem desde o início, por meio do conceito de propriedades. Se não houver lógica adicional envolvida na definição e obtenção de valores, o programador poderá usar <a href="https://learn.microsoft.com/pt-br/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties">propriedades autoimplementadas</a> com um resultado conciso (nem mesmo os campos privados precisam mais ser declarados explicitamente):</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Person</span> +<span class="p">{</span> + <span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">age</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">Name</span> <span class="p">=</span> <span class="n">nome</span><span class="p">;</span> + <span class="n">Age</span> <span class="p">=</span> <span class="n">idade</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> + <span class="k">public</span> <span class="kt">int</span> <span class="n">Age</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>Tudo isso quer dizer que, para ser legível, um determinado trecho de código precisa ser <em>idiomático para a linguagem em que está sendo escrito.</em> Se estiver escrevendo em C#, siga os padrões de codificação e as convenções da linguagem. O mesmo se aplica a Java, JavaScript e qualquer outra linguagem.</p> + +<p>A comunidade Python tem um conceito maravilhoso para descrever o código Python que segue os padrões e as filosofias da linguagem: “pythônico”. Um trecho de código Python pode funcionar, mas se não for pythônico, os engenheiros experientes em Python acharão o código difícil de trabalhar.</p> + +<p>Por que escrever um código idiomático é importante para a legibilidade? Quando você olha para um código - em qualquer linguagem - que não se parece com o que deveria ser, de acordo com o modelo mental que você tem dessa linguagem, fica mais difícil acompanhar o código.</p> + +<p>O código não idiomático aumenta a <a href="https://linearb.io/blog/cognitive-complexity-in-software">complexidade cognitiva</a> de uma base de código. Isso dificulta a integração de desenvolvedores que estejam familiarizados com os padrões e expressões idiomáticas da linguagem. Se você tiver um projeto open source, o excesso de idiossincrasias no código pode afastar possíveis colaboradores.</p> + +<p>É claro que o oposto de tudo isso é verdadeiro.</p> + +<h2 id="nível-3-seu-código-revela-a-intenção-por-meio-do-uso-tático-da-tipagem">Nível 3: Seu Código Revela a Intenção Por Meio Do Uso Tático Da Tipagem</h2> + +<p>Como o título sugere, este item, diferentemente dos dois anteriores, só se aplica a linguagens estaticamente tipadas - ou, talvez, dinamicamente tipadas que apresentem algum tipo de anotação de tipo opcional.</p> + +<p>Vamos começar com um exemplo simples:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Canvas</span><span class="p">.</span><span class="nf">DrawLine</span><span class="p">(</span><span class="m">5</span><span class="p">);</span> +</code></pre></div></div> + +<p>Não leve em consideração o número mágico, que por si só já é um problema. Considere que você sabe que o método <code class="language-plaintext highlighter-rouge">DrawLine</code> tem um único parâmetro, <code class="language-plaintext highlighter-rouge">length</code>. A linha poderia ter se tornado um pouco mais legível com o uso de um <a href="https://learn.microsoft.com/pt-br/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments">argumento nomeado,</a>, mas mesmo isso não resolveria o maior problema: qual é a unidade de medida?</p> + +<p>Além de prejudicar a legibilidade, esse problema abre a possibilidade de bugs, devido a uma incompatibilidade de unidades - uma parte do código “pensa” que a unidade é centímetros, enquanto outras podem acreditar que é polegadas.</p> + +<p>O que estou defendendo em vez disso? Bem, use a tipagem a seu favor. Aqui, uma boa solução seria criar um <a href="https://carlosschults.net/pt/value-objects-ferramenta/">value object</a> chamado, digamos, <code class="language-plaintext highlighter-rouge">Length</code>. Esse tipo teria vários métodos factory com o nome de unidades de medida específicas, e seu construtor seria privado. Então, daria para mudar o exemplo anterior para isso:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Canvas</span><span class="p">.</span><span class="nf">DrawLine</span><span class="p">(</span><span class="n">Length</span><span class="p">.</span><span class="nf">FromCentimeters</span><span class="p">(</span><span class="m">5</span><span class="p">));</span> +</code></pre></div></div> + +<p>Outro exemplo seria o uso do tipo <code class="language-plaintext highlighter-rouge">TimeSpan</code> para expressar durações, em vez de usar valores primitivos ou usar a classe <a href="https://learn.microsoft.com/pt-br/dotnet/api/system.uri?view=net-7.0">Uri</a> em vez de apenas strings.</p> + +<p>Talvez você esteja pensando que tudo isso é simplesmente uma forma complicada de dizer “evite a obsessão primitiva”. Também, mas tem mais coisas.</p> + +<p>Para ilustrar meu ponto de vista, vou compartilhar outro exemplo - talvez um pouco forçado, admito. Digamos que você esteja resolvendo um problema que exija o uso de uma <a href="https://pt.wikipedia.org/wiki/Pilha_(inform%C3%A1tica)">pilha</a>. Nesse caso, nada o impede de usar a classe <code class="language-plaintext highlighter-rouge">List&lt;T&gt;</code> como uma pilha, certo?</p> + +<ul> + <li>O método <code class="language-plaintext highlighter-rouge">Add</code> seria seu substituto para a funcionalidade <code class="language-plaintext highlighter-rouge">push</code>.</li> + <li>Para a funcionalidade <code class="language-plaintext highlighter-rouge">pop</code>, você usaria uma combinação de obter o último elemento da lista por meio de seu indexador e, em seguida, usar o método <code class="language-plaintext highlighter-rouge">RemoveAt</code> para excluir o item.</li> +</ul> + +<p>A solução acima, apesar de ser um pouco complicada, funcionaria. Mas eu o encorajaria fortemente a usar a classe <code class="language-plaintext highlighter-rouge">Stack&lt;T&gt;</code> normal. O uso do tipo mais específico tornaria o código imediatamente mais legível para qualquer pessoa que saiba o que é uma pilha. Isso faria com que o código revelasse sua intenção.</p> + +<p>Resumindo: a menos que você tenha um motivo justificável para não fazer isso, <strong>sempre prefira o tipo que representa melhor o conceito ou a funcionalidade de que você precisa</strong>. Isso não apenas tornará seu código mais robusto, mas também revelará melhor sua intenção.</p> + +<h2 id="nível-4-seu-código-não-mistura-níveis-de-abstração">Nível 4: Seu Código Não Mistura Níveis de Abstração</h2> + +<p>Seu código não deve misturar mais de um nível de abstração. O código que está na parte de “Regras de negócios” da sua base de código não deve mexer com o código que está na parte de “Preocupações de IO”, para dar um exemplo.</p> + +<p>Por que isso é um problema? Veja a função a seguir:</p> + +<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="kt">double</span> <span class="nf">CalculateAverageTemperature</span><span class="p">(</span><span class="kt">string</span> <span class="n">filePath</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">List</span><span class="p">&lt;</span><span class="n">ClimaticReading</span><span class="p">&gt;</span> <span class="n">readings</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span> + + <span class="k">try</span> + <span class="p">{</span> + <span class="k">using</span> <span class="nn">var</span> <span class="n">reader</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StreamReader</span><span class="p">(</span><span class="n">filePath</span><span class="p">);</span> + <span class="k">while</span> <span class="p">(!</span><span class="n">reader</span><span class="p">.</span><span class="n">EndOfStream</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">line</span> <span class="p">=</span> <span class="n">reader</span><span class="p">.</span><span class="nf">ReadLine</span><span class="p">();</span> + <span class="kt">var</span> <span class="n">values</span> <span class="p">=</span> <span class="n">line</span><span class="p">?.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">)</span> <span class="p">??</span> <span class="n">Array</span><span class="p">.</span><span class="n">Empty</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;();</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">Length</span> <span class="p">&lt;</span> <span class="m">2</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">values</span><span class="p">[</span><span class="m">0</span><span class="p">],</span> <span class="k">out</span> <span class="n">DateTime</span> <span class="n">date</span><span class="p">)</span> <span class="p">&amp;&amp;</span> + <span class="kt">double</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span> + <span class="n">values</span><span class="p">[</span><span class="m">1</span><span class="p">],</span> + <span class="n">NumberStyles</span><span class="p">.</span><span class="n">Float</span><span class="p">,</span> + <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">,</span> + <span class="k">out</span> <span class="kt">double</span> <span class="n">temperature</span><span class="p">))</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">reading</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ClimaticReading</span> + <span class="p">{</span> + <span class="n">Date</span> <span class="p">=</span> <span class="n">data</span><span class="p">,</span> + <span class="n">Temperature</span> <span class="p">=</span> <span class="n">temperatura</span> + <span class="p">};</span> + <span class="n">readings</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">reading</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="s">$"Erro ao ler o arquivo CSV: </span><span class="p">{</span><span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">readings</span><span class="p">.</span><span class="n">Count</span> <span class="p">&lt;</span> <span class="m">3</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="s">"Deve haver pelo menos 3 leituras para calcular a média."</span><span class="p">);</span> + <span class="p">}</span> + + <span class="n">readings</span> <span class="p">=</span> <span class="n">readings</span><span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">leitura</span> <span class="p">=&gt;</span> <span class="n">leitura</span><span class="p">.</span><span class="n">Temperatura</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span> + + <span class="n">readings</span><span class="p">.</span><span class="nf">RemoveAt</span><span class="p">(</span><span class="m">0</span><span class="p">);</span> + <span class="n">readings</span><span class="p">.</span><span class="nf">RemoveAt</span><span class="p">(</span><span class="n">readings</span><span class="p">.</span><span class="n">Count</span> <span class="p">-</span> <span class="m">1</span><span class="p">);</span> + + <span class="kt">double</span> <span class="n">sum</span> <span class="p">=</span> <span class="n">readings</span><span class="p">.</span><span class="nf">Sum</span><span class="p">(</span><span class="n">reading</span> <span class="p">=&gt;</span> <span class="n">reading</span><span class="p">.</span><span class="n">Temperature</span><span class="p">);</span> + <span class="kt">double</span> <span class="n">average</span> <span class="p">=</span> <span class="n">sum</span> <span class="p">/</span> <span class="n">readings</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">average</span><span class="p">;</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>A função lê e analisa um arquivo .CSV que contém leituras climáticas. As linhas que não têm os dois valores esperados (data e temperatura) são descartadas. Em seguida, ela classifica as leituras, remove os valores mais altos e mais baixos e, por fim, calcula e retorna a média dos valores restantes.</p> + +<p>Essa função mistura pelo menos dois níveis de abstração:</p> + +<ul> + <li>O nível de “lógica de domínio”, ou seja, a parte que faz o cálculo</li> + <li>O nível baixo: leitura e parsing do arquivo .CSV.</li> +</ul> + +<p>Você poderia até argumentar que há três níveis, já que o nível baixo pode ser dividido em dois: manipulação do sistema de arquivos e parsing de arquivos.</p> + +<p>Essa função de exemplo não é a coisa mais difícil de ler no mundo, mas certamente é mais difícil do que deveria ser. Ela mistura lógica de domínio com IO. Ela mistura lógica de domínio com tratamento de erros de IO e até mesmo parsing. Uma solução melhor seria ter um método que obtivesse uma coleção de <code class="language-plaintext highlighter-rouge">ClimaticReading</code> e calculasse e retornasse a média.</p> + +<p>Em outras palavras, uma solução melhor e mais elegante seria ter uma <strong>função pura</strong>. Esse novo método, além de ser mais legível, seria mais robusto, menos propenso a erros e também determinístico, ou seja, sempre retornaria os mesmos resultados para a mesma entrada, tornando-o intrinsecamente <a href="https://carlosschults.net/pt/testes-unitarios-csharp-intro-tdd/">testável por testes de unidade</a>.</p> + +<h2 id="nível-5-seu-código-fala-a-linguagem-do-negócio">Nível 5: Seu Código Fala a Linguagem Do Negócio</h2> + +<p>Você atingiu o nível 5 quando escreve um código que fala a linguagem do negócio. Quando você usa termos que são os mesmos que os especialistas no domínio usam.</p> + +<p>Em outras palavras: sim, estou praticamente defendendo a mesma coisa que os programadores pragmáticos chamam de “programar mais próximo do domínio”, ou que Eric Evans chamou de linguagem ubíqua em seu clássico “Domain-Driven Design: Tackling Complexity in the Heart of Software”.</p> + +<p>Se o seu código usa termos não ortodoxos em vez de termos do setor, isso dificulta a integração quando você traz novas pessoas que estão familiarizadas com o negócio, mas são novas na base de código. Se o código usar um jargão diferente do que os stakeholders usam, a comunicação se tornará mais cansativa, pois exigirá que você faça um mapeamento constante entre os conceitos apenas para conseguir acompanhar o que está acontecendo.</p> + +<p>O nível 5 é, de certa forma, uma consequência lógica do nível 4. Se você separar cuidadosamente as preocupações da sua aplicação, certificando-se de que o código de alto nível não se misture com o código de baixo nível, a tendência é que o código de alto nível fique cada vez mais próximo do domínio em termos de nomenclatura.</p> + +<h2 id="dê-um-level-up-na-legibilidade-do-seu-código">Dê um “Level Up” Na Legibilidade Do Seu Código</h2> + +<p>A maioria dos programadores concorda que a legibilidade do código é vital. Mas e quanto a concordar com a aparência de um “código legível”? Aí é outra história.</p> + +<p>Como eu disse anteriormente, acho que um nível de subjetividade quando se trata de legibilidade é inevitável e inofensivo. Entretanto, no contexto de um time, deve haver pelo menos algum consenso sobre o que é um código legível. Caso contrário, as revisões de código se tornam exercícios de futilidade e o moral da equipe despenca.</p> + +<p>Acredito que nosso setor se beneficiaria de uma forma mais objetiva de pensar sobre a legibilidade. Nesta publicação, dei minha pequena contribuição, na forma de um checklist de legibilidade, em ordem de prioridade.</p> + +<p>Mas, novamente: a ideia desta publicação não é dar uma resposta definitiva, <strong>mas iniciar uma conversa</strong>. Você acha que os modelos de “níveis” não fazem sentido? Ou talvez queira compartilhar seus próprios níveis? Convido-o a compartilhar sua opinião por meio de um comentário ou a me enviar um e-mail (meu endereço está na página sobre).</p> + +<p>_Agradecimentos especiais a <a href="https://blog.ploeh.dk/">Mark Seemann</a>, <a href="https://www.linkedin.com/in/pgpbarbosa/">Pedro Barbosa</a> e <a href="https://www.linkedin.com/in/petermorlion/">Peter Morlion</a> por lerem e darem feedback em rascunhos deste post.</p> + + Wed, 18 Oct 2023 00:00:00 +0000 + https://carlosschults.net/pt/cinco-niveis-codigo-legivel + https://carlosschults.net/pt/cinco-niveis-codigo-legivel + + boas-praticas + + legibilidade + + + + + + Fazendo Seu Histórico Git Ficar Bonitão Com Amend e Rebase + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png" alt="" /></p> + +<p><span>Foto por <a href="https://unsplash.com/@yancymin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yancy Min</a> no <a href="https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p>Você faz parte de uma equipe de software de pequeno a médio porte e morre de inveja do histórico de commits das pessoas que trabalham com você. Elas produzem histórias limpas e bem estruturadas com mensagens de commit bem escritas. A sua, em comparação, é um desastre, cheia de descrições como “corrigir erro de digitação”, “adicionar arquivo esquecido” e assim por diante. Você queria entender como eles fazem isso.</p> + +<p>A resposta é simples: <em>eles trapaceiam</em>. Seguinte: eles provavelmente cometem tantos erros quanto você, mas usam as features do Git para escondê-los. Eles então apresentam uma história mais limpa e bonita para o mundo.</p> + +<p>Algumas ferramentas de controle de versão tratam o histórico do projeto como se fosse esta coisa super sagrada. Git não é assim. Ele lhe dá o poder de reescrever a história como você quiser. Tanto poder que você pode até se dar mal se não tiver cuidado.</p> + +<p>Neste post, eu lhe mostrarei como usar <code class="language-plaintext highlighter-rouge">amend</code> e rebase interativo para fazer sua história de commits no Git ficar bonitona antes de publicá-la. Não vai ter muita teoria; eu o acompanharei através de alguns cenários comuns, mostrando como eu iria resolvê-los.</p> + +<p>Antes de terminar, vou ensiná-lo a não atirar no seu pé com estes comandos. Como explicarei, <code class="language-plaintext highlighter-rouge">amend</code> e <code class="language-plaintext highlighter-rouge">rebase</code> são ações destrutivas, e tem situações em que você não deve executá-las.</p> + +<h2 id="requisitos">Requisitos</h2> +<p>Para acompanhar este posto, presumo que você:</p> + +<ul> + <li>sabe trabalhar com a linha de comando</li> + <li>tem o Git instalado em sua máquina</li> + <li>conhece ao menos os comandos básicos do Git</li> +</ul> + +<p>Ao escrever este post, estou no Windows, usando a versão Git <strong>2.38.1.windows.1</strong>* e digitando meus comandos no Git Bash. Se você estiver no Linux ou OSX, acho que tudo funcionará da mesma forma, mas eu não testei.</p> + +<h2 id="definindo-o-vs-code-como-seu-editor-de-texto-predefinido">Definindo o VS Code como seu editor de texto predefinido</h2> +<p>Apenas um último detalhe antes da gente começar pra valer. Alguns dos comandos que você verá ao longo deste post exigirão que você edite e salve um arquivo de texto. Eles fazem isso abrindo seu editor de texto padrão conforme configurado em seu arquivo de configuração Git e esperando até que você edite, salve e feche o arquivo.</p> + +<p>Se você estiver no Windows como eu, usando o Git Bash, seu editor padrão será o Vim. Vim é um editor de texto de linha de comando, e algumas pessoas o acham intimidante. Embora aprender Vim exija algum trabalho, não é tão difícil de começar, e eu recomendaria que você investisse algum tempo para aprender pelo menos os comandos mais básicos - especialmente como sair!</p> + +<p>Entretanto, Git permite que você escolha outros editores de texto como seu padrão. Se você tiver o <a href="https://code.visualstudio.com/">Visual Studio Code</a> instalado e quiser usá-lo, execute o seguinte comando:</p> + +<p><code class="language-plaintext highlighter-rouge">git config --global core.editor "code --wait"</code></p> + +<h2 id="reescrevendo-história-3-cenários-comuns">Reescrevendo História: 3 Cenários comuns</h2> +<p>Vou mostrar alguns cenários comuns nos quais você poderá se encontrar, nos quais a reescrita da história o salvará.</p> + +<h3 id="minha-mensagem-de-commit-tem-um-erro">Minha Mensagem de Commit Tem Um Erro</h3> +<p>Você está correndo para corrigir este bug de alta prioridade. Depois de horas de depuração exaustiva, você encontra o código ofensivo, faz a correção e faz o commit da mudança.</p> + +<p>Só então você vê que cometeu um erro de digitação. Como corrigir isso?</p> + +<p>Vamos começar criando um repositório para que você possa praticar:</p> + +<p><code class="language-plaintext highlighter-rouge">git init</code></p> + +<p>Agora, vamos adicionar um novo arquivo e commitar:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>file.txt +git add file.txt +git commit <span class="nt">-m</span> <span class="s2">"fix async request in getUsers() functino"</span><span class="sb">`</span> +</code></pre></div></div> + +<p>Execute <code class="language-plaintext highlighter-rouge">git log--oneline</code> para ver sua mensagem de commit. Você verá algo como isto:</p> + +<p><img src="/img/git-beautiful-history/img1.png" alt="" /></p> + +<p>Preste atenção no identificador do commit, e talvez até mesmo anote-o em algum lugar; será importante mais tarde. (O seu será diferente do meu).</p> + +<p>De qualquer forma, sua mensagem tem um erro. Como você a corrige?</p> + +<p>Basta executar o comando <code class="language-plaintext highlighter-rouge">git commit --amend</code>, exatamente assim. O Git abrirá seu editor de texto e esperará que você edite a mensagem do commit:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fix async request in getUsers() functino + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# Date:      Tue Jan 10 19:14:17 2023 -0300 +# +# On branch master +# +# Initial commit +# +# Changes to be committed: +#   new file:   file.txt +# +</code></pre></div></div> + +<p>A primeira linha é a mensagem de commit propriamente dita. As linhas que começam com o “#” são comentários e serão ignoradas. Basta corrigir o erro, salvar e fechar o arquivo de texto, e você terá uma nova mensagem de commit. Execute o <code class="language-plaintext highlighter-rouge">git log --oneline</code> novamente para vê-lo:</p> + +<p><img src="/img/git-beautiful-history/img2.png" alt="" /></p> + +<p>Você notará que a identificação (SHA-1) do commit é agora diferente do que era antes - e também diferente daquela da imagem acima. Voltarei a este assunto mais tarde.</p> + +<p>Por enquanto, você alterou com sucesso sua mensagem de commit. Parabéns!</p> + +<h3 id="esqueci-de-incluir-um-arquivo">Esqueci de Incluir um Arquivo</h3> +<p>Às vezes você tem vários arquivos alterados e quer commitar alguns, mas não todos. Na sua pressa, você deixa um ou mais arquivos para trás. Como corrigir isso?</p> + +<p><code class="language-plaintext highlighter-rouge">amend</code> ao resgate novamente.</p> + +<p>Para simular esta situação, vamos criar um novo arquivo e também adicionar uma nova linha ao existente:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>file2.txt +<span class="nb">echo</span> <span class="s1">'New line'</span> <span class="o">&gt;&gt;</span> file.txt +</code></pre></div></div> + +<p>Um erro comum aqui é fazer o commit com a opção <code class="language-plaintext highlighter-rouge">-a</code>, pensando que ela incluirá ambos os arquivos:</p> + +<p><code class="language-plaintext highlighter-rouge">git commit -am "atualizar arquivo e adicionar arquivo2"</code></p> + +<p>Execute o comando acima. Em seguida, execute o comando <code class="language-plaintext highlighter-rouge">git status</code>. Este é o resultado que você vai obter:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>On branch master + +Untracked files: + + (use "git add &lt;file&gt;..." to include in what will be committed) + + file2.txt + +nothing added to commit but untracked files present (use "git add" to track) +</code></pre></div></div> +<p>Corrigir a situação é fácil. Primeiro, você rastreia ou adiciona ao index o arquivo esquecido:</p> + +<p><code class="language-plaintext highlighter-rouge">git add file2.txt</code></p> + +<p>Em seguida, utilize novamente o <code class="language-plaintext highlighter-rouge">git commit -amend</code>. Seu editor irá abrir, mas neste caso, não há nada de errado com a mensagem. Basta fechar o editor e pronto: agora você tem um commit “emendado” que inclui o arquivo anteriormente esquecido.</p> + +<p>Mas se você se parece comigo, provavelmente se sentiu meio trouxa tendo aberto seu editor de texto sem nenhuma razão.</p> + +<p>Felizmente, você nem sempre tem que fazer isso. Quando você quer apenas adicionar um ou mais arquivos faltantes sem alterar a mensagem de commit, você pode usar a opção <code class="language-plaintext highlighter-rouge">--no-edit</code>, desta forma:</p> + +<p><code class="language-plaintext highlighter-rouge">git commit --amend --no-edit</code></p> + +<p>Desta forma, Git não abrirá seu editor de texto, mantendo a mensagem de commit original.</p> + +<h3 id="quero-mesclar-vários-commits-em-um-só">Quero Mesclar Vários Commits Em Um Só</h3> +<p>A fusão de vários commits em um só é uma operação chamada “squashing”. Mas por que você iria querer fazer isso?</p> + +<p>Bem, tudo se resume ao seu estilo Git. Eu gosto de fazer pequenos commits, com muita freqüência. Depois, quando estou prestes a torná-los públicos (por exemplo, ao abrir um pull request) eu os junto em um único commit, com uma mensagem bem escrita.</p> + +<p>Esta também é uma exigência comum dos mantenedores de projetos de código aberto, por isso é uma boa habilidade pra se ter. Vamos aprender como fazer isso.</p> + +<p>Primeiro, vamos criar três commits:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit"</span> <span class="nt">-m</span> +git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit 2"</span> <span class="nt">-m</span> +git commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> <span class="s2">"empty commit 3"</span> <span class="nt">-m</span> +</code></pre></div></div> + +<p>Ter de ficar criando arquivos inúteis para poder commitar é tedioso. É por isso que eu estou usando a opção <code class="language-plaintext highlighter-rouge">--allow-empty</code>, que me permite criar commits vazios.</p> + +<p>Agora, digamos que eu preciso juntar os três commits acima em um só. Para fazer isso, precisarei rebaseá-los interativamente. Ao fazer um rebase interativo, você pode realizar tarefas como:</p> + +<ul> + <li>Reordenar commits</li> + <li>Abandonar um ou mais commits</li> + <li>Mudar suas mensagens</li> + <li>Mesclar um ou mais commits</li> +</ul> + +<p>Agora vem a parte que pode ser confusa, então preste atenção, por favor. Já que vamos trabalhar com os três últimos commits, dizemos que os estamos rebaseando em cima do quarto commit (contando a partir do último.)</p> + +<p>Então, use o comando <code class="language-plaintext highlighter-rouge">git log --oneline -4</code> para exibir os últimos quatro commits e depois copie o SHA-1 do quarto commit do resultado:</p> + +<p><img src="/img/git-beautiful-history/img3.png" alt="" /></p> + +<p>Copie o identificador desse commit e passe-o para o comando de rebase, assim:</p> + +<p><code class="language-plaintext highlighter-rouge">git rebase -i 45f90ca</code></p> + +<p>Naturalmente, seu valor real de SHA-1 será diferente. Mas há uma maneira mais fácil:</p> + +<p><code class="language-plaintext highlighter-rouge">git rebase -i HEAD~3</code></p> + +<p>Para simplificar, <code class="language-plaintext highlighter-rouge">HEAD</code> aqui significa o último commit, e <code class="language-plaintext highlighter-rouge">~3</code> significa “três commits antes deste”.</p> + +<p>Após executar um dos dois comandos acima, seu editor irá abrir, mostrando um arquivo de texto que contém as mensagens dos três commits que queremos reorganizar, cada um precedido pela palavra “pick”. E depois disso, um conjunto de instruções:</p> + +<p><img src="/img/git-beautiful-history/img4.png" alt="" /></p> + +<p>Observe que os commits aqui não estão na ordem em que você está acostumado a vê-los no Git. Em vez de estarem em ordem cronológica inversa, eles estão em ordem cronológica direta, e há uma razão para isso.</p> + +<p>Cada linha que você vê acima é um comando que o Git executará quando você confirmar a operação de rebase. Há vários comandos disponíveis, e o <code class="language-plaintext highlighter-rouge">pick</code> é o comando padrão. Isso significa simplesmente que o commit será mantido como está. Você pode usar <code class="language-plaintext highlighter-rouge">drop</code> para remover um commit, <code class="language-plaintext highlighter-rouge">reword</code> para editar uma mensagem de commit, e assim por diante.</p> + +<p>O comando que vamos utilizar é <code class="language-plaintext highlighter-rouge">squash</code>. Basta substituir a palavra <code class="language-plaintext highlighter-rouge">pick</code> por <code class="language-plaintext highlighter-rouge">squash</code> no segundo e terceiro commits, desta forma:</p> + +<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pick dd25df9 empty commit <span class="c"># empty</span> +squash c68804f empty commit 2 <span class="c"># empty</span> +squash a76fd60 empty commit 3 <span class="c"># empty</span> +</code></pre></div></div> + +<p>O comando <code class="language-plaintext highlighter-rouge">squash</code> mescla um commit com aquele anterior. Assim, o terceiro será fundido com o segundo, que será fundido com o primeiro. E é por isso que o primeiro precisa ser <em>picked</em>.</p> + +<p>Depois de editar o texto como eu lhe disse, salve e feche o arquivo. Quando você fizer isso, seu editor será aberto novamente. Desta vez, você será solicitado a escrever uma mensagem de commit para o novo commit que irá surgir:</p> + +<p><img src="/img/git-beautiful-history/img5.png" alt="" /></p> + +<p>Substituir o conteúdo do arquivo por “this is now a single commit”. Salve e feche o arquivo.</p> + +<p>Finalmente, vamos ver o resultado:</p> + +<p><code class="language-plaintext highlighter-rouge">git log --oneline</code></p> + +<p>Isto é o que você deveria ver:</p> + +<p><img src="/img/git-beautiful-history/img6.png" alt="" /></p> + +<p>Como você pode ver, os três commits vazios foram substituídos por um único commit. Você realizou com sucesso sua primeira operação de <code class="language-plaintext highlighter-rouge">squash</code>. Parabéns!</p> + +<h2 id="quando-não-se-deve-mexer-com-a-história">Quando Não Se Deve Mexer Com a História</h2> +<p>Antes de terminar, vamos entender quando a mudança da história é problemática.</p> + +<p>Primeiro, entenda que tanto <code class="language-plaintext highlighter-rouge">amend</code> quanto <code class="language-plaintext highlighter-rouge">rebase</code> produzem <strong>mudanças destrutivas</strong>. É como se eles estivessem destruindo a história e criando uma nova.</p> + +<p>Então, imagine que você junta três commits (que já haviam sido enviados para o servidor) e depois faz o <code class="language-plaintext highlighter-rouge">push</code> desse novo commit para dentro do repositório remoto (você teria que forçar o <code class="language-plaintext highlighter-rouge">push</code> para que isso funcionasse, a propósito.) Mas enquanto você estava trabalhando, seu colega de trabalho tinha criado um branch novo a partir do (o que era então) último commit.</p> + +<p>Esse commit não existe mais (tecnicamente, isso não é bem verdade, mas vamos fingir por um minuto que é), o que significa que eles não serão capazes de simplesmente dar o push das suas mudanças. Eles terão que puxar seus novos commits e então realizar um merge potencialmente complexo a fim de conseguir que as coisas sejam ordenadas.</p> + +<p>Portanto, a regra de ouro é <strong>nunca reescreva a história da qual outras pessoas dependem.</strong> O que isto significa em específico depende do workflow de branches que você e sua equipe utilizam.</p> + +<p>Se você usar <a href="https://trunkbaseddevelopment.com/">trunk-based development,</a> nunca reescreva o branch master/main. O mesmo é verdade se seu trabalho com <a href="https://docs.github.com/en/get-started/quickstart/github-flow">GitHub Flow</a>. Se você usa o git-flow, isso significa nunca reescrever os branches permanentes, ou seja, master/main e develop.</p> + +<h2 id="ok-eu-menti-toma-um-pouco-de-teoria">OK, Eu Menti: Toma Um Pouco De Teoria</h2> +<p>Ao longo deste artigo, usei expressões como “mudar a mensagem do commit”, “juntar múltiplos commits em um”, e assim por diante.</p> + +<p>Tecnicamente falando, tudo isso eram mentiras. Quando você utiliza comandos como <code class="language-plaintext highlighter-rouge">git commit --amend</code> ou <code class="language-plaintext highlighter-rouge">rebase -i</code>, você não está mudando nada. O que Git está fazendo é <strong>criar novos commits</strong>.</p> + +<p>Lembra-se quando você usou o <code class="language-plaintext highlighter-rouge">amend</code> pela primeira vez e eu disse que era relevante que o commit agora tinha um novo identificador? Acontece que aquele era um commit completamente novo, e o antigo ainda está por aí!</p> + +<p>O mesmo vale para a operação de rebase. Quando você “mescla três commits em um”, não é isso que está acontecendo. Em vez disso, Git cria um novo commit e atualiza a referência do branch, de modo que aponte para o novo commit. Os três commits antigos ainda estão lá (pelo menos por algum tempo), mas como nenhum branch aponta para eles, eles são inalcançáveis - a menos que você consiga obter de alguma forma os valores SHA-1 deles.</p> + +<p>A imagem a seguir representa o que realmente aconteceu depois que você deu squash nos seus commits:</p> + +<p><img src="/img/git-beautiful-history/img7.png" alt="" /></p> + +<p>Agora, vamos ver o cenário após o squash:</p> + +<p><img src="/img/git-beautiful-history/img8.png" alt="" /></p> + +<p>Como você pode ver, há agora um novo commit, em laranja, que é o resultado de “mesclar” os três originais. No entanto, os três commits antigos ainda estão lá. Mas não se pode alcançá-los facilmente, porque agora não há nenhum branch apontando para eles.</p> + +<p>O leitor astuto vai notar que até mesmo as imagens acima são uma simplificação. “Deveríamos ter mais commits na imagem”, dizem eles, com seu dedo indicador acusatório apontando para a tela. E adivinhe, eles estão certos.</p> + +<p>Lembra-se de que começamos tudo isso alterando dois commits? Bem, como dar <code class="language-plaintext highlighter-rouge">amend</code> não altera os commits, mas cria novos, temos dois commits extra perdidos em nosso repositório. Eu os omiti dos diagramas acima <sup>porque eu estava com preguiça</sup> por uma questão de brevidade. Mas como um exercício para o leitor, você mesmo pode adicioná-los.</p> + +<h2 id="reescreva-o-passado-para-parecer-e-ser-mais-inteligente">Reescreva o Passado Para Parecer (e ser) Mais Inteligente</h2> +<p>Reescrever a história é uma poderosa capacidade do Git. Com comandos como <code class="language-plaintext highlighter-rouge">git commit --amend</code> e <code class="language-plaintext highlighter-rouge">git rebase -i</code> você pode “mudar” seus commits passados, escondendo seus erros e fazendo parecer que você fez tudo certo desde o início. Eu faço isso o tempo todo e colho os benefícios: meus colegas de trabalho pensam que sou muito mais esperto do que realmente sou - por favor, não conta meu segredo pra eles.</p> + +<p>Falando sério agora: esses comandos são ferramentas fantásticas para você conseguir um histórico mais organizado. Com eles, você pode perder de uma vez o medo de commitar com frequência. Faça commits pequenos e frequentes, e não ligue muito para a mensagem — por exemplo, se você usa <a href="/pt/testes-unitarios-csharp-intro-tdd/">TDD</a>, você pode commitar toda vez que os testes passarem.</p> + +<p>Depois, quando for a hora de publicar o seu trabalho, dê squash nos commits e capriche na descrição. Aproveite e adote uma convenção de mensagens de commit para você e seu time, como o <a href="https://www.conventionalcommits.org/pt-br/v1.0.0/">Conventional Commits</a>. Seus colegas (e seu eu futuro) vão te agradecer.</p> + + Tue, 17 Jan 2023 00:00:00 +0000 + https://carlosschults.net/pt/git-historico-bonito/ + https://carlosschults.net/pt/git-historico-bonito/ + + git + + + + + + Como Reduzir a Complexidade Ciclomática: Um Guia Completo + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1617641333/reduce-cyclomatic-complexity/reduce-cyclomatic-complexity-1038x437.jpg" alt="" /> +<span>Foto por <a href="https://unsplash.com/@hishahadat?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Shahadat Rahman</a> no <a href="https://unsplash.com/s/photos/complexity?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p><em>Nota editorial: Escrevi originalmente este post para o blog da LinearB. Você pode <a href="https://linearb.io/blog/reduce-cyclomatic-complexity/">conferir o original em inglês no site deles</a>. Enquanto estiver lá, dê uma olhada no produto deles, uma solução de inteligência de software que usa Git e estatísticas de projetos para ajudar as equipes de desenvolvimento a melhorar sua produtividade.</em></p> + +<p>Engenheiros(as) de software dignos do nome estão sempre em busca de maneiras de melhorar seu código. A boa notícia é que existe uma maneira confiável de avaliar a saúde de uma base de código e de um projeto, e isso é através do uso de <a href="https://linearb.io/metrics-modern-dev-leaders/">métricas</a>. O post de hoje é sobre uma métrica específica. Você aprenderá como reduzir a complexidade ciclomática e, mais importante, por que você gostaria de fazê-lo.</p> + +<p>Vamos começar definindo a complexidade ciclomática. Depois disso, você aprenderá qual é o problema de ter um alto valor de complexidade ciclomática e por que você precisaria reduzi-la. Depois do “o quê” e do “porquê”, finalmente chegaremos ao “como”: mostraremos as táticas que você pode adotar para reduzir a complexidade ciclomática de seu código. Vamos lá.</p> + +<h2 id="complexidade-ciclomática-uma-breve-definição">Complexidade Ciclomática: Uma breve definição</h2> + +<p>A complexidade ciclomática é uma importante métrica de software. Refere-se ao número de caminhos de execução possíveis dentro de um determinado código - por exemplo, uma função. Quanto mais estruturas de decisão você usar, mais ramificações possíveis existem para seu código.</p> + +<p>A complexidade ciclomática é especialmente importante quando se trata de testes. Ao calcular a complexidade ciclomática de uma função, por exemplo, você sabe o número mínimo de casos de teste que você precisará para alcançar a <a href="https://linearb.io/blog/what-is-branch-coverage/">cobertura de ramificação</a> completa dessa função. Portanto, podemos dizer que a complexidade ciclomática pode ser um preditor de quão difícil é testar um determinado código.</p> + +<h2 id="um-exemplo-de-complexidade-ciclomática-super-simples">Um Exemplo de Complexidade Ciclomática Super Simples</h2> + +<p>Considere a seguinte função escrita em pseudocódigo:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">void</span> <span class="nf">sayHello</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Hello, ${name}!"</span><span class="p">);</span> +<span class="p">}</span></code></pre></figure> + +<p>Como tem uma única declaração, é fácil ver sua complexidade ciclomática é 1. Agora, vamos mudar um pouco as coisas:</p> + +<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">void</span> <span class="nf">sayHello</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">sayGoodbye</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Hello, ${name}!"</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sayGoodbye</span><span class="p">)</span> <span class="p">{</span> + <span class="nf">print</span><span class="p">(</span><span class="s">"Goodbye, ${name}!"</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>A segunda versão da função tem um ramo nela. O chamador da função pode passar <strong>true</strong> como o valor do parâmetro <strong>sayGoodbye</strong>, mesmo que o valor padrão seja <strong>false</strong><em>. Se isso acontecer, a função imprimirá uma mensagem de adeus após dizer olá. Por outro lado, se o interlocutor não fornecer um valor para o parâmetro ou escolher <strong>false</strong></em>, a mensagem de adeus não será exibida.</p> + +<p>Portanto, a função tem dois ramos de execução possíveis, o que é o mesmo que dizer que sua complexidade ciclomática tem um valor de 2.</p> + +<h2 id="por-que-a-complexidade-ciclomática-é-ruim">Por que a Complexidade Ciclomática é Ruim?</h2> + +<p>A complexidade ciclomática não é intrinsecamente ruim. Por exemplo, você pode ter um pedaço de código com um valor complexo ciclomático um pouco alto que é super fácil de ler e entender. Entretanto, de modo geral, podemos dizer que ter uma alta complexidade ciclomática é ou um sintoma de problemas com a base de código ou uma causa potencial de problemas futuros. Vamos cobrir algumas das razões pelas quais você gostaria de reduzi-la com mais detalhes.</p> + +<h3 id="a-complexidade-ciclomática-pode-contribuir-para-a-complexidade-cognitiva">A Complexidade Ciclomática Pode Contribuir para a Complexidade Cognitiva</h3> + +<p>A complexidade cognitiva refere-se ao quanto é difícil entender um determinado código. Embora nem sempre seja esse o caso, a complexidade ciclomática pode ser um dos fatores que impulsionam a complexidade cognitiva. Quanto maior a complexidade cognitiva de um pedaço de código, mais difícil é navegar e manter.</p> + +<h3 id="a-complexidade-ciclomática-torna-o-código-mais-difícil-de-ser-testado">A Complexidade Ciclomática torna o código mais difícil de ser testado</h3> + +<p>Como já mencionamos, valores mais altos de complexidade ciclomática resultam na necessidade de um maior número de casos de teste para testar de forma abrangente um bloco de código - e.g., uma função. Portanto, se você quer facilitar sua vida ao escrever testes, provavelmente quer reduzir a complexidade ciclomática de seu código.</p> + +<h3 id="a-complexidade-ciclomática-contribui-para-maior-risco-de-defeitos">A Complexidade Ciclomática Contribui para Maior Risco de Defeitos</h3> + +<p>É mais provável que você introduza defeitos em uma área da base de código que você muda muito do que a uma que você raramente toca. Além disso, quanto mais complexo for um determinado pedaço de código, mais provável é que você o entenda mal e introduza um defeito a ele.</p> + +<p>Portanto, código complexo que sofre muito <a href="https://linearb.io/blog/what-is-code-churn/">churn</a>- mudanças freqüentes pela equipe - representa mais risco de defeitos. Ao reduzir a complexidade ciclomática - e, idealmente, também a rotatividade do código - você estará mitigando esses riscos.</p> + +<h2 id="como-reduzir-a-complexidade-ciclomática-6-maneiras-práticas">Como Reduzir a Complexidade Ciclomática: 6 Maneiras Práticas</h2> + +<p>Agora vamos rever algumas dicas práticas que você pode usar para garantir que a complexidade ciclomática de seu código seja a mais baixa possível.</p> + +<h3 id="1preferir-funções-menores">1.Preferir funções menores</h3> + +<h4 id="o-que-fazer">O que fazer?</h4> + +<p>Sendo todas as outras iguais, funções menores são mais fáceis de ler e entender. Elas também são menos propensas a conter bugs em virtude de seu comprimento. Se você não tem muito código, você não tem muitas oportunidades para o código de bugs. O mesmo raciocínio se aplica à complexidade ciclomática: é menos provável que você tenha um código complexo se tiver menos período de código. Portanto, o conselho aqui é preferir funções menores.</p> + +<h4 id="como-fazer-isso">Como fazer isso?</h4> + +<p>Para cada função, identifique sua principal responsabilidade. Extraia o que sobra para suas próprias funções e módulos. Fazer isso também facilita a reutilização do código, o que é um ponto que revisaremos em breve.</p> + +<h3 id="2evitar-argumentos-de-bandeira-em-funções">2.Evitar Argumentos de Bandeira em Funções</h3> + +<h4 id="o-que-fazer-1">O que fazer?</h4> + +<p>Os argumentos da bandeira são parâmetros booleanos que você acrescenta a uma função. As pessoas normalmente os utilizam quando precisam mudar o funcionamento de uma função, preservando ao mesmo tempo o antigo comportamento.</p> + +<h4 id="como-fazer">Como fazer?</h4> + +<p>O que usar ao invés de parâmetros de bandeira? Em poucas palavras, você pode usar estratégias que alcançam o mesmo resultado sem incorrer em alta complexidade. Por exemplo, você poderia criar uma nova função, mantendo a antiga como está e extraindo as partes comuns em sua própria função privada.</p> + +<p>Se o parâmetro da bandeira estiver sendo usado para melhorar ou melhorar de alguma forma o comportamento da função original, você pode querer aproveitar o [padrão decorator] (https://en.wikipedia.org/wiki/Decorator_pattern) para alcançar o mesmo fim.</p> + +<h3 id="3reduzir-o-número-de-estruturas-de-decisão">3.Reduzir o número de estruturas de decisão</h3> + +<h4 id="o-que-fazer-2">O que fazer?</h4> + +<p>Você pode considerar este um “não-cérebro”. Se as estruturas de decisão - especialmente <strong>se-else</strong> e mudar de caso são o que causa mais ramos no código, é lógico que você deve reduzi-los se quiser manter a complexidade ciclomática à distância.</p> + +<h4 id="como-fazer-isso-1">Como fazer isso?</h4> + +<p>Algumas das táticas que acabamos de ver podem contribuir para reduzir o número de <strong>se</strong> declarações em seu código. Por exemplo, em vez de usar argumentos de bandeira e depois usar uma declaração <strong>if</strong>* para verificar, você pode usar o padrão decorador. Em vez de usar um caso de troca para rever muitas possibilidades e decidir qual delas o código executará, você pode aproveitar o <a href="https://en.wikipedia.org/wiki/Strategy_pattern">design pattern strategy</a>. Claro que, em algum ponto do código, você ainda precisará de um estojo de troca. Afinal de contas, <em>alguém</em> tem que decidir qual a implementação real a ser usada. Entretanto, esse ponto se torna o único ponto no código que precisa dessa estrutura de decisão.</p> + +<h3 id="4get-rid-of-duplicated-code-livre-se-do-código-duplicado">4.Get Rid of Duplicated Code (Livre-se do código duplicado)</h3> + +<h4 id="o-que-fazer-3">O que fazer?</h4> + +<p>Às vezes, você tem funções/métodos que fazem quase a mesma coisa. Manter ambos aumentam a complexidade ciclomática total de sua classe ou módulo. Se você pode limitar suas duplicatas, você pode limitar a complexidade.</p> + +<h4 id="como-fazer-1">Como fazer?</h4> + +<p>Remova as duplicatas de código por:</p> + +<ul> + <li>extraindo os bits de código comuns para seus próprios métodos/funções dedicados.</li> + <li>alavancando padrões de projeto - tais como <a href="https://en.wikipedia.org/wiki/Template_method_pattern">o design pattern template</a>- que incentivam a reutilização do código.</li> + <li>extraindo funções utilitárias genéricas em pacotes-gems, módulos npm, pacotes NuGet, etc. - que podem ser reutilizados por toda a organização.</li> +</ul> + +<h3 id="5remover-código-obsoleto">5.Remover Código Obsoleto</h3> + +<h4 id="o-que-fazer-4">O que fazer?</h4> + +<p>Há muitas razões pelas quais é uma boa idéia remover o código obsoleto, ou seja, o código morto de sua aplicação. Para nosso contexto, basta dizer que essa é uma forma “gratuita” de aumentar a cobertura de código e diminuir a complexidade ciclomática.</p> + +<h4 id="como-fazer-isso-2">Como fazer isso?</h4> + +<p>Basta usar uma ferramenta que lhe permita identificar o código morto - até mesmo sua IDE pode ser capaz de fazê-lo - e depois apagá-lo impiedosamente.</p> + +<h3 id="6não-reinvente-a-roda">6.Não Reinvente a Roda</h3> + +<h4 id="o-que-fazer-5">O que fazer?</h4> + +<p>Deixe o desenvolvedor que nunca escreveu uma função - ou mesmo alguns deles - realizar a formatação da data lançar a primeira pedra! É quase como um rito de passagem.</p> + +<p>Escrever código que simplesmente duplica a funcionalidade que a biblioteca padrão de seu idioma ou sua estrutura já oferece é uma maneira segura de aumentar desnecessariamente a complexidade. Se <a href="https://wiki.c2.com/?SoftwareAsLiability">código é uma responsabilidade</a>, você quer escrever apenas a quantidade estritamente necessária.</p> + +<h4 id="como-fazer-isso-3">Como fazer isso?</h4> + +<p>Implemente uma sólida estratégia de revisão de código que seja capaz de identificar e se livrar de tais reinvenções de roda.</p> + +<h2 id="reduzir-a-complexidade-ciclomática-aumentar-a-clareza-do-código">Reduzir a Complexidade Ciclomática, Aumentar a Clareza do Código</h2> + +<p>A complexidade ciclomática é uma das métricas mais valiosas na engenharia de software. Ela tem implicações importantes para a qualidade do código e a capacidade de manutenção, sem mencionar os testes. A alta complexidade ciclomática pode ser tanto um sinal de problemas existentes como um preditor de problemas futuros. Portanto, manter o valor desta métrica sob controle é certamente algo que você quer fazer se quiser alcançar uma base de código saudável. Mantê-lo sob controle é exatamente o que você aprendeu com nosso posto.</p> + +<p>Antes de separar os caminhos, uma última advertência. Tenha em mente que nenhuma métrica é uma panacéia quando usada isoladamente. Muitas vezes, o que você realmente gostaria de fazer é rastrear e melhorar um <a href="https://linearb.io/5-key-metrics-fix-your-software-teams-quality/">grupo de métricas</a> que, juntos, podem lhe dar uma visão geral da saúde de sua equipe e de seu projeto. Obrigado pela leitura.</p> + + Mon, 05 Apr 2021 00:00:00 +0000 + https://carlosschults.net/pt/reduzir-complexidade-ciclomatica/ + https://carlosschults.net/pt/reduzir-complexidade-ciclomatica/ + + boas-praticas + + testes-automatizados + + testes-unitarios + + testes-de-software + + engenharia-de-software + + + + + + Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1595528879/mutation/mutation-testing-1038x437.jpg" alt="" /></p> + +<p><span>Photo by <a href="https://unsplash.com/@wocintechchat?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Christina @ wocintechchat.com</a> on <a href="https://unsplash.com/s/photos/software-testing?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p> + +<p><em>NOTA: Este post foi originalmente escrito para o blog da NCrunch. Você pode ler o <a href="https://blog.ncrunch.net/post/mutation-testing-code-coverage.aspx">artigo original, em inglês, no site deles</a>.</em></p> + +<p>Sou fascinado com o conceito de testes de mutação desde que os conheci. Pensei finalmente ter encontrado a resposta para tantos problemas que tive ao escrever testes. Com os testes de mutação, agora eu tinha uma maneira de realmente confiar em meus testes. Finalmente, a cobertura de código tinha significado novamente.</p> + +<p>Então, fiquei atônito ao perceber que muito poucos desenvolvedores compartilhavam meu interesse em testes de mutação. Na verdade, ouso dizer que a maioria dos desenvolvedores ainda nem sequer ouviu falar sobre isso. E isso é uma pena porque eles - e nós, como uma indústria - estamos perdendo tantos benefícios.</p> + +<p>Portanto, este posto é minha humilde tentativa de remediar a situação. Vou começar por explicar os atuais dilemas que os desenvolvedores enfrentam em relação à confiabilidade dos testes que escrevem. Em seguida, vou prosseguir para lhe mostrar como os testes de mutação são a resposta a estes dilemas. Explicarei o que é, como pode tornar seus testes mais confiáveis, e como pode transformar a cobertura de código na valiosa métrica que deve ser.</p> + +<h2 id="o-problema-a-confiabilidade-dos-testes">O problema: a confiabilidade dos testes</h2> + +<p>Ao aprender sobre <a href="https://carlosschults.net/pt/testes-unitarios-iniciantes-parte1/">testes unitários</a> - ou testes automatizados em geral - a maioria das pessoas fará a mesma pergunta ou uma pergunta semelhante: Como sei que meus testes estão corretos? Essa é uma preocupação legítima. Se seus testes não são confiáveis, então talvez você esteja melhor sem nenhum teste.</p> + +<p>Então, qual é a resposta? Como as pessoas lidam com o problema da confiabilidade dos testes sem depender de testes de mutação?</p> + +<h2 id="tornando-os-testes-confiáveis-sem-testes-de-mutação">Tornando os testes confiáveis sem testes de mutação</h2> + +<p>Há técnicas que os desenvolvedores empregam para melhorar a confiabilidade de seus testes, e cobriremos brevemente algumas delas nesta seção. Se você tem experiência com testes unitários, provavelmente está familiarizado com essas técnicas. Vamos lá.</p> + +<h3 id="manter-os-testes-simples">Manter os testes simples</h3> + +<p>A primeira técnica que cobriremos aqui para melhorar a confiabilidade de seus testes é apenas mantê-los simples. E por “simples” quero dizer com menos complexidade ciclomática. Quanto menor a <a href="https://pt.wikipedia.org/wiki/Complexidade_ciclom%C3%A1tica">complexidade ciclomática</a> de um determinado código, mais provável é que ele realmente faz o que você pensa que faz. O código simples é mais fácil de entender, que é uma propriedade que você definitivamente quer que seus testes unitários tenham.</p> + +<p>Mantenha o código de teste simples ao ponto de ser óbvio. Isso significa, por exemplo, evitar loops ou estruturas de decisão. Além disso, evite fazer qualquer coisa para computar o resultado esperado (mais sobre isso na próxima seção). Em vez disso, codifique-o de maneira fixa.</p> + +<h3 id="não-duplique-o-código-de-implementação">Não Duplique o Código de Implementação</h3> + +<p>Digamos que você esteja praticando o <a href="https://codingdojo.org/kata/RomanNumerals/">Coding Kata dos números romanos</a>. Resista à tentação de gerar automaticamente os valores esperados (“I” para 1, “II” para 2, e assim por diante). Em vez disso, codifique os valores de forma fixa. Se a repetição realmente o incomoda e sua ferramenta de teste o permite, use testes parametrizados.</p> + +<p>Por que isso seria um problema? Simples: Quanto mais sofisticado for o código de teste, mais provável é que seja uma duplicação do código de produção. Se este for o caso, você pode ter o azar de se encontrar na situação em que seu código de produção está errado (não resolve o problema como deveria fazer), mas os testes passam. Esse é um dos piores cenários possíveis. É ainda pior do que não ter nenhum teste.</p> + +<h3 id="garanta-que-você-veja-o-teste-falhar">Garanta que você veja o teste falhar</h3> + +<p>Garantir que cada teste falhe pelo menos uma vez antes de ser aprovado. Se você vê o teste falhar quando acha que deveria estar falhando e vice-versa, isso é um sinal de que você está se movendo na direção certa. Não garante nada, mas diminui a probabilidade de o teste estar passando devido a uma coincidência.</p> + +<p>Como fazer isso? Assim que você chegar à fase verde, danifique o código de implementação de tal maneira que um ou mais testes devem falhar. Você poderia inverter os condicionantes, substituir strings ou literais numéricos por valores aleatórios, ou mesmo apagar um if. Se você conseguir sabotar o código de produção e se safar, isso não é um bom sinal. Seu conjunto de testes ou está errado ou incompleto. Em certo sentido, você está testando os testes.</p> + +<p>Desenvolvedores que empregam <a href="https://carlosschults.net/pt/testes-unitarios-csharp-intro-tdd/">TDD (desenvolvimento orientado a testes)</a> já fazem isso, por definição. Uma vez que você escreve um teste falho e depois procede para que ele seja aprovado, você está vendo o teste falhar. É claro, o teste deve falhar da maneira esperada. Isso significa que se você estiver realizando uma asserção, o teste deve falhar devido a uma falha na asserção e não, digamos, porque o método sob teste lança uma exceção. Sim, isto é melhor do que nada, mas ainda assim pode não ser suficiente. Como um teste unitário representa um caso de uso único, é totalmente possível introduzir um defeito no código de produção de tal forma que este teste em particular ainda passe.</p> + +<h2 id="temos-que-fazer-melhor-é-aí-que-entra-o-teste-de-mutação">Temos que fazer melhor: É Aí Que Entra o Teste de Mutação</h2> + +<p>Então, você acabou de aplicar a técnica descrita na última seção. Ótimo! Não é perfeita, porém. Aí vem um problema. Você não pode simplesmente inserir muitos defeitos e executar os testes, pois não seria capaz de identificar qual defeito foi responsável pelo fracasso dos testes. A maneira correta de fazer isso é inserir um único defeito deliberado, executar todos os testes, verificar seu resultado e <em>então</em> reverter a mudança. Depois disso, você pode introduzir outro erro, executar todos os testes novamente, verificar o resultado, reverter a mudança…e repetir, muitas vezes. Nem precisa dizer que tal abordagem é extremamente lenta, entediante e propensa a erros.</p> + +<p>É aí que entram os testes de mutação.</p> + +<h3 id="o-que-é-teste-de-mutação-afinal">O que é teste de mutação, afinal?</h3> + +<p>O teste de mutação é nada mais, nada menos, do que automatizar todo o processo de “sabotar o código de produção e executar testes para ver se eles falham” que você acabou de ver. Para usar o teste de mutação, você precisa de um framework, ou ferramenta, de teste de mutação. O framework irá alterar o código de produção, introduzindo defeitos que são chamados de “mutações”. Para cada mutação introduzida, o framework executará novamente o conjunto de testes unitários. Se todos os testes forem aprovados, dizemos que a mutação sobreviveu. Isso é uma coisa ruim. Significa que ou seu conjunto de testes está faltando ou os testes existentes estão errados.</p> + +<p>Se, por outro lado, um ou mais testes falharem, isso significa que a mutação foi morta, o que é uma coisa boa. A ferramenta repetirá esse processo até que se teste a parte relevante da base de código. Quando tudo estiver feito, você poderá verificar os resultados, que conterão o número de mutações introduzidas, assim como a proporção de mutantes sobreviventes vs. mutantes mortos.</p> + +<h3 id="os-testes-de-mutação-melhoram-a-cobertura-do-código">Os testes de mutação melhoram a cobertura do código</h3> + +<p>Um dos tópicos mais controversos no mundo dos testes de unidade é o argumento sobre a cobertura de código. Alguns desenvolvedores dizem que chegar à cobertura total é essencial; outros argumentarão que é uma métrica inútil. Quem está certo?</p> + +<p>Primeiro de tudo, é preciso entender que esta questão não é preto no branco. Como é o caso de praticamente tudo em software, há alguma nuance. É claro que a cobertura de código não é inútil. Saber que sua base de código tem, digamos, 10% de cobertura de teste é definitivamente um dado útil. Tal cobertura é muito baixa: ver a barra verde não lhes oferecerá nenhuma confiança. Isso não quer dizer que ter 100% de cobertura é necessariamente uma coisa boa em si mesmo. Você poderia ter testes que não têm afirmações, por exemplo. Sim, este é um exemplo elaborado, mas algo assim poderia (e às vezes acontece) acontecer.</p> + +<p>Uma ocorrência mais comum seria ter apenas testes que não exercitam suficientemente os caminhos no software. Em resumo: baixa cobertura de código é definitivamente uma coisa ruim, mas alta (ou total) cobertura de código não é <em>necessariamente</em> uma coisa boa, uma vez que não diz nada sobre a qualidade dos testes na suíte.</p> + +<p>Como os testes de mutação verificam a qualidade da suíte de testes, é a peça que falta no quebra-cabeça. Se sua base de código tem uma alta cobertura de código e os resultados dos testes de mutação mostram que a maioria ou todas as mutações introduzidas estão sendo mortas, então sorria! Você provavelmente tem uma ótima suíte de teste no lugar!</p> + +<h2 id="testes-de-mutação-abrace-hoje">Testes de Mutação Abrace Hoje</h2> + +<p>No post de hoje, falamos sobre o problema da confiabilidade dos testes, depois procedemos a uma revisão de algumas técnicas e diretrizes que você pode usar para superar esse desafio. Finalmente, vimos como o teste de mutação é a abordagem superior para resolver esse problema.</p> + +<p>Eis o seguinte: As técnicas que abordamos são boas diretrizes a serem seguidas ao escrever testes unitários. Seus testes serão beneficiados por cumpri-los, quer você empregue ou não testes de mutação. Mas as diretrizes só podem levá-lo até agora. Elas dependem muito da força de vontade e disciplina humanas, e todos nós temos quantidades limitadas delas. A fim de levar a qualidade de seus testes ao próximo nível, você precisa adotar a automação.</p> + +<p>São necessários apenas alguns minutos de pesquisa no Google para encontrar uma ferramenta de teste de mutação para a plataforma de sua preferência. Faça isso hoje e comece a aproveitar os benefícios que os testes de mutação podem oferecer a você e à sua equipe!</p> + + + Thu, 23 Jul 2020 00:00:00 +0000 + https://carlosschults.net/pt/testes-de-mutacao/ + https://carlosschults.net/pt/testes-de-mutacao/ + + testes-de-software + + testes-unitarios + + testes-automatizados + + cobertura-de-codigo + + testes-de-mutacao + + tdd + + + + + + Testes Unitários em C#: Iniciando Com TDD + <p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1459979937/testes-unitarios-iniciantes-min_povcse.png" alt="" /></p> + +<p><em>Este post faz parte de uma série. <a href="http://carlosschults.net/tag_ptbr/serie-testes-unitarios/">Veja os outros artigos.</a></em></p> + +<p>Hoje eu trago outro post para ajudá-los a começar com os testes da unidade C#. Já cobri o <a href="https://carlosschults.net/pt/testes-unitarios-iniciantes-parte1">básico de testes unitários</a>, explicando o que eles são e por que são tão importantes. Depois disso, mostrei <a href="https://carlosschults.net/pt/testes-unitarios-iniciantes-parte-2">como começar com os testes unitários</a> com um exemplo prático. Hoje, vamos um passo adiante, explorando a metodologia TDD.</p> + +<p>Você provavelmente já ouviu falar de TDD, mas pode ficar confuso quanto ao que é. A propósito, isto não é culpa sua. Há muitos equívocos em torno desta sigla. Algumas pessoas até a usam de forma intercambiável com os testes unitários. Neste post, você vai aprender por que eles estão errados, e mais.</p> + +<p>Começamos o post com uma breve definição de TDD. Você aprenderá não apenas que TDD significa Desenvolvimento Orientado por Testes, mas também que não é uma técnica de teste, apesar do nome. Depois disso, eu explico o que é TDD e quais são seus benefícios.</p> + +<p>Após o “o quê” e o “porquê” estarem ambos fora do nosso caminho, estaremos prontos para nos divertir um pouco. Vou lhes mostrar, na prática, como começar com a TDD, desenvolvendo uma solução para um famoso exercício de programação. Soa bem? Então, vamos começar.</p> + +<h2 id="testes-unitários-em-c--tdd-começando-pelo-básico">Testes Unitários em C# &amp; TDD: Começando Pelo Básico</h2> + +<p>Já mencionei anteriormente que o TDD não é uma técnica de teste. Mas o que é isso? E como está relacionado ao teste de unidade C# (ou teste de unidade em geral, já agora?)</p> + +<h3 id="definindo-tdd">Definindo TDD</h3> + +<p>Como você já viu, TDD significa “Test-Driven Development”, ou “Desenvolvimento guiado por testes.” É uma técnica ou metodologia de desenvolvimento de software que utiliza testes unitários para guiar ou dirigir o desenvolvimento da aplicação.</p> + +<p>Em vez de fazer a coisa mais intuitiva, que seria escrever testes unitários após o código de produção, a metodologia TDD afirma que você deve começar escrevendo um teste unitário falho. Depois você escreve o código de produção, mas apenas o necessário para que o teste seja aprovado.</p> + +<p>Acho que agora você está se perguntando pelo menos duas coisas:</p> + +<ul> + <li>Como isso funciona na prática?</li> + <li>Por que escrever o código de uma maneira tão estranha?</li> +</ul> + +<p>É o que vamos ver a seguir.</p> + +<h3 id="as-fases-do-tdd">As fases do TDD</h3> + +<p>O desenvolvimento orientado por testes depende da repetição de um ciclo incrivelmente curto. Este ciclo é composto de três fases:</p> + +<ol> + <li>Primeiro, você escreve um teste que representa um requisito específico da funcionalidade que você está tentando implementar.</li> + <li>Em seguida, você faz o teste passar, escrevendo a quantidade mínima de código de produção com a qual você pode escapar.</li> + <li>Se necessário, você refatoria o código para eliminar duplicações ou outros problemas.</li> +</ol> + +<p>Como a funcionalidade ainda não existe, o teste que você escreve no passo nº 1 falhará. Ou seja, em linguagens como Python ou Ruby. No caso de linguagens estaticamente digitadas, como Java ou C#, o código nem sequer será compilado. Para nossos propósitos, a não compilação do código conta como falha no teste.</p> + +<p>No passo 2, você tem que fazer o teste passar, mas nada além disso. O que eu quero dizer é que seu objetivo aqui não é resolver o problema, pelo menos ainda não. Ao invés disso, seu único trabalho é fazer o teste passar, escrevendo a menor quantidade possível de código. Fazer batota - por exemplo, devolver um valor codificado - não só é OK, mas encorajado, como você logo verá.</p> + +<p>Finalmente, a terceira fase é a única que permite a você escrever o código de produção sem ter que criar primeiro um teste de reprovação. Mas você não pode criar novas classes ou funções; você só pode refatorar o código que você escreveu na etapa anterior, para torná-lo mais legível, para eliminar a duplicação ou para resolver outro problema. E, é claro, o teste ainda deve ser aprovado.</p> + +<p>As pessoas freqüentemente usam o TDD como “red green-refactor” porque a maioria das ferramentas de teste de unidade usa vermelho para denotar testes fracassados e verde para passar nos testes.</p> + +<h3 id="por-que-usar-o-tdd">Por que usar o TDD?</h3> + +<p>O difícil de entender quando se começa a usar o TDD não é o como. O “como” é trivial: escrever um teste, faze-lo passar, talvez refatorar, enxaguar, repetir. A parte preocupante é o “por quê”. Por que desenvolver software de uma maneira tão não-intuitiva?</p> + +<p>Vou falar mais sobre a filosofia TDD em artigos futuros. Em poucas palavras, aplicar TDD garante que você terá um código testável desde o início. Ele o incentivará a projetar seu código de uma maneira simples e modular.</p> + +<p>Mas talvez a principal vantagem do TDD seja aumentar a confiança do desenvolvedor em seu código. Ao desenvolver um pequeno passo de cada vez, você nunca será capaz de errar muito, já que está fazendo muito pouco. Saber que você está apenas a um teste de reprovação de ter um código de trabalho é reconfortante.</p> + +<h2 id="testes-unitários-em-c--tdd-o-guia-mão-na-massa">Testes Unitários em C# &amp; TDD: O Guia Mão-Na-Massa</h2> + +<p>Eu cobri como começar com os testes de unidade C# no passado. Eu também cobri as ferramentas necessárias e como começar. Entretanto, não vou assumir que você tenha lido esses artigos. Em vez disso, vou cobrir tudo a partir do zero. Assim, você será capaz de seguir o tutorial mesmo que tenha zero de experiência com testes unitários.</p> + +<h3 id="nosso-problema-o-kata-string-calculator">Nosso problema: O Kata String Calculator</h3> + +<p>Para nosso tutorial, escreveremos uma solução para o <a href="https://osherove.com/tdd-kata-1">coding kata String Calculator</a>, idealizado pelo Roy Osherov. Um kata de codificação é um exercício de programação, destinado a permitir que os desenvolvedores pratiquem práticas de engenharia de software ágeis fundamentais, como a refatoração, e - você adivinhou - TDD.</p> + +<p>Para simplificar, vou ignorar algumas das exigências do kata. O que se segue são as exigências que vamos utilizar:</p> + +<ol> + <li>Vamos criar uma classe chamada StringCalculator, com um único método estático com a assinatura estática int Add(string numbers);</li> + <li>O método pega uma string representando números separados por uma vírgula, e retorna sua soma.</li> + <li>Se passarmos uma string vazia, o método deve retornar zero.</li> + <li>A passagem de um único número deve resultar no próprio número.</li> + <li>Se passarmos números negativos, o método deve lançar uma ArgumentException, com a mensagem “Números negativos não permitidos:” seguida dos negativos que foram especificados.</li> + <li>O método deve ignorar números maiores que 1000 devem. Portanto, “1.2.1000” deve resultar em 1003, mas “1.2.1001” deve resultar em 3.</li> +</ol> + +<h3 id="criando-o-projeto-de-produção">Criando o Projeto de Produção</h3> + +<p>Para este tutorial, estarei usando a edição comunitária do Visual Studio 2019. Se você ainda não o tem, pode baixá-lo e instalá-lo de graça.</p> + +<p>Abra o VS e clique em “Criar um novo projeto”, como na imagem a seguir:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/img1.png" alt="" /></p> + +<p>Na janela aberta, escolha Biblioteca de Classes (.NET Core) como modelo para o novo projeto. Em seguida, clique em “Next” (Próximo):</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/img2.png" alt="" /></p> + +<p>A tela seguinte simplesmente pede um nome para o projeto e a solução. Eu escolhi” StringCalculatorKata” tanto para o projeto quanto para a solução. Você também terá que fornecer um local para salvar os arquivos do projeto. Quando terminar, basta clicar em “Criar”.</p> + +<p>Se tudo correr bem, você deverá ver a classe padrão aberta para você no Visual Studio. Vá ao Solution Explorer e exclua essa classe; não vamos precisar dela.</p> + +<h3 id="criando-o-projeto-de-teste">Criando o Projeto de Teste</h3> + +<p>Agora, é hora de criar o projeto de teste. Poderíamos fazer isso de duas maneiras: criando um projeto regular de “Biblioteca de Classe” e depois adicionando as dependências necessárias a ele, ou criando um projeto de teste de unidade imediatamente. Iremos com este último, já que facilita tudo isso.</p> + +<p>Você conhece o procedimento: clique com o botão direito do mouse na solução, vá para “Adicionar”,depois para “Novo Projeto…”. Em seguida, escolha o modelo “NUnit Test Project (.NET Core)”.</p> + +<p>Em seguida, você deverá fornecer um nome e um local para o projeto. Gosto de seguir a convenção de nomear o projeto de teste após o projeto de produção, com um “.Test” adicionado. Portanto, escolho “StringCalculatorKata.Test”. Terminar a criação do projeto.</p> + +<p>Se tudo correr bem, você deve ver agora uma nova classe que se parece com esta:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Tests</span> +<span class="p">{</span> + <span class="p">[</span><span class="n">SetUp</span><span class="p">]</span> + <span class="k">public</span> <span class="k">void</span> <span class="nf">Setup</span><span class="p">()</span> + <span class="p">{</span> + <span class="p">}</span> + + <span class="p">[</span><span class="n">Test</span><span class="p">]</span> + <span class="k">public</span> <span class="k">void</span> <span class="nf">Test1</span><span class="p">()</span> + <span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">Pass</span><span class="p">();</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Vamos fazer algumas coisas. Primeiro, livre-se do método <code class="language-plaintext highlighter-rouge">Setup()</code>. Não vamos precisar dele. Depois, acrescente um novo método com o código abaixo:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Test2</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">Fail</span><span class="p">();</span> +<span class="p">}</span></code></pre></figure> + +<p>Portanto, agora temos dois testes, um que deve passar e outro que deve falhar. Vamos examiná-los para ver se eles estão funcionando corretamente. Vá ao menu “Executar” e clique em “Executar todos os testes”.</p> + +<p>Agora, abra a janela Test Explorer (View -&gt; Test Explorer). Deve ser parecido com isto:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/tests-running.png" alt="" /></p> + +<p>Parece que tudo está funcionando bem! Mas antes de começarmos a fazer nosso exercício de codificação do kata, há dois passos finais que precisamos dar. Primeiro, vamos renomear a classe de teste. Ir para o explorador de soluções, expandir o projeto de teste de unidade, e excluir sua classe de teste padrão. Depois, clique com o botão direito do mouse no projeto de teste, vá para “Adicionar”, depois para “Nova classe…” e adicione uma nova classe chamada “StringCalculatorKata”. Alternativamente, você pode renomear a classe existente.</p> + +<p>A segunda coisa que temos que fazer é garantir que nosso projeto de teste possa ver nosso projeto de produção. Para resolver isso, estamos acrescentando uma referência.</p> + +<p>Vá até o explorador de soluções novamente, clique com o botão direito do mouse no projeto de teste, depois vá até “Adicionar” e clique em “Referência…”.</p> + +<p>Na nova janela, selecione “Projetos” no painel esquerdo, e depois selecione o projeto StringCalculatorKata, que deve ser o único disponível:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594235427/unit3/add-reference.png" alt="" /></p> + +<p>Depois, basta clicar em “OK”, e agora você está pronto para continuar.</p> + +<h2 id="iniciando-nosso-kata-de-codificação">Iniciando nosso Kata de Codificação</h2> + +<p>Agora, estamos prontos para escrever nosso primeiro teste de reprovação. Portanto, abra a classe StringCalculatorTest e acrescente a ela o seguinte método</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_EmptyStringAsParam_ReturnsZero</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Em nosso primeiro caso de teste, testamos o cenário mais simples possível. Ou seja, chamamos o método Add de passar uma string vazia, que, de acordo com os requisitos que você viu antes, deve resultar em 0. É claro que nem o método Add nem a classe StringCalculator existem, portanto nosso código nem sequer é compilado. Bem, parabéns! Você realizou com sucesso o primeiro passo no ciclo vermelho-verde-refator, escrevendo um teste de reprovação! Lembre-se: em idiomas estaticamente digitados como C#, a falha em compilar conta como um teste reprovado.</p> + +<p>Portanto, nosso primeiro passo é nos livrarmos do erro de compilação. Se você pairar sobre “StringCalculator”, você deve ver um pequeno pop-up explicando o erro e oferecendo possíveis correções:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594238110/unit3/hover-tip.png" alt="" /></p> + +<p>Clique em “Mostrar correções potenciais” e depois em “Gerar novo tipo…”. Você deve então ver uma janela solicitando os detalhes e a localização do novo tipo. Mude o “acesso” para “público” e a localização para o projeto de produção, que é “StringCalculatorKata”. A janela deve ser parecida com esta:</p> + +<p><img src="https://res.cloudinary.com/dz5ppacuo/image/upload/v1594238213/unit3/create-production-class.png" alt="" /></p> + +<p>Clique em “OK”. Agora, se você abrir o explorador de soluções e expandir o projeto StringCalculatorKata, você deve ver a classe StringCalculator.cs à espreita por lá. Legal.</p> + +<p>Entretanto, nosso código ainda não está compilado. E isso porque, apesar de termos criado a classe de produção, não adicionamos o método Add a ela. Então, vamos fazer da mesma forma que fizemos com a classe.</p> + +<p>Passe o mouse sobre a palavra “Adicionar” até que a ajuda apareça com a mensagem “’ StringCalculator’ não contém uma definição para ‘Adicionar’”. Clique em Mostrar correções potenciais, e depois clique em “Gerar método ‘StringCalculator.Add’”.</p> + +<p>Você verá que a classe de produção agora contém um método chamado Add, com o dobro como um tipo de retorno. Queremos que o método retorne int, então vamos mudar isso. Vamos também mudar o nome do parâmetro para “números” para corresponder aos requisitos do kata de codificação. Neste ponto, sua classe StringCalculator completa deve ser parecida com esta:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">StringCalculator</span> +<span class="p">{</span> + <span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotImplementedException</span><span class="p">();</span> + <span class="p">}</span> +<span class="p">}</span></code></pre></figure> + +<p>Agora seu código deve ser compilado. Faça o teste novamente, e você verá que ele falha, com uma mensagem como esta:</p> + +<pre> +Add_EmptyStringAsParam_ReturnsZero + Source: StringCalculatorTest.cs line 8 + Duration: 43 ms + + Message: + System.NotImplementedException : The method or operation is not implemented. + Stack Trace: + StringCalculator.Add(String numbers) line 9 + StringCalculatorTest.Add_EmptyStringAsParam_ReturnsZero() line 10 + +</pre> + +<p>Temos uma falha de teste verdadeira. Estamos prontos para escrever o código de produção? Não tão rápido. Claro, nosso teste falha, mas falha da maneira errada. Como nosso teste contém uma asserção, esperávamos uma asserção fracassada. Em vez disso, o que temos é uma falha devido ao método em teste, lançando uma exceção.</p> + +<p>A correção aqui é simples. Vamos apenas mudar o método Add, para que ele retorne qualquer número diferente de zero:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">-</span><span class="m">1</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Agora, faça o teste novamente, e você verá que a mensagem de erro é esta:</p> + +<pre> +Add_EmptyStringAsParam_ReturnsZero + Source: StringCalculatorTest.cs line 8 + Duration: 76 ms + + Message: + Expected: 0 + But was: -1 +</pre> + +<h3 id="fazendo-o-teste-passar">Fazendo o teste passar</h3> + +<p>Estamos agora finalmente prontos para fazer o teste passar. Como disse anteriormente, para passar no teste, você não só é permitido, mas também encorajado a fazer batota. Em nosso caso, podemos simplesmente fazer com que o método Add retorne zero:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="escrevendo-o-segundo-teste-um-único-número">Escrevendo o segundo teste: Um único número</h3> + +<p>Os requisitos dizem que a passagem de um único número deve retornar o próprio número. Isso soa como uma coisa útil para testar:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_StringContainingSingleNumber_ReturnsTheNumberItself</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"5"</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>O teste falha com a seguinte mensagem:</p> + +<pre> +Add_StringContainingSingleNumber_ReturnsTheNumberItself + Source: StringCalculatorTest.cs line 14 + Duration: 56 ms + + Message: + Expected: 5 + But was: 0 + +</pre> + +<p>Como podemos fazer o teste acima passar da maneira mais preguiçosa possível? Que tal assim?</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="testando-dois-números">Testando Dois Números</h3> + +<p>Como já testamos o método Add passando por números zero (uma seqüência vazia) e um único número, parece que o próximo passo natural para nós agora seria escrever um teste para o cenário de adição de dois números. Então, vamos fazer exatamente isso.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_TwoNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">()</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">numbers</span> <span class="p">=</span> <span class="s">"7,8"</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">expectedResult</span> <span class="p">=</span> <span class="m">15</span><span class="p">;</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">expectedResult</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>O teste acima naturalmente falha uma vez que nosso método atualmente retorna 0 quando recebe um fio vazio e cinco de outra forma. Como podemos mudá-lo, para que este novo teste passe, os testes mais antigos continuem a passar, de uma forma que não resolve o problema em geral?</p> + +<p>Esta é uma idéia:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<h3 id="testando-três-números">Testando Três Números</h3> + +<p>Você já notou que, até agora, não fizemos nenhuma refatoração? Bem, estamos nos aproximando do ponto em que nossos testes nos levam a incluir alguma duplicação desagradável em nosso código. Então, usaremos a refatoração para alterar o código de uma forma que se aproxime de uma solução geral.</p> + +<p>Vamos ver se podemos fazer isso testando o cenário com três números:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="n">Test</span><span class="p">]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_ThreeNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">()</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">numbers</span> <span class="p">=</span> <span class="s">"1, 2, 3"</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">expected</span> <span class="p">=</span> <span class="m">6</span><span class="p">;</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>O teste naturalmente falhará. Como a corda fornecida contém vírgulas, caímos no ramo condicional que retorna 15. Nosso desafio agora é mudar o método de produção de forma a fazer este teste passar. Podemos fazê-lo sem ir à solução geral do problema? Vamos ver.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span> + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="s">"1, 2, 3"</span><span class="p">)</span> + <span class="k">return</span> <span class="m">6</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="k">return</span> <span class="m">5</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Comparando o parâmetro especificado com a entrada exata usada no teste, podemos fazer o teste passar, evitando ir para a solução geral. Entretanto, agora conseguimos criar uma duplicação de código. Você consegue ver isso? Estamos fazendo duas comparações contra o valor dos números, uma logo após a outra. Vamos ver se conseguimos nos livrar dessa duplicação.</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span> <span class="p">==</span> <span class="s">"1, 2, 3"</span><span class="p">)</span> + <span class="k">return</span> <span class="m">6</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="sc">','</span><span class="p">))</span> + <span class="k">return</span> <span class="m">15</span><span class="p">;</span> + + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="n">outint</span> <span class="n">result</span><span class="p">);</span> + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Aproveitando o método <code class="language-plaintext highlighter-rouge">TryParse</code> do tipo <code class="language-plaintext highlighter-rouge">System.Int32</code>, consegui me livrar do primeiro if. Também usamos um recurso introduzido no <a href="https://carlosschults.net/pt/funcionalidades-csharp-7/">C# 7</a> chamado “out variables”. Este recurso nos permite utilizar parâmetros sem ter que declará-los previamente.</p> + +<p>Todos os testes ainda passam, portanto, não posso escrever mais código de produção. Qual deve ser o próximo teste?</p> + +<h3 id="testando-mais-de-três-números">Testando Mais de Três Números</h3> + +<p>Os requisitos não dizem que devemos ser capazes de lidar apenas com três números. Portanto, vamos criar outro caso de teste para cobrir os cenários com 4, 5, ou mais números. Já que estamos nisso, podemos também incluir a exigência de ignorar números maiores que 1000.</p> + +<p>Para fazer isso sem ter que criar muitos métodos de teste, vamos aproveitar o recurso NUnit [testes parametrizados] (https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html), adicionando um único método com vários casos de teste:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"1,2,3,4"</span><span class="p">,</span> <span class="m">10</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"8,7,20"</span><span class="p">,</span> <span class="m">35</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,0,4,1001"</span><span class="p">,</span> <span class="m">9</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,0,4,1000"</span><span class="p">,</span> <span class="m">1009</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"26,6,90"</span><span class="p">,</span> <span class="m">122</span><span class="p">)]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_MoreThanThreeNumbersSeparatedByComma_ReturnsTheirSum</span><span class="p">(</span> + <span class="kt">string</span> <span class="n">input</span><span class="p">,</span> <span class="kt">int</span> <span class="n">result</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="nf">AreEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">input</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Observe que o terceiro caso de teste exemplifica a exigência que diz que devemos ignorar números superiores a 1000. O próximo caso de teste, no entanto, mostra que 1000 não deve ser ignorado. Se você executar os testes, verá que o test explorer mostra cada caso de teste como um teste distinto.</p> + +<p>Como podemos fazer este teste passar? Honestamente, a essa altura, é muito mais fácil ir para a implementação correta do que trapacear. Então, vamos fazer exatamente isso:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">parts</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> + + <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">part</span> <span class="k">in</span> <span class="n">parts</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">outint</span> <span class="n">number</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;=</span> <span class="m">1000</span><span class="p">)</span> + <span class="n">result</span> <span class="p">+=</span> <span class="n">number</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>O código acima deve ser fácil de entender. Nós apenas dividimos o fio em partes usando a vírgula como delimitador. Então, para cada parte, nós a dividimos em um inteiro, verificamos se é igual ou inferior a mil e, se for o caso, adicionamo-la à variável de resultado. Finalmente, retornamos o resultado.</p> + +<h2 id="ainda-não-terminamos">Ainda não terminamos</h2> + +<p>Os requisitos dizem que números negativos não devem ser permitidos. Vamos acrescentar um teste para isso! Por uma questão de brevidade, acrescentaremos um único método de teste com vários casos de teste, de modo que somos forçados a ir imediatamente para a implementação correta:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"1,2,3,4,5,-5"</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"-1,1,2,9"</span><span class="p">)]</span> +<span class="p">[</span><span class="nf">TestCase</span><span class="p">(</span><span class="s">"5,6,8,-5"</span><span class="p">)]</span> +<span class="k">public</span> <span class="k">void</span> <span class="nf">Add_StringContainingNegativeNumbers_Throws</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">Assert</span><span class="p">.</span><span class="n">Throws</span><span class="p">&lt;</span><span class="n">ArgumentException</span><span class="p">&gt;(()</span> <span class="p">=&gt;</span> <span class="n">StringCalculator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">numbers</span><span class="p">));</span> +<span class="p">}</span></code></pre></figure> + +<p>Para este teste, afirmamos que não estamos contra um valor de retorno. Ao invés disso, estamos verificando se o método em teste abre uma exceção.</p> + +<p>Lembre-se que os requisitos dizem que devemos lançar uma exceção com uma mensagem dizendo que os negativos não são permitidos. Devemos também incluir uma lista dos negativos que foram aprovados. Isto exigirá algumas mudanças em nosso método:</p> + +<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Add</span><span class="p">(</span><span class="kt">string</span> <span class="n">numbers</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">var</span> <span class="n">parts</span> <span class="p">=</span> <span class="n">numbers</span><span class="p">.</span><span class="nf">Split</span><span class="p">(</span><span class="sc">','</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> + <span class="kt">var</span> <span class="n">negatives</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;();</span> + + <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">part</span> <span class="k">in</span> <span class="n">parts</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">int</span><span class="p">.</span><span class="nf">TryParse</span><span class="p">(</span><span class="n">part</span><span class="p">,</span> <span class="n">outint</span> <span class="n">number</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;</span> <span class="m">0</span><span class="p">)</span> + <span class="n">negatives</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">number</span><span class="p">);</span> + <span class="nf">elseif</span> <span class="p">(</span><span class="n">number</span> <span class="p">&lt;=</span> <span class="m">1000</span><span class="p">)</span> + <span class="n">result</span> <span class="p">+=</span> <span class="n">number</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">negatives</span><span class="p">.</span><span class="n">Count</span> <span class="p">&gt;</span> <span class="m">0</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">var</span> <span class="n">negativesList</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="sc">','</span><span class="p">,</span> <span class="n">negatives</span><span class="p">);</span> + <span class="kt">var</span> <span class="n">exceptionMessage</span> <span class="p">=</span> <span class="s">$"Negative numbers not allowed: </span><span class="p">{</span><span class="n">negativesList</span><span class="p">}</span><span class="s">."</span><span class="p">;</span> + <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span><span class="n">exceptionMessage</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">result</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +<p>Como você pode ver, logo no início, nós definimos uma instância de <code class="language-plaintext highlighter-rouge">List&lt;int&gt;</code> para armazenar os negativos que encontramos enquanto iteramos sobre todos os números. Dentro do laço, verificamos se o número atual é negativo. Se for, adicionamo-lo à lista. Se não for, verificamos se é menor ou igual a 1000, caso em que o adicionamos à variável de resultado.</p> + +<p>Após o loop, verificamos se a lista negativa tem algum elemento. Se tiver, criamos uma mensagem de exceção que inclui os negativos especificados e, em seguida, lançamos uma nova ArgumentException. Caso contrário, devolvemos o resultado.</p> + +<h2 id="conclusão">Conclusão</h2> + +<p>Este post foi um guia prático sobre como começar com o TDD em C#. Então, para onde você vai a partir daqui?</p> + +<p>Bem, a maioria das coisas na vida você aprende fazendo. A programação é certamente uma dessas coisas. Portanto, se você quer que os conceitos que você viu hoje realmente se afundem, você tem que praticar.</p> + +<p>O código que escrevi durante este post está disponível como <a href="https://github.com/carlosschults/string-calculator-kata">um repositório público no GitHub.</a> Vá lá, clone-o usando <a href="https://carlosschults.net/pt/basicos-do-git-usuarios-tfvc">Git,</a>, e comece a brincar com ele.</p> + +<p>Você verá que eu criei um compromisso para cada etapa do ciclo TDD. Dessa forma, torna-se mais fácil para os futuros leitores visualizar todas as etapas do processo, percorrendo a história do projeto, um compromisso de cada vez.</p> + +<p>É possível melhorar o código que eu usei hoje. Por exemplo, o código do método <code class="language-plaintext highlighter-rouge">Add</code> pode ser escrito de uma forma mais curta, clara e eficiente, usando <a href="https://carlosschults.net/pt/programacao-funcional-csharp/.">LINQ</a> Você pode criar mais testes. Os requisitos do exercício que apresentamos no início pedem por uma mensagem de erro específica ao lançar a exceção quando há números negativos na string. Apesar de termos implementado a mensagem como pedido, nós não criamos um teste pra isso. Você pode fazer isso, como forma de praticar.</p> + +<p>Finalmente, fique atento a este blog. Este post é parte de uma série, à qual pretendo acrescentar mais partes.</p> + +<p>Obrigado pela leitura, e até a próxima!</p> + + Wed, 08 Jul 2020 00:00:00 +0000 + https://carlosschults.net/pt/testes-unitarios-csharp-intro-tdd/ + https://carlosschults.net/pt/testes-unitarios-csharp-intro-tdd/ + + csharp + + iniciantes + + testes-de-software + + testes-unitarios + + testes-automatizados + + csharp + + metodologias-ageis + + serie-testes-unitarios + + + + + + diff --git a/search/index.html b/search/index.html new file mode 100644 index 00000000..270ce69d --- /dev/null +++ b/search/index.html @@ -0,0 +1,176 @@ + + + + + + + + Search | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+
+ +
+

Search

+
+ +
+ + + + +
+ +
+ +
+
+ + + + + + + + diff --git a/sitemaps.xml b/sitemaps.xml new file mode 100644 index 00000000..f89c8d12 --- /dev/null +++ b/sitemaps.xml @@ -0,0 +1,3378 @@ + + + + + + /pt/configuracao-dotnet + + + + + 2024-07-23T00:00:00+00:00 + weekly + + + + + + /en/csharp-regex + + + + + + + 2024-05-07T00:00:00+00:00 + weekly + + + + + + /pt/csharp-expressoes-regulares + + + + + + + 2024-05-07T00:00:00+00:00 + weekly + + + + + + /pt/git-criar-branch + + + + + + + 2024-02-21T00:00:00+00:00 + weekly + + + + + + /en/git-create-branch + + + + + + + 2024-02-21T00:00:00+00:00 + weekly + + + + + + /pt/operador-linq-join + + + + + + + 2024-02-06T00:00:00+00:00 + weekly + + + + + + /en/linq-join-operator + + + + + + + 2024-02-06T00:00:00+00:00 + weekly + + + + + + /pt/git-bisect-intro/ + + + + + + + 2024-01-22T00:00:00+00:00 + weekly + + + + + + /git-bisect-intro/ + + + + + + + 2024-01-22T00:00:00+00:00 + weekly + + + + + + /en/fivel-levels-readable-code/ + + + + + + + 2023-10-18T00:00:00+00:00 + weekly + + + + + + /pt/cinco-niveis-codigo-legivel + + + + + + + 2023-10-18T00:00:00+00:00 + weekly + + + + + + /en/git-beautiful-history/ + + + + + + + 2023-01-17T00:00:00+00:00 + weekly + + + + + + /pt/git-historico-bonito/ + + + + + + + 2023-01-17T00:00:00+00:00 + weekly + + + + + + /pt/reduzir-complexidade-ciclomatica/ + + + + + + + 2021-04-05T00:00:00+00:00 + weekly + + + + + + /en/reduce-cyclomatic-complexity/ + + + + + + + 2021-04-05T00:00:00+00:00 + weekly + + + + + + /pt/testes-de-mutacao/ + + + + + + + 2020-07-23T00:00:00+00:00 + weekly + + + + + + /en/mutation-testing/ + + + + + + + 2020-07-23T00:00:00+00:00 + weekly + + + + + + /en/csharp-unit-testing-intro-tdd/ + + + + + + + 2020-07-08T00:00:00+00:00 + weekly + + + + + + /pt/testes-unitarios-csharp-intro-tdd/ + + + + + + + 2020-07-08T00:00:00+00:00 + weekly + + + + + + /pt/null-problematico + + + + + + + 2020-07-02T00:00:00+00:00 + weekly + + + + + + /en/null-is-evil + + + + + + + 2020-07-02T00:00:00+00:00 + weekly + + + + + + /en/sharpen-the-saw/ + + + + + + + 2020-06-16T00:00:00+00:00 + weekly + + + + + + /pt/afiando-a-serra/ + + + + + + + 2020-06-16T00:00:00+00:00 + weekly + + + + + + /pt/programacao-funcional-csharp/ + + + + + + + 2019-01-22T00:00:00+00:00 + weekly + + + + + + /en/functional-programming-csharp/ + + + + + + + 2019-01-22T00:00:00+00:00 + weekly + + + + + + /en/value-objects-tool/ + + + + + + + 2018-10-24T00:00:00+00:00 + weekly + + + + + + /pt/value-objects-ferramenta/ + + + + + + + 2018-10-24T00:00:00+00:00 + weekly + + + + + + /en/coding-best-practices-short-time/ + + + + + + + 2018-10-16T00:00:00+00:00 + weekly + + + + + + /pt/boas-praticas-sem-tempo/ + + + + + + + 2018-10-16T00:00:00+00:00 + weekly + + + + + + /pt/4-erros-comuns-datetime-csharp/ + + + + + + + 2018-07-11T00:00:00+00:00 + weekly + + + + + + /en/4-common-datetime-mistakes-csharp/ + + + + + + + 2018-07-11T00:00:00+00:00 + weekly + + + + + + /pt/revisao-codigo-vs-programacao-em-par/ + + + + + + + 2018-01-24T00:00:00+00:00 + weekly + + + + + + /en/code-review-vs-pair-programming/ + + + + + + + 2018-01-24T00:00:00+00:00 + weekly + + + + + + /pt/cargo-cult-programming/ + + + + + + + 2018-01-17T00:00:00+00:00 + weekly + + + + + + /en/cargo-cult-programming/ + + + + + + + 2018-01-17T00:00:00+00:00 + weekly + + + + + + /pt/funcionalidades-csharp8/ + + + + + + + 2017-12-20T00:00:00+00:00 + weekly + + + + + + /en/csharp-8-features/ + + + + + + + 2017-12-20T00:00:00+00:00 + weekly + + + + + + /pt/como-aprender-ingles-parte-2 + + + + + 2017-12-05T00:00:00+00:00 + weekly + + + + + + /pt/como-aprender-ingles-parte-1 + + + + + 2017-11-27T00:00:00+00:00 + weekly + + + + + + /en/unit-testing-for-beginners-part2/ + + + + + + + 2017-08-08T00:00:00+00:00 + weekly + + + + + + /pt/testes-unitarios-iniciantes-parte-2 + + + + + + + 2017-08-08T00:00:00+00:00 + weekly + + + + + + /pt/funcionalidades-csharp-7-parte-2 + + + + + + + 2017-06-05T00:00:00+00:00 + weekly + + + + + + /en/csharp-7-features-part-2/ + + + + + + + 2017-06-05T00:00:00+00:00 + weekly + + + + + + /en/git-basics-for-tfs-users + + + + + + + 2017-04-04T00:00:00+00:00 + weekly + + + + + + /pt/basicos-do-git-usuarios-tfvc + + + + + + + 2017-04-04T00:00:00+00:00 + weekly + + + + + + /pt/escrevendo-codigo-bom/ + + + + + 2017-03-25T00:00:00+00:00 + weekly + + + + + + /pt/funcionalidades-csharp-7/ + + + + + + + 2017-03-13T00:00:00+00:00 + weekly + + + + + + /en/csharp-7-features/ + + + + + + + 2017-03-13T00:00:00+00:00 + weekly + + + + + + /en/types-of-comments-to-avoid/ + + + + + + + 2017-03-02T00:00:00+00:00 + weekly + + + + + + /pt/tipos-de-comentarios-a-evitar/ + + + + + + + 2017-03-02T00:00:00+00:00 + weekly + + + + + + /pt/blogs-desenvolvimento-portugues/ + + + + + 2017-02-11T00:00:00+00:00 + weekly + + + + + + /pt/metodos-privados-code-smell/ + + + + + + + 2017-01-29T00:00:00+00:00 + weekly + + + + + + /en/are-private-methods-a-code-smell/ + + + + + + + 2017-01-29T00:00:00+00:00 + weekly + + + + + + /en/value-reference-types-in-csharp-part-2/ + + + + + + + 2016-06-19T00:00:00+00:00 + weekly + + + + + + /pt/tipos-valor-referencia-em-csharp-parte-2/ + + + + + + + 2016-06-19T00:00:00+00:00 + weekly + + + + + + /en/how-to-choose-good-names/ + + + + + + + 2016-05-22T00:00:00+00:00 + weekly + + + + + + /pt/como-escolher-bons-nomes/ + + + + + + + 2016-05-22T00:00:00+00:00 + weekly + + + + + + /pt/traducao-fases-estabilizacao/ + + + + + 2016-05-02T00:00:00+00:00 + weekly + + + + + + /en/unit-testing-for-beginners-part1/ + + + + + + + 2016-04-09T00:00:00+00:00 + weekly + + + + + + /pt/testes-unitarios-iniciantes-parte1 + + + + + + + 2016-04-09T00:00:00+00:00 + weekly + + + + + + /pt/programar-portugues-ou-ingles/ + + + + + 2016-03-29T00:00:00+00:00 + weekly + + + + + + /pt/resenha-livro-programador-pragmatico/ + + + + + + + 2016-03-14T00:00:00+00:00 + weekly + + + + + + /en/book-review-pragmatic-programmer/ + + + + + + + 2016-03-14T00:00:00+00:00 + weekly + + + + + + /en/value-reference-types-in-csharp/ + + + + + + + 2016-01-30T00:00:00+00:00 + weekly + + + + + + /pt/tipos-valor-referencia-em-csharp/ + + + + + + + 2016-01-30T00:00:00+00:00 + weekly + + + + + + /en/share-what-you-learn/ + + + + + + + 2015-08-25T00:00:00+00:00 + weekly + + + + + + /pt/compartilhe-o-que-voce-aprende/ + + + + + + + 2015-08-25T00:00:00+00:00 + weekly + + + + + + + /AJ21/ + + + + + weekly + + + + + + /about/ + + + + + + + weekly + + + + + + /busca/ + + + + + + + weekly + + + + + + /como-aprender-ingles/ + + + + + weekly + + + + + + /feed.xml + + + + + + + + + + + + + weekly + + + + + + /footprints/ + + + + + weekly + + + + + + / + + + + + + + weekly + + + + + + /css/main.css + + + + + + + + + + + + + weekly + + + + + + /pt/ + + + + + + + weekly + + + + + + /readings/ + + + + + weekly + + + + + + /rss.xml + + + + + + + + + + + + + weekly + + + + + + /search/ + + + + + + + weekly + + + + + + /sitemaps.xml + + + + + + + + + + + + + weekly + + + + + + /sobre/ + + + + + + + weekly + + + + + + /unifai2017/ + + + + + weekly + + + + + + /unifai2018/ + + + + + weekly + + + + + + /tag/blog/ + + + + + + + weekly + + + + + + /tag/compartilhar/ + + + + + + + weekly + + + + + + /tag/primeiro%20post/ + + + + + + + weekly + + + + + + /tag/blogging/ + + + + + + + weekly + + + + + + /tag/sharing/ + + + + + + + weekly + + + + + + /tag/first%20post/ + + + + + + + weekly + + + + + + /tag/csharp/ + + + + + + + weekly + + + + + + /tag/iniciantes/ + + + + + + + weekly + + + + + + /tag/orientacao-a-objetos/ + + + + + + + weekly + + + + + + /tag/tipagem/ + + + + + + + weekly + + + + + + /tag/beginners/ + + + + + + + weekly + + + + + + /tag/oop/ + + + + + + + weekly + + + + + + /tag/type%20system/ + + + + + + + weekly + + + + + + /tag/book%20review/ + + + + + + + weekly + + + + + + /tag/agile/ + + + + + + + weekly + + + + + + /tag/livros/ + + + + + + + weekly + + + + + + /tag/metodologias%20%C3%A1geis/ + + + + + + + weekly + + + + + + /tag/boas-praticas/ + + + + + + + weekly + + + + + + /tag/ingles/ + + + + + + + weekly + + + + + + /tag/testes-de-software/ + + + + + + + weekly + + + + + + /tag/testes-unitarios/ + + + + + + + weekly + + + + + + /tag/testes-automatizados/ + + + + + + + weekly + + + + + + /tag/metodologias-ageis/ + + + + + + + weekly + + + + + + /tag/serie-testes-unitarios/ + + + + + + + weekly + + + + + + /tag/software-testing/ + + + + + + + weekly + + + + + + /tag/unit-testing/ + + + + + + + weekly + + + + + + /tag/unit-testing-series/ + + + + + + + weekly + + + + + + /tag/automated-tests/ + + + + + + + weekly + + + + + + /tag/tradu%C3%A7%C3%B5es/ + + + + + + + weekly + + + + + + /tag/integra%C3%A7%C3%A3o%20cont%C3%ADnua/ + + + + + + + weekly + + + + + + /tag/testes%20de%20software/ + + + + + + + weekly + + + + + + /tag/testes%20automatizados/ + + + + + + + weekly + + + + + + /tag/boas%20pr%C3%A1ticas/ + + + + + + + weekly + + + + + + /tag/best%20practices/ + + + + + + + weekly + + + + + + /tag/code%20smell/ + + + + + + + weekly + + + + + + /tag/recomendacoes/ + + + + + + + weekly + + + + + + /tag/code-smell/ + + + + + + + weekly + + + + + + /tag/boas-pr%C3%A1ticas/ + + + + + + + weekly + + + + + + /tag/coment%C3%A1rios/ + + + + + + + weekly + + + + + + /tag/best-practices/ + + + + + + + weekly + + + + + + /tag/comments/ + + + + + + + weekly + + + + + + /tag/traducoes/ + + + + + + + weekly + + + + + + /tag/controle-de-versao/ + + + + + + + weekly + + + + + + /tag/git/ + + + + + + + weekly + + + + + + /tag/tfs/ + + + + + + + weekly + + + + + + /tag/tfvcs/ + + + + + + + weekly + + + + + + /tag/version-control-system/ + + + + + + + weekly + + + + + + /tag/ingl%C3%AAs/ + + + + + + + weekly + + + + + + /tag/cargo%20cult%20programming/ + + + + + + + weekly + + + + + + /tag/boas%20praticas/ + + + + + + + weekly + + + + + + /tag/programacao%20cargo%20cult/ + + + + + + + weekly + + + + + + /tag/pair%20programming/ + + + + + + + weekly + + + + + + /tag/code%20review/ + + + + + + + weekly + + + + + + /tag/programacao%20em%20par/ + + + + + + + weekly + + + + + + /tag/revisao%20de%20codigo/ + + + + + + + weekly + + + + + + /tag/metodologias%20ageis/ + + + + + + + weekly + + + + + + /tag/time/ + + + + + + + weekly + + + + + + /tag/tempo/ + + + + + + + weekly + + + + + + /tag/ddd/ + + + + + + + weekly + + + + + + /tag/modelagem-de-software/ + + + + + + + weekly + + + + + + /tag/software-design/ + + + + + + + weekly + + + + + + /tag/functional-programming/ + + + + + + + weekly + + + + + + /tag/programacao%20funcional/ + + + + + + + weekly + + + + + + /tag/engenharia-de-software/ + + + + + + + weekly + + + + + + /tag/programa%C3%A7%C3%A3o/ + + + + + + + weekly + + + + + + /tag/carreira/ + + + + + + + weekly + + + + + + /tag/software-engineering/ + + + + + + + weekly + + + + + + /tag/programming/ + + + + + + + weekly + + + + + + /tag/career-advice/ + + + + + + + weekly + + + + + + /tag/programacao/ + + + + + + + weekly + + + + + + /tag/automated-testing/ + + + + + + + weekly + + + + + + /tag/code-coverage/ + + + + + + + weekly + + + + + + /tag/mutation-testing/ + + + + + + + weekly + + + + + + /tag/tdd/ + + + + + + + weekly + + + + + + /tag/cobertura-de-codigo/ + + + + + + + weekly + + + + + + /tag/testes-de-mutacao/ + + + + + + + weekly + + + + + + /tag/legibilidade/ + + + + + + + weekly + + + + + + /tag/readability/ + + + + + + + weekly + + + + + + /tag/linq/ + + + + + + + weekly + + + + + + /tag/dotnet/ + + + + + + + weekly + + + + + + /tag/tutorial/ + + + + + + + weekly + + + + + + /tag/regex/ + + + + + + + weekly + + + + + + /tag/expressoes_regulares/ + + + + + + + weekly + + + + + + /tag/regular_expressions/ + + + + + + + weekly + + + + + + /tag/configuracao/ + + + + + + + weekly + + + + + + /tag_ptbr/blog/ + + + + + + + weekly + + + + + + /tag_ptbr/compartilhar/ + + + + + + + weekly + + + + + + /tag_ptbr/primeiro%20post/ + + + + + + + weekly + + + + + + /tag_ptbr/blogging/ + + + + + + + weekly + + + + + + /tag_ptbr/sharing/ + + + + + + + weekly + + + + + + /tag_ptbr/first%20post/ + + + + + + + weekly + + + + + + /tag_ptbr/csharp/ + + + + + + + weekly + + + + + + /tag_ptbr/iniciantes/ + + + + + + + weekly + + + + + + /tag_ptbr/orientacao-a-objetos/ + + + + + + + weekly + + + + + + /tag_ptbr/tipagem/ + + + + + + + weekly + + + + + + /tag_ptbr/beginners/ + + + + + + + weekly + + + + + + /tag_ptbr/oop/ + + + + + + + weekly + + + + + + /tag_ptbr/type%20system/ + + + + + + + weekly + + + + + + /tag_ptbr/book%20review/ + + + + + + + weekly + + + + + + /tag_ptbr/agile/ + + + + + + + weekly + + + + + + /tag_ptbr/livros/ + + + + + + + weekly + + + + + + /tag_ptbr/metodologias%20%C3%A1geis/ + + + + + + + weekly + + + + + + /tag_ptbr/boas-praticas/ + + + + + + + weekly + + + + + + /tag_ptbr/ingles/ + + + + + + + weekly + + + + + + /tag_ptbr/testes-de-software/ + + + + + + + weekly + + + + + + /tag_ptbr/testes-unitarios/ + + + + + + + weekly + + + + + + /tag_ptbr/testes-automatizados/ + + + + + + + weekly + + + + + + /tag_ptbr/metodologias-ageis/ + + + + + + + weekly + + + + + + /tag_ptbr/serie-testes-unitarios/ + + + + + + + weekly + + + + + + /tag_ptbr/software-testing/ + + + + + + + weekly + + + + + + /tag_ptbr/unit-testing/ + + + + + + + weekly + + + + + + /tag_ptbr/unit-testing-series/ + + + + + + + weekly + + + + + + /tag_ptbr/automated-tests/ + + + + + + + weekly + + + + + + /tag_ptbr/tradu%C3%A7%C3%B5es/ + + + + + + + weekly + + + + + + /tag_ptbr/integra%C3%A7%C3%A3o%20cont%C3%ADnua/ + + + + + + + weekly + + + + + + /tag_ptbr/testes%20de%20software/ + + + + + + + weekly + + + + + + /tag_ptbr/testes%20automatizados/ + + + + + + + weekly + + + + + + /tag_ptbr/boas%20pr%C3%A1ticas/ + + + + + + + weekly + + + + + + /tag_ptbr/best%20practices/ + + + + + + + weekly + + + + + + /tag_ptbr/code%20smell/ + + + + + + + weekly + + + + + + /tag_ptbr/recomendacoes/ + + + + + + + weekly + + + + + + /tag_ptbr/code-smell/ + + + + + + + weekly + + + + + + /tag_ptbr/boas-pr%C3%A1ticas/ + + + + + + + weekly + + + + + + /tag_ptbr/coment%C3%A1rios/ + + + + + + + weekly + + + + + + /tag_ptbr/best-practices/ + + + + + + + weekly + + + + + + /tag_ptbr/comments/ + + + + + + + weekly + + + + + + /tag_ptbr/traducoes/ + + + + + + + weekly + + + + + + /tag_ptbr/controle-de-versao/ + + + + + + + weekly + + + + + + /tag_ptbr/git/ + + + + + + + weekly + + + + + + /tag_ptbr/tfs/ + + + + + + + weekly + + + + + + /tag_ptbr/tfvcs/ + + + + + + + weekly + + + + + + /tag_ptbr/version-control-system/ + + + + + + + weekly + + + + + + /tag_ptbr/ingl%C3%AAs/ + + + + + + + weekly + + + + + + /tag_ptbr/cargo%20cult%20programming/ + + + + + + + weekly + + + + + + /tag_ptbr/boas%20praticas/ + + + + + + + weekly + + + + + + /tag_ptbr/programacao%20cargo%20cult/ + + + + + + + weekly + + + + + + /tag_ptbr/pair%20programming/ + + + + + + + weekly + + + + + + /tag_ptbr/code%20review/ + + + + + + + weekly + + + + + + /tag_ptbr/programacao%20em%20par/ + + + + + + + weekly + + + + + + /tag_ptbr/revisao%20de%20codigo/ + + + + + + + weekly + + + + + + /tag_ptbr/metodologias%20ageis/ + + + + + + + weekly + + + + + + /tag_ptbr/time/ + + + + + + + weekly + + + + + + /tag_ptbr/tempo/ + + + + + + + weekly + + + + + + /tag_ptbr/ddd/ + + + + + + + weekly + + + + + + /tag_ptbr/modelagem-de-software/ + + + + + + + weekly + + + + + + /tag_ptbr/software-design/ + + + + + + + weekly + + + + + + /tag_ptbr/functional-programming/ + + + + + + + weekly + + + + + + /tag_ptbr/programacao%20funcional/ + + + + + + + weekly + + + + + + /tag_ptbr/engenharia-de-software/ + + + + + + + weekly + + + + + + /tag_ptbr/programa%C3%A7%C3%A3o/ + + + + + + + weekly + + + + + + /tag_ptbr/carreira/ + + + + + + + weekly + + + + + + /tag_ptbr/software-engineering/ + + + + + + + weekly + + + + + + /tag_ptbr/programming/ + + + + + + + weekly + + + + + + /tag_ptbr/career-advice/ + + + + + + + weekly + + + + + + /tag_ptbr/programacao/ + + + + + + + weekly + + + + + + /tag_ptbr/automated-testing/ + + + + + + + weekly + + + + + + /tag_ptbr/code-coverage/ + + + + + + + weekly + + + + + + /tag_ptbr/mutation-testing/ + + + + + + + weekly + + + + + + /tag_ptbr/tdd/ + + + + + + + weekly + + + + + + /tag_ptbr/cobertura-de-codigo/ + + + + + + + weekly + + + + + + /tag_ptbr/testes-de-mutacao/ + + + + + + + weekly + + + + + + /tag_ptbr/legibilidade/ + + + + + + + weekly + + + + + + /tag_ptbr/readability/ + + + + + + + weekly + + + + + + /tag_ptbr/linq/ + + + + + + + weekly + + + + + + /tag_ptbr/dotnet/ + + + + + + + weekly + + + + + + /tag_ptbr/tutorial/ + + + + + + + weekly + + + + + + /tag_ptbr/regex/ + + + + + + + weekly + + + + + + /tag_ptbr/expressoes_regulares/ + + + + + + + weekly + + + + + + /tag_ptbr/regular_expressions/ + + + + + + + weekly + + + + + + /tag_ptbr/configuracao/ + + + + + + + weekly + + + + + + /css/main.css.map + + + + + + + + + + + + + weekly + + + + diff --git a/sobre/index.html b/sobre/index.html new file mode 100644 index 00000000..129b7e73 --- /dev/null +++ b/sobre/index.html @@ -0,0 +1,185 @@ + + + + + + + + Sobre | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+
+ +
+

Sobre

+
+ +
+

Oi. Eu sou o Carlos.

+ +

Bem-vindo ao meu blog! Meu nome é Carlos Schults, sou engenheiro de software e escritor técnico.

+ +

Embora C# seja a linguagem com a qual tenho mais experiência, trabalhei com várias tecnologias durante minha carreira, incluindo Java, Python, PHP e até VB.NET. Apesar de ter experiência com desenvolvimento de front-end (particularmente com React/Tyoescript), sou especializado em desenvolvimento de software de back-end.

+ +

Esporadicamente, trabalho como autor técnico freelancer. A maior parte do meu trabalho nesse espaço foi feita em parceria com a Hit Subscribe, tendo escrito mais de 200 posts para clientes como NDepend, NCrunch, Submain, Testim.io, TechBeacon e muitos outros.

+ +

Acredito firmemente na tese de que, se você realmente quer aprender alguma coisa, precisa ensiná-la. Em resumo, este blog existe para que eu possa compartilhar informações úteis sobre desenvolvimento de software, na esperança de que elas ajudem outras pessoas e que eu aprenda mais no processo.

+ +

Convite aberto

+ +

Se você quiser conversar comigo sobre desenvolvimento de software ou tecnologia em geral, eu quero falar com você. Aqui estão algumas maneiras de nos conectarmos:

+ +
    +
  • Se você for um desenvolvedor júnior em busca de orientação, posso ajudá-lo.
  • +
  • Encontrou um erro de digitação ou qualquer outro tipo de erro em uma de minhas postagens? Ou simplesmente discordou de algo que escrevi? Me avise!
  • +
  • Deseja revisar um texto (por exemplo, uma publicação de blog) antes de publicá-lo? Terei prazer em ajudar.
  • +
  • Se você tiver recomendações de livros, publicações, artigos ou podcasts interessantes, envie-as para mim!
  • +
  • Ou qualquer coisa, na verdade. Sinta-se à vontade para entrar em contato comigo em:
  • +
+ +

carlos arroba carlosschults ponto net

+ +

Aguardo seu contato!

+ +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag/agile/index.html b/tag/agile/index.html new file mode 100644 index 00000000..fc0d49cf --- /dev/null +++ b/tag/agile/index.html @@ -0,0 +1,442 @@ + + + + + + + + Tag: agile | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'agile'

+ + +
+
+ + + + + + + + diff --git a/tag/automated-testing/index.html b/tag/automated-testing/index.html new file mode 100644 index 00000000..8d1d596a --- /dev/null +++ b/tag/automated-testing/index.html @@ -0,0 +1,430 @@ + + + + + + + + Tag: automated-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'automated-testing'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + How To Reduce Cyclomatic Complexity: A Complete Guide +
  • + + + + + + + + + + + +
  • + Mutation Testing: What It Is and How It Makes Code Coverage Matter +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/automated-tests/index.html b/tag/automated-tests/index.html new file mode 100644 index 00000000..b77f50f4 --- /dev/null +++ b/tag/automated-tests/index.html @@ -0,0 +1,434 @@ + + + + + + + + Tag: automated-tests | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'automated-tests'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + C# Unit Testing: Getting Started With TDD +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Unit testing for beginners - Part 2 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Unit testing for beginners - Part 1 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/beginners/index.html b/tag/beginners/index.html new file mode 100644 index 00000000..eef4870e --- /dev/null +++ b/tag/beginners/index.html @@ -0,0 +1,454 @@ + + + + + + + + Tag: beginners | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'beginners'

+ + +
+
+ + + + + + + + diff --git a/tag/best practices/index.html b/tag/best practices/index.html new file mode 100644 index 00000000..2e19f58d --- /dev/null +++ b/tag/best practices/index.html @@ -0,0 +1,450 @@ + + + + + + + + Tag: best practices | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'best practices'

+ + +
+
+ + + + + + + + diff --git a/tag/best-practices/index.html b/tag/best-practices/index.html new file mode 100644 index 00000000..42bdf544 --- /dev/null +++ b/tag/best-practices/index.html @@ -0,0 +1,450 @@ + + + + + + + + Tag: best-practices | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'best-practices'

+ + +
+
+ + + + + + + + diff --git a/tag/blog/index.html b/tag/blog/index.html new file mode 100644 index 00000000..c11684f4 --- /dev/null +++ b/tag/blog/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: blog | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'blog'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/blogging/index.html b/tag/blogging/index.html new file mode 100644 index 00000000..fd672c20 --- /dev/null +++ b/tag/blogging/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: blogging | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'blogging'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Share what you learn +
  • + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/boas praticas/index.html b/tag/boas praticas/index.html new file mode 100644 index 00000000..6b45f028 --- /dev/null +++ b/tag/boas praticas/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: boas praticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'boas praticas'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/boas pr\303\241ticas/index.html" "b/tag/boas pr\303\241ticas/index.html" new file mode 100644 index 00000000..2878b0b9 --- /dev/null +++ "b/tag/boas pr\303\241ticas/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: boas práticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'boas práticas'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/boas-praticas/index.html b/tag/boas-praticas/index.html new file mode 100644 index 00000000..3eb1ed15 --- /dev/null +++ b/tag/boas-praticas/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: boas-praticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'boas-praticas'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/boas-pr\303\241ticas/index.html" "b/tag/boas-pr\303\241ticas/index.html" new file mode 100644 index 00000000..fc5b9833 --- /dev/null +++ "b/tag/boas-pr\303\241ticas/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: boas-práticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'boas-práticas'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/book review/index.html b/tag/book review/index.html new file mode 100644 index 00000000..7874ca73 --- /dev/null +++ b/tag/book review/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: book review | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'book review'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Book Review: The Pragmatic Programmer +
  • + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/career-advice/index.html b/tag/career-advice/index.html new file mode 100644 index 00000000..40e046d1 --- /dev/null +++ b/tag/career-advice/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: career-advice | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'career-advice'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Sharpen the Saw: 4 Quick Tips for Your Dev Team +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/cargo cult programming/index.html b/tag/cargo cult programming/index.html new file mode 100644 index 00000000..b72b8f16 --- /dev/null +++ b/tag/cargo cult programming/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: cargo cult programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'cargo cult programming'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Cargo Cult Programming Is The Art of Programming by Coincidence +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/carreira/index.html b/tag/carreira/index.html new file mode 100644 index 00000000..e9aa1f98 --- /dev/null +++ b/tag/carreira/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: carreira | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'carreira'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/cobertura-de-codigo/index.html b/tag/cobertura-de-codigo/index.html new file mode 100644 index 00000000..d80892be --- /dev/null +++ b/tag/cobertura-de-codigo/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: cobertura-de-codigo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'cobertura-de-codigo'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/code review/index.html b/tag/code review/index.html new file mode 100644 index 00000000..ae503582 --- /dev/null +++ b/tag/code review/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: code review | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'code review'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Code Review vs Pair-Programming: Which One Should Your Team Pick? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/code smell/index.html b/tag/code smell/index.html new file mode 100644 index 00000000..d2791ff9 --- /dev/null +++ b/tag/code smell/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: code smell | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'code smell'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Are private methods a code smell? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/code-coverage/index.html b/tag/code-coverage/index.html new file mode 100644 index 00000000..eb0d23bd --- /dev/null +++ b/tag/code-coverage/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: code-coverage | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'code-coverage'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Mutation Testing: What It Is and How It Makes Code Coverage Matter +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/code-smell/index.html b/tag/code-smell/index.html new file mode 100644 index 00000000..4be4ca05 --- /dev/null +++ b/tag/code-smell/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: code-smell | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'code-smell'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Learn which types of comments should be avoided +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/coment\303\241rios/index.html" "b/tag/coment\303\241rios/index.html" new file mode 100644 index 00000000..2cedaf50 --- /dev/null +++ "b/tag/coment\303\241rios/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: comentários | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'comentários'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/comments/index.html b/tag/comments/index.html new file mode 100644 index 00000000..498f45dd --- /dev/null +++ b/tag/comments/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: comments | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'comments'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Learn which types of comments should be avoided +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/compartilhar/index.html b/tag/compartilhar/index.html new file mode 100644 index 00000000..d19cfcb2 --- /dev/null +++ b/tag/compartilhar/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: compartilhar | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'compartilhar'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/configuracao/index.html b/tag/configuracao/index.html new file mode 100644 index 00000000..be89b838 --- /dev/null +++ b/tag/configuracao/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: configuracao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'configuracao'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/controle-de-versao/index.html b/tag/controle-de-versao/index.html new file mode 100644 index 00000000..26faed7f --- /dev/null +++ b/tag/controle-de-versao/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: controle-de-versao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'controle-de-versao'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/csharp/index.html b/tag/csharp/index.html new file mode 100644 index 00000000..a9b08828 --- /dev/null +++ b/tag/csharp/index.html @@ -0,0 +1,482 @@ + + + + + + + + Tag: csharp | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'csharp'

+ + +
+
+ + + + + + + + diff --git a/tag/ddd/index.html b/tag/ddd/index.html new file mode 100644 index 00000000..e6b2aefb --- /dev/null +++ b/tag/ddd/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: ddd | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'ddd'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value Objects: A Tool for Self-Documented Code and Fewer Errors +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/dotnet/index.html b/tag/dotnet/index.html new file mode 100644 index 00000000..7b4c1aa1 --- /dev/null +++ b/tag/dotnet/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: dotnet | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'dotnet'

+
    + + + + + + + + + + + + + + + + + + + + + + + + +
  • + The LINQ Join Operator: A Complete Tutorial +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/engenharia-de-software/index.html b/tag/engenharia-de-software/index.html new file mode 100644 index 00000000..88965955 --- /dev/null +++ b/tag/engenharia-de-software/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: engenharia-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'engenharia-de-software'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/expressoes_regulares/index.html b/tag/expressoes_regulares/index.html new file mode 100644 index 00000000..6ee164b5 --- /dev/null +++ b/tag/expressoes_regulares/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: expressoes_regulares | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'expressoes_regulares'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/first post/index.html b/tag/first post/index.html new file mode 100644 index 00000000..dec01f7e --- /dev/null +++ b/tag/first post/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: first post | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'first post'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Share what you learn +
  • + + + +
+ +
+
+ + + + + + + + diff --git a/tag/functional-programming/index.html b/tag/functional-programming/index.html new file mode 100644 index 00000000..cd4331a8 --- /dev/null +++ b/tag/functional-programming/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: functional-programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'functional-programming'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Functional Programming in C#: Map, Filter, and Reduce Your Way to Clean Code +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/git/index.html b/tag/git/index.html new file mode 100644 index 00000000..9ce6d932 --- /dev/null +++ b/tag/git/index.html @@ -0,0 +1,438 @@ + + + + + + + + Tag: git | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'git'

+ + +
+
+ + + + + + + + diff --git a/tag/ingles/index.html b/tag/ingles/index.html new file mode 100644 index 00000000..3905d063 --- /dev/null +++ b/tag/ingles/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: ingles | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'ingles'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/ingl\303\252s/index.html" "b/tag/ingl\303\252s/index.html" new file mode 100644 index 00000000..e668b1ba --- /dev/null +++ "b/tag/ingl\303\252s/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: inglês | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'inglês'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/iniciantes/index.html b/tag/iniciantes/index.html new file mode 100644 index 00000000..a6208b1e --- /dev/null +++ b/tag/iniciantes/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: iniciantes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'iniciantes'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/integra\303\247\303\243o cont\303\255nua/index.html" "b/tag/integra\303\247\303\243o cont\303\255nua/index.html" new file mode 100644 index 00000000..67f3b7c1 --- /dev/null +++ "b/tag/integra\303\247\303\243o cont\303\255nua/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: integração contínua | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'integração contínua'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/legibilidade/index.html b/tag/legibilidade/index.html new file mode 100644 index 00000000..5a09db07 --- /dev/null +++ b/tag/legibilidade/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: legibilidade | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'legibilidade'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/linq/index.html b/tag/linq/index.html new file mode 100644 index 00000000..fb1f9c67 --- /dev/null +++ b/tag/linq/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: linq | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'linq'

+
    + + + + + + + + + + + + + + + + + + + + + + +
  • + The LINQ Join Operator: A Complete Tutorial +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/livros/index.html b/tag/livros/index.html new file mode 100644 index 00000000..6c1fe377 --- /dev/null +++ b/tag/livros/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: livros | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'livros'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/metodologias ageis/index.html b/tag/metodologias ageis/index.html new file mode 100644 index 00000000..4b8fa6fa --- /dev/null +++ b/tag/metodologias ageis/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: metodologias ageis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'metodologias ageis'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/metodologias \303\241geis/index.html" "b/tag/metodologias \303\241geis/index.html" new file mode 100644 index 00000000..2c8a4584 --- /dev/null +++ "b/tag/metodologias \303\241geis/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: metodologias ágeis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'metodologias ágeis'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/metodologias-ageis/index.html b/tag/metodologias-ageis/index.html new file mode 100644 index 00000000..054c137d --- /dev/null +++ b/tag/metodologias-ageis/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: metodologias-ageis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'metodologias-ageis'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/modelagem-de-software/index.html b/tag/modelagem-de-software/index.html new file mode 100644 index 00000000..5caf3efc --- /dev/null +++ b/tag/modelagem-de-software/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: modelagem-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'modelagem-de-software'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/mutation-testing/index.html b/tag/mutation-testing/index.html new file mode 100644 index 00000000..9cf569a5 --- /dev/null +++ b/tag/mutation-testing/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: mutation-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'mutation-testing'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Mutation Testing: What It Is and How It Makes Code Coverage Matter +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/oop/index.html b/tag/oop/index.html new file mode 100644 index 00000000..06510647 --- /dev/null +++ b/tag/oop/index.html @@ -0,0 +1,438 @@ + + + + + + + + Tag: oop | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'oop'

+ + +
+
+ + + + + + + + diff --git a/tag/orientacao-a-objetos/index.html b/tag/orientacao-a-objetos/index.html new file mode 100644 index 00000000..90efc562 --- /dev/null +++ b/tag/orientacao-a-objetos/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: orientacao-a-objetos | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'orientacao-a-objetos'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/pair programming/index.html b/tag/pair programming/index.html new file mode 100644 index 00000000..bd94bd43 --- /dev/null +++ b/tag/pair programming/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: pair programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'pair programming'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Code Review vs Pair-Programming: Which One Should Your Team Pick? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/primeiro post/index.html b/tag/primeiro post/index.html new file mode 100644 index 00000000..ac8d2ce4 --- /dev/null +++ b/tag/primeiro post/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: primeiro post | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'primeiro post'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/programacao cargo cult/index.html b/tag/programacao cargo cult/index.html new file mode 100644 index 00000000..f8f9cc43 --- /dev/null +++ b/tag/programacao cargo cult/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: programacao cargo cult | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programacao cargo cult'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/programacao em par/index.html b/tag/programacao em par/index.html new file mode 100644 index 00000000..37e0f877 --- /dev/null +++ b/tag/programacao em par/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: programacao em par | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programacao em par'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/programacao funcional/index.html b/tag/programacao funcional/index.html new file mode 100644 index 00000000..f40b54c1 --- /dev/null +++ b/tag/programacao funcional/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: programacao funcional | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programacao funcional'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/programacao/index.html b/tag/programacao/index.html new file mode 100644 index 00000000..9d10d901 --- /dev/null +++ b/tag/programacao/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: programacao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programacao'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/programa\303\247\303\243o/index.html" "b/tag/programa\303\247\303\243o/index.html" new file mode 100644 index 00000000..16289a3f --- /dev/null +++ "b/tag/programa\303\247\303\243o/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: programação | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programação'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/programming/index.html b/tag/programming/index.html new file mode 100644 index 00000000..9184b14b --- /dev/null +++ b/tag/programming/index.html @@ -0,0 +1,430 @@ + + + + + + + + Tag: programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'programming'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Null Is Evil. What's The Best Alternative? Null. +
  • + + + + + + + + + + + +
  • + Sharpen the Saw: 4 Quick Tips for Your Dev Team +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/readability/index.html b/tag/readability/index.html new file mode 100644 index 00000000..c6672a12 --- /dev/null +++ b/tag/readability/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: readability | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'readability'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + The 5 Levels of Readable Code +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/recomendacoes/index.html b/tag/recomendacoes/index.html new file mode 100644 index 00000000..16ad5087 --- /dev/null +++ b/tag/recomendacoes/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: recomendacoes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'recomendacoes'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/regex/index.html b/tag/regex/index.html new file mode 100644 index 00000000..5d45ad20 --- /dev/null +++ b/tag/regex/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: regex | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'regex'

+
    + + + + + + +
  • + C# Regex: How Regular Expressions Work in C#, With Examples +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/regular_expressions/index.html b/tag/regular_expressions/index.html new file mode 100644 index 00000000..6a017507 --- /dev/null +++ b/tag/regular_expressions/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: regular_expressions | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'regular_expressions'

+
    + + + + + + + + +
  • + C# Regex: How Regular Expressions Work in C#, With Examples +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/revisao de codigo/index.html b/tag/revisao de codigo/index.html new file mode 100644 index 00000000..4a4b6f59 --- /dev/null +++ b/tag/revisao de codigo/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: revisao de codigo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'revisao de codigo'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/serie-testes-unitarios/index.html b/tag/serie-testes-unitarios/index.html new file mode 100644 index 00000000..eaab1376 --- /dev/null +++ b/tag/serie-testes-unitarios/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: serie-testes-unitarios | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'serie-testes-unitarios'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/sharing/index.html b/tag/sharing/index.html new file mode 100644 index 00000000..f180f483 --- /dev/null +++ b/tag/sharing/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: sharing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'sharing'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Share what you learn +
  • + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/software-design/index.html b/tag/software-design/index.html new file mode 100644 index 00000000..9f4adbba --- /dev/null +++ b/tag/software-design/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: software-design | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'software-design'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value Objects: A Tool for Self-Documented Code and Fewer Errors +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/software-engineering/index.html b/tag/software-engineering/index.html new file mode 100644 index 00000000..db950ae6 --- /dev/null +++ b/tag/software-engineering/index.html @@ -0,0 +1,434 @@ + + + + + + + + Tag: software-engineering | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'software-engineering'

+ + +
+
+ + + + + + + + diff --git a/tag/software-testing/index.html b/tag/software-testing/index.html new file mode 100644 index 00000000..1eb68e1b --- /dev/null +++ b/tag/software-testing/index.html @@ -0,0 +1,442 @@ + + + + + + + + Tag: software-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'software-testing'

+ + +
+
+ + + + + + + + diff --git a/tag/tdd/index.html b/tag/tdd/index.html new file mode 100644 index 00000000..4ab3552a --- /dev/null +++ b/tag/tdd/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: tdd | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tdd'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Mutation Testing: What It Is and How It Makes Code Coverage Matter +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/tempo/index.html b/tag/tempo/index.html new file mode 100644 index 00000000..2678a8b4 --- /dev/null +++ b/tag/tempo/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: tempo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tempo'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes automatizados/index.html b/tag/testes automatizados/index.html new file mode 100644 index 00000000..ca0262a2 --- /dev/null +++ b/tag/testes automatizados/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes automatizados | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes automatizados'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes de software/index.html b/tag/testes de software/index.html new file mode 100644 index 00000000..1efd80d9 --- /dev/null +++ b/tag/testes de software/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes de software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes de software'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes-automatizados/index.html b/tag/testes-automatizados/index.html new file mode 100644 index 00000000..2d3a8c57 --- /dev/null +++ b/tag/testes-automatizados/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes-automatizados | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes-automatizados'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes-de-mutacao/index.html b/tag/testes-de-mutacao/index.html new file mode 100644 index 00000000..678c334c --- /dev/null +++ b/tag/testes-de-mutacao/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes-de-mutacao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes-de-mutacao'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes-de-software/index.html b/tag/testes-de-software/index.html new file mode 100644 index 00000000..59a63d96 --- /dev/null +++ b/tag/testes-de-software/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes-de-software'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/testes-unitarios/index.html b/tag/testes-unitarios/index.html new file mode 100644 index 00000000..14e74454 --- /dev/null +++ b/tag/testes-unitarios/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: testes-unitarios | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'testes-unitarios'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/tfs/index.html b/tag/tfs/index.html new file mode 100644 index 00000000..f169137d --- /dev/null +++ b/tag/tfs/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: tfs | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tfs'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Git basics for TFS/TFVC users +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/tfvcs/index.html b/tag/tfvcs/index.html new file mode 100644 index 00000000..f6744b51 --- /dev/null +++ b/tag/tfvcs/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: tfvcs | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tfvcs'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Git basics for TFS/TFVC users +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/time/index.html b/tag/time/index.html new file mode 100644 index 00000000..a60b626d --- /dev/null +++ b/tag/time/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: time | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'time'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + 4 Common Datetime Mistakes in C# — And How to Avoid Them +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/tipagem/index.html b/tag/tipagem/index.html new file mode 100644 index 00000000..ad73b443 --- /dev/null +++ b/tag/tipagem/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: tipagem | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tipagem'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/traducoes/index.html b/tag/traducoes/index.html new file mode 100644 index 00000000..45c9bb76 --- /dev/null +++ b/tag/traducoes/index.html @@ -0,0 +1,422 @@ + + + + + + + + Tag: traducoes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'traducoes'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git "a/tag/tradu\303\247\303\265es/index.html" "b/tag/tradu\303\247\303\265es/index.html" new file mode 100644 index 00000000..309b2350 --- /dev/null +++ "b/tag/tradu\303\247\303\265es/index.html" @@ -0,0 +1,422 @@ + + + + + + + + Tag: traduções | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'traduções'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/tutorial/index.html b/tag/tutorial/index.html new file mode 100644 index 00000000..5767dac5 --- /dev/null +++ b/tag/tutorial/index.html @@ -0,0 +1,430 @@ + + + + + + + + Tag: tutorial | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'tutorial'

+
    + + + + + + + + + + +
  • + C# Regex: How Regular Expressions Work in C#, With Examples +
  • + + + + + + + +
  • + Git Create Branch: 4 Ways To Do It +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/type system/index.html b/tag/type system/index.html new file mode 100644 index 00000000..1d1c79f7 --- /dev/null +++ b/tag/type system/index.html @@ -0,0 +1,430 @@ + + + + + + + + Tag: type system | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'type system'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value and reference types in C#, Part 2 - Why can't a DateTime be null? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value and reference types in C# +
  • + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/unit-testing-series/index.html b/tag/unit-testing-series/index.html new file mode 100644 index 00000000..55801b6f --- /dev/null +++ b/tag/unit-testing-series/index.html @@ -0,0 +1,434 @@ + + + + + + + + Tag: unit-testing-series | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'unit-testing-series'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + C# Unit Testing: Getting Started With TDD +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Unit testing for beginners - Part 2 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Unit testing for beginners - Part 1 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag/unit-testing/index.html b/tag/unit-testing/index.html new file mode 100644 index 00000000..49d591fb --- /dev/null +++ b/tag/unit-testing/index.html @@ -0,0 +1,442 @@ + + + + + + + + Tag: unit-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'unit-testing'

+ + +
+
+ + + + + + + + diff --git a/tag/version-control-system/index.html b/tag/version-control-system/index.html new file mode 100644 index 00000000..58ef69f0 --- /dev/null +++ b/tag/version-control-system/index.html @@ -0,0 +1,426 @@ + + + + + + + + Tag: version-control-system | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Posts tagged with 'version-control-system'

+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Git basics for TFS/TFVC users +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + diff --git a/tag_ptbr/agile/index.html b/tag_ptbr/agile/index.html new file mode 100644 index 00000000..44f2e1a8 --- /dev/null +++ b/tag_ptbr/agile/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: agile | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'agile'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/automated-testing/index.html b/tag_ptbr/automated-testing/index.html new file mode 100644 index 00000000..17969b10 --- /dev/null +++ b/tag_ptbr/automated-testing/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: automated-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'automated-testing'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/automated-tests/index.html b/tag_ptbr/automated-tests/index.html new file mode 100644 index 00000000..6810ced6 --- /dev/null +++ b/tag_ptbr/automated-tests/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: automated-tests | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'automated-tests'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/beginners/index.html b/tag_ptbr/beginners/index.html new file mode 100644 index 00000000..c61a6836 --- /dev/null +++ b/tag_ptbr/beginners/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: beginners | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'beginners'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/best practices/index.html b/tag_ptbr/best practices/index.html new file mode 100644 index 00000000..e6b061e9 --- /dev/null +++ b/tag_ptbr/best practices/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: best practices | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'best practices'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/best-practices/index.html b/tag_ptbr/best-practices/index.html new file mode 100644 index 00000000..8a07e3e2 --- /dev/null +++ b/tag_ptbr/best-practices/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: best-practices | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'best-practices'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/blog/index.html b/tag_ptbr/blog/index.html new file mode 100644 index 00000000..879eaf02 --- /dev/null +++ b/tag_ptbr/blog/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: blog | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'blog'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Compartilhe o que você aprende +
  • + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/blogging/index.html b/tag_ptbr/blogging/index.html new file mode 100644 index 00000000..25c7654f --- /dev/null +++ b/tag_ptbr/blogging/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: blogging | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'blogging'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/boas praticas/index.html b/tag_ptbr/boas praticas/index.html new file mode 100644 index 00000000..605e43f9 --- /dev/null +++ b/tag_ptbr/boas praticas/index.html @@ -0,0 +1,500 @@ + + + + + + + + Tag: boas praticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'boas praticas'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/boas pr\303\241ticas/index.html" "b/tag_ptbr/boas pr\303\241ticas/index.html" new file mode 100644 index 00000000..40b2737c --- /dev/null +++ "b/tag_ptbr/boas pr\303\241ticas/index.html" @@ -0,0 +1,496 @@ + + + + + + + + Tag: boas práticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'boas práticas'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/boas-praticas/index.html b/tag_ptbr/boas-praticas/index.html new file mode 100644 index 00000000..c53d55ba --- /dev/null +++ b/tag_ptbr/boas-praticas/index.html @@ -0,0 +1,504 @@ + + + + + + + + Tag: boas-praticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'boas-praticas'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/boas-pr\303\241ticas/index.html" "b/tag_ptbr/boas-pr\303\241ticas/index.html" new file mode 100644 index 00000000..bc0a75d8 --- /dev/null +++ "b/tag_ptbr/boas-pr\303\241ticas/index.html" @@ -0,0 +1,488 @@ + + + + + + + + Tag: boas-práticas | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'boas-práticas'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Aprenda quais tipos de comentários devem ser evitados +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/book review/index.html b/tag_ptbr/book review/index.html new file mode 100644 index 00000000..ce607567 --- /dev/null +++ b/tag_ptbr/book review/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: book review | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'book review'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/career-advice/index.html b/tag_ptbr/career-advice/index.html new file mode 100644 index 00000000..b55ae6fb --- /dev/null +++ b/tag_ptbr/career-advice/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: career-advice | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'career-advice'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/cargo cult programming/index.html b/tag_ptbr/cargo cult programming/index.html new file mode 100644 index 00000000..5db1d7c1 --- /dev/null +++ b/tag_ptbr/cargo cult programming/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: cargo cult programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'cargo cult programming'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/carreira/index.html b/tag_ptbr/carreira/index.html new file mode 100644 index 00000000..b9001776 --- /dev/null +++ b/tag_ptbr/carreira/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: carreira | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'carreira'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/cobertura-de-codigo/index.html b/tag_ptbr/cobertura-de-codigo/index.html new file mode 100644 index 00000000..7f841855 --- /dev/null +++ b/tag_ptbr/cobertura-de-codigo/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: cobertura-de-codigo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'cobertura-de-codigo'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/code review/index.html b/tag_ptbr/code review/index.html new file mode 100644 index 00000000..aa36e7a0 --- /dev/null +++ b/tag_ptbr/code review/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: code review | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'code review'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/code smell/index.html b/tag_ptbr/code smell/index.html new file mode 100644 index 00000000..983316c7 --- /dev/null +++ b/tag_ptbr/code smell/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: code smell | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'code smell'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Métodos privados são um 'Code Smell'? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/code-coverage/index.html b/tag_ptbr/code-coverage/index.html new file mode 100644 index 00000000..3ac83d69 --- /dev/null +++ b/tag_ptbr/code-coverage/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: code-coverage | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'code-coverage'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/code-smell/index.html b/tag_ptbr/code-smell/index.html new file mode 100644 index 00000000..6ebd0a7e --- /dev/null +++ b/tag_ptbr/code-smell/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: code-smell | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'code-smell'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Aprenda quais tipos de comentários devem ser evitados +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/coment\303\241rios/index.html" "b/tag_ptbr/coment\303\241rios/index.html" new file mode 100644 index 00000000..96b09529 --- /dev/null +++ "b/tag_ptbr/coment\303\241rios/index.html" @@ -0,0 +1,484 @@ + + + + + + + + Tag: comentários | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'comentários'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Aprenda quais tipos de comentários devem ser evitados +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/comments/index.html b/tag_ptbr/comments/index.html new file mode 100644 index 00000000..25dff034 --- /dev/null +++ b/tag_ptbr/comments/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: comments | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'comments'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/compartilhar/index.html b/tag_ptbr/compartilhar/index.html new file mode 100644 index 00000000..dbeaeef7 --- /dev/null +++ b/tag_ptbr/compartilhar/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: compartilhar | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'compartilhar'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Compartilhe o que você aprende +
  • + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/configuracao/index.html b/tag_ptbr/configuracao/index.html new file mode 100644 index 00000000..79cd6a6a --- /dev/null +++ b/tag_ptbr/configuracao/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: configuracao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'configuracao'

+
+
    + + + + + + + + +
  • + [Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/controle-de-versao/index.html b/tag_ptbr/controle-de-versao/index.html new file mode 100644 index 00000000..3927214a --- /dev/null +++ b/tag_ptbr/controle-de-versao/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: controle-de-versao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'controle-de-versao'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Introdução ao Git para usuários de TFS/TFVC +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/csharp/index.html b/tag_ptbr/csharp/index.html new file mode 100644 index 00000000..91451a23 --- /dev/null +++ b/tag_ptbr/csharp/index.html @@ -0,0 +1,560 @@ + + + + + + + + Tag: csharp | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'csharp'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/ddd/index.html b/tag_ptbr/ddd/index.html new file mode 100644 index 00000000..00e25c85 --- /dev/null +++ b/tag_ptbr/ddd/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: ddd | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'ddd'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value Objects: Uma Técnica Para Código Auto-Documentado E Menos Erros +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/dotnet/index.html b/tag_ptbr/dotnet/index.html new file mode 100644 index 00000000..5c305529 --- /dev/null +++ b/tag_ptbr/dotnet/index.html @@ -0,0 +1,488 @@ + + + + + + + + Tag: dotnet | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'dotnet'

+
+
    + + + + + + +
  • + [Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Operador 'Join' do LINQ: Um Tutorial Completo +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/engenharia-de-software/index.html b/tag_ptbr/engenharia-de-software/index.html new file mode 100644 index 00000000..e58b4dbb --- /dev/null +++ b/tag_ptbr/engenharia-de-software/index.html @@ -0,0 +1,492 @@ + + + + + + + + Tag: engenharia-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'engenharia-de-software'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Como Reduzir a Complexidade Ciclomática: Um Guia Completo +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Null É Ruim. Qual A Melhor Alternativa? Null. +
  • + + + + + + + + + + + +
  • + Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/expressoes_regulares/index.html b/tag_ptbr/expressoes_regulares/index.html new file mode 100644 index 00000000..23a67f74 --- /dev/null +++ b/tag_ptbr/expressoes_regulares/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: expressoes_regulares | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'expressoes_regulares'

+
+
    + + + + + + + + + + + + + + + + + + + + +
  • + C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/first post/index.html b/tag_ptbr/first post/index.html new file mode 100644 index 00000000..089f0a5f --- /dev/null +++ b/tag_ptbr/first post/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: first post | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'first post'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/functional-programming/index.html b/tag_ptbr/functional-programming/index.html new file mode 100644 index 00000000..de835873 --- /dev/null +++ b/tag_ptbr/functional-programming/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: functional-programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'functional-programming'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/git/index.html b/tag_ptbr/git/index.html new file mode 100644 index 00000000..240161d0 --- /dev/null +++ b/tag_ptbr/git/index.html @@ -0,0 +1,496 @@ + + + + + + + + Tag: git | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'git'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/ingles/index.html b/tag_ptbr/ingles/index.html new file mode 100644 index 00000000..77f30a98 --- /dev/null +++ b/tag_ptbr/ingles/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: ingles | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'ingles'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Programar em português ou inglês? That's the question! +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/ingl\303\252s/index.html" "b/tag_ptbr/ingl\303\252s/index.html" new file mode 100644 index 00000000..4f1a5427 --- /dev/null +++ "b/tag_ptbr/ingl\303\252s/index.html" @@ -0,0 +1,488 @@ + + + + + + + + Tag: inglês | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'inglês'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Como aprender inglês: Um guia para desenvolvedores, Parte 2 +
  • + + + + + + + +
  • + Como aprender inglês: Um guia para desenvolvedores +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/iniciantes/index.html b/tag_ptbr/iniciantes/index.html new file mode 100644 index 00000000..b808e92d --- /dev/null +++ b/tag_ptbr/iniciantes/index.html @@ -0,0 +1,512 @@ + + + + + + + + Tag: iniciantes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'iniciantes'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/integra\303\247\303\243o cont\303\255nua/index.html" "b/tag_ptbr/integra\303\247\303\243o cont\303\255nua/index.html" new file mode 100644 index 00000000..2e056907 --- /dev/null +++ "b/tag_ptbr/integra\303\247\303\243o cont\303\255nua/index.html" @@ -0,0 +1,484 @@ + + + + + + + + Tag: integração contínua | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'integração contínua'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Fases de Estabilização +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/legibilidade/index.html b/tag_ptbr/legibilidade/index.html new file mode 100644 index 00000000..d16e5028 --- /dev/null +++ b/tag_ptbr/legibilidade/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: legibilidade | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'legibilidade'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Os Cinco Níveis de Código Legível +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/linq/index.html b/tag_ptbr/linq/index.html new file mode 100644 index 00000000..7d948db4 --- /dev/null +++ b/tag_ptbr/linq/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: linq | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'linq'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Operador 'Join' do LINQ: Um Tutorial Completo +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/livros/index.html b/tag_ptbr/livros/index.html new file mode 100644 index 00000000..7133c8a3 --- /dev/null +++ b/tag_ptbr/livros/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: livros | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'livros'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Resenha de Livro: O Programador Pragmático +
  • + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/metodologias ageis/index.html b/tag_ptbr/metodologias ageis/index.html new file mode 100644 index 00000000..c4ed6a80 --- /dev/null +++ b/tag_ptbr/metodologias ageis/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: metodologias ageis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'metodologias ageis'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Revisão de Código vs Programação em Par: Qual a sua equipe deve escolher? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/metodologias \303\241geis/index.html" "b/tag_ptbr/metodologias \303\241geis/index.html" new file mode 100644 index 00000000..36b80d0e --- /dev/null +++ "b/tag_ptbr/metodologias \303\241geis/index.html" @@ -0,0 +1,488 @@ + + + + + + + + Tag: metodologias ágeis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'metodologias ágeis'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Fases de Estabilização +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Resenha de Livro: O Programador Pragmático +
  • + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/metodologias-ageis/index.html b/tag_ptbr/metodologias-ageis/index.html new file mode 100644 index 00000000..89f025ed --- /dev/null +++ b/tag_ptbr/metodologias-ageis/index.html @@ -0,0 +1,492 @@ + + + + + + + + Tag: metodologias-ageis | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'metodologias-ageis'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes Unitários em C#: Iniciando Com TDD +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes Unitários Para Iniciantes - Parte 2 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes unitários para iniciantes - Parte 1 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/modelagem-de-software/index.html b/tag_ptbr/modelagem-de-software/index.html new file mode 100644 index 00000000..9e091a42 --- /dev/null +++ b/tag_ptbr/modelagem-de-software/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: modelagem-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'modelagem-de-software'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Value Objects: Uma Técnica Para Código Auto-Documentado E Menos Erros +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/mutation-testing/index.html b/tag_ptbr/mutation-testing/index.html new file mode 100644 index 00000000..1c516ba7 --- /dev/null +++ b/tag_ptbr/mutation-testing/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: mutation-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'mutation-testing'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/oop/index.html b/tag_ptbr/oop/index.html new file mode 100644 index 00000000..09345d59 --- /dev/null +++ b/tag_ptbr/oop/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: oop | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'oop'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/orientacao-a-objetos/index.html b/tag_ptbr/orientacao-a-objetos/index.html new file mode 100644 index 00000000..f1cf3fc1 --- /dev/null +++ b/tag_ptbr/orientacao-a-objetos/index.html @@ -0,0 +1,496 @@ + + + + + + + + Tag: orientacao-a-objetos | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'orientacao-a-objetos'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/pair programming/index.html b/tag_ptbr/pair programming/index.html new file mode 100644 index 00000000..a6adb7f1 --- /dev/null +++ b/tag_ptbr/pair programming/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: pair programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'pair programming'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/primeiro post/index.html b/tag_ptbr/primeiro post/index.html new file mode 100644 index 00000000..8c9b7cfd --- /dev/null +++ b/tag_ptbr/primeiro post/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: primeiro post | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'primeiro post'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Compartilhe o que você aprende +
  • + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/programacao cargo cult/index.html b/tag_ptbr/programacao cargo cult/index.html new file mode 100644 index 00000000..f8ff6d7c --- /dev/null +++ b/tag_ptbr/programacao cargo cult/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: programacao cargo cult | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programacao cargo cult'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Programação Cargo Cult É A Arte de Programar Por Coincidência +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/programacao em par/index.html b/tag_ptbr/programacao em par/index.html new file mode 100644 index 00000000..93ff8484 --- /dev/null +++ b/tag_ptbr/programacao em par/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: programacao em par | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programacao em par'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Revisão de Código vs Programação em Par: Qual a sua equipe deve escolher? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/programacao funcional/index.html b/tag_ptbr/programacao funcional/index.html new file mode 100644 index 00000000..888914ac --- /dev/null +++ b/tag_ptbr/programacao funcional/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: programacao funcional | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programacao funcional'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Programação Funcional em C#: Mapeando, Filtrando e Reduzindo Em Busca de Código Limpo +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/programacao/index.html b/tag_ptbr/programacao/index.html new file mode 100644 index 00000000..4071d30f --- /dev/null +++ b/tag_ptbr/programacao/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: programacao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programacao'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Null É Ruim. Qual A Melhor Alternativa? Null. +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/programa\303\247\303\243o/index.html" "b/tag_ptbr/programa\303\247\303\243o/index.html" new file mode 100644 index 00000000..8556dcd2 --- /dev/null +++ "b/tag_ptbr/programa\303\247\303\243o/index.html" @@ -0,0 +1,484 @@ + + + + + + + + Tag: programação | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programação'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Afiando a Serra: 4 Dicas Rápidas Para Sua Equipe +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/programming/index.html b/tag_ptbr/programming/index.html new file mode 100644 index 00000000..6720fdb2 --- /dev/null +++ b/tag_ptbr/programming/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: programming | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'programming'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/readability/index.html b/tag_ptbr/readability/index.html new file mode 100644 index 00000000..19359942 --- /dev/null +++ b/tag_ptbr/readability/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: readability | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'readability'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/recomendacoes/index.html b/tag_ptbr/recomendacoes/index.html new file mode 100644 index 00000000..fea43c66 --- /dev/null +++ b/tag_ptbr/recomendacoes/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: recomendacoes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'recomendacoes'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Blogs em português sobre desenvolvimento de software que você deveria seguir! +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/regex/index.html b/tag_ptbr/regex/index.html new file mode 100644 index 00000000..d542825e --- /dev/null +++ b/tag_ptbr/regex/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: regex | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'regex'

+
+
    + + + + + + + + + + + + + + + + + + +
  • + C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/regular_expressions/index.html b/tag_ptbr/regular_expressions/index.html new file mode 100644 index 00000000..c1182522 --- /dev/null +++ b/tag_ptbr/regular_expressions/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: regular_expressions | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'regular_expressions'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/revisao de codigo/index.html b/tag_ptbr/revisao de codigo/index.html new file mode 100644 index 00000000..05c651be --- /dev/null +++ b/tag_ptbr/revisao de codigo/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: revisao de codigo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'revisao de codigo'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Revisão de Código vs Programação em Par: Qual a sua equipe deve escolher? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/serie-testes-unitarios/index.html b/tag_ptbr/serie-testes-unitarios/index.html new file mode 100644 index 00000000..247897c0 --- /dev/null +++ b/tag_ptbr/serie-testes-unitarios/index.html @@ -0,0 +1,492 @@ + + + + + + + + Tag: serie-testes-unitarios | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'serie-testes-unitarios'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes Unitários em C#: Iniciando Com TDD +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes Unitários Para Iniciantes - Parte 2 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes unitários para iniciantes - Parte 1 +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/sharing/index.html b/tag_ptbr/sharing/index.html new file mode 100644 index 00000000..9131aff5 --- /dev/null +++ b/tag_ptbr/sharing/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: sharing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'sharing'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/software-design/index.html b/tag_ptbr/software-design/index.html new file mode 100644 index 00000000..efd4bdc4 --- /dev/null +++ b/tag_ptbr/software-design/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: software-design | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'software-design'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/software-engineering/index.html b/tag_ptbr/software-engineering/index.html new file mode 100644 index 00000000..e0732408 --- /dev/null +++ b/tag_ptbr/software-engineering/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: software-engineering | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'software-engineering'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/software-testing/index.html b/tag_ptbr/software-testing/index.html new file mode 100644 index 00000000..ecbc7954 --- /dev/null +++ b/tag_ptbr/software-testing/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: software-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'software-testing'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tdd/index.html b/tag_ptbr/tdd/index.html new file mode 100644 index 00000000..cad9d401 --- /dev/null +++ b/tag_ptbr/tdd/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: tdd | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tdd'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tempo/index.html b/tag_ptbr/tempo/index.html new file mode 100644 index 00000000..e5d23e8b --- /dev/null +++ b/tag_ptbr/tempo/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: tempo | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tempo'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + 4 Erros Comuns Com Data e Hora no C# — E como evitá-los +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes automatizados/index.html b/tag_ptbr/testes automatizados/index.html new file mode 100644 index 00000000..270136d1 --- /dev/null +++ b/tag_ptbr/testes automatizados/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: testes automatizados | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes automatizados'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Fases de Estabilização +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes de software/index.html b/tag_ptbr/testes de software/index.html new file mode 100644 index 00000000..68de68ca --- /dev/null +++ b/tag_ptbr/testes de software/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: testes de software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes de software'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Fases de Estabilização +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes-automatizados/index.html b/tag_ptbr/testes-automatizados/index.html new file mode 100644 index 00000000..19580327 --- /dev/null +++ b/tag_ptbr/testes-automatizados/index.html @@ -0,0 +1,500 @@ + + + + + + + + Tag: testes-automatizados | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes-automatizados'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes-de-mutacao/index.html b/tag_ptbr/testes-de-mutacao/index.html new file mode 100644 index 00000000..d8b4c1d5 --- /dev/null +++ b/tag_ptbr/testes-de-mutacao/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: testes-de-mutacao | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes-de-mutacao'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Testes de Mutação: O Que São e Como Tornam A Cobertura de Código Relevante +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes-de-software/index.html b/tag_ptbr/testes-de-software/index.html new file mode 100644 index 00000000..06608541 --- /dev/null +++ b/tag_ptbr/testes-de-software/index.html @@ -0,0 +1,500 @@ + + + + + + + + Tag: testes-de-software | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes-de-software'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/testes-unitarios/index.html b/tag_ptbr/testes-unitarios/index.html new file mode 100644 index 00000000..b71fff3c --- /dev/null +++ b/tag_ptbr/testes-unitarios/index.html @@ -0,0 +1,500 @@ + + + + + + + + Tag: testes-unitarios | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'testes-unitarios'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tfs/index.html b/tag_ptbr/tfs/index.html new file mode 100644 index 00000000..37ccf827 --- /dev/null +++ b/tag_ptbr/tfs/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: tfs | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tfs'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Introdução ao Git para usuários de TFS/TFVC +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tfvcs/index.html b/tag_ptbr/tfvcs/index.html new file mode 100644 index 00000000..2dfa55e5 --- /dev/null +++ b/tag_ptbr/tfvcs/index.html @@ -0,0 +1,484 @@ + + + + + + + + Tag: tfvcs | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tfvcs'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Introdução ao Git para usuários de TFS/TFVC +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/time/index.html b/tag_ptbr/time/index.html new file mode 100644 index 00000000..97343c41 --- /dev/null +++ b/tag_ptbr/time/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: time | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'time'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tipagem/index.html b/tag_ptbr/tipagem/index.html new file mode 100644 index 00000000..3185a9ab --- /dev/null +++ b/tag_ptbr/tipagem/index.html @@ -0,0 +1,488 @@ + + + + + + + + Tag: tipagem | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tipagem'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Tipos de valor e referência em C#, Parte 2 - Por que DateTime não pode ser nulo? +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Tipos de valor e referência em C# +
  • + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/traducoes/index.html b/tag_ptbr/traducoes/index.html new file mode 100644 index 00000000..74e6ab08 --- /dev/null +++ b/tag_ptbr/traducoes/index.html @@ -0,0 +1,488 @@ + + + + + + + + Tag: traducoes | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'traducoes'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git "a/tag_ptbr/tradu\303\247\303\265es/index.html" "b/tag_ptbr/tradu\303\247\303\265es/index.html" new file mode 100644 index 00000000..7af5cf4c --- /dev/null +++ "b/tag_ptbr/tradu\303\247\303\265es/index.html" @@ -0,0 +1,484 @@ + + + + + + + + Tag: traduções | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'traduções'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + Fases de Estabilização +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/tutorial/index.html b/tag_ptbr/tutorial/index.html new file mode 100644 index 00000000..55a90799 --- /dev/null +++ b/tag_ptbr/tutorial/index.html @@ -0,0 +1,492 @@ + + + + + + + + Tag: tutorial | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'tutorial'

+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/type system/index.html b/tag_ptbr/type system/index.html new file mode 100644 index 00000000..972800c4 --- /dev/null +++ b/tag_ptbr/type system/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: type system | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'type system'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/unit-testing-series/index.html b/tag_ptbr/unit-testing-series/index.html new file mode 100644 index 00000000..265d2901 --- /dev/null +++ b/tag_ptbr/unit-testing-series/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: unit-testing-series | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'unit-testing-series'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/unit-testing/index.html b/tag_ptbr/unit-testing/index.html new file mode 100644 index 00000000..d91e567c --- /dev/null +++ b/tag_ptbr/unit-testing/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: unit-testing | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'unit-testing'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/tag_ptbr/version-control-system/index.html b/tag_ptbr/version-control-system/index.html new file mode 100644 index 00000000..c568c423 --- /dev/null +++ b/tag_ptbr/version-control-system/index.html @@ -0,0 +1,480 @@ + + + + + + + + Tag: version-control-system | carlos schults / blog | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + en pt +
+ + +
+
+

Post marcados com 'version-control-system'

+
+
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/unifai2017/index.html b/unifai2017/index.html new file mode 100644 index 00000000..2177b022 --- /dev/null +++ b/unifai2017/index.html @@ -0,0 +1,216 @@ + + + + + + + + Informações sobre o minicurso "Introdução aos testes unitários automatizados com NUnit e C#" | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + pt +
+ + +
+
+
+ +
+

Informações sobre o minicurso "Introdução aos testes unitários automatizados com NUnit e C#"

+
+ +
+

Esta página vai servir para agregar todo o conteúdo relevante relativo ao minicurso ministrado por mim na XXI Semana de Informática da UNIFAI, em Adamantina - SP, nos dias 17 e 18 de agosto de 2017.

+ +

Downloads

+ + + +

Série Testes Unitários Para Iniciantes

+ +

“Testes Unitários Para Iniciantes” é uma série de posts em progresso no meu blog, no qual tento apresentar, de maneira bem didática, o assunto de teste unitários +para pessoas sem experiência com este tema.

+ +

O minicurso foi parcialmente baseado nesta série, que conta com dois artigos publicados até o momento.

+ + + +

Instalação do NUnit

+ +

Para criar os testes unitários, você precisa de um Framework de Testes. No meu dia-a-dia utilizo o NUnit, desta forma nada mais natural que escolher este framework para o minicurso e também minha série de artigos sobre testes.

+ +

Além do Nunit em si, precisamos de mais um componente chamado NUnit Test Adapter, que faz com que o Visual Studio consiga enxergar a e executar os testes do NUnit.

+ +

Tanto o NUnit quanto o NUnit Test Adapter são disponibilizados como pacotes do Nuget, e podem ser instalados com os seguintes comandos no console do Nuget:

+ +
+

Install-Package NUnit

+
+ +

e

+ +
+

Install-Package NUnit3TestAdapter

+
+ +

Caso precise de mais ajuda, meu segundo artigo sobre teste unitários possui uma seção detalhada ensinando passo-a-passo a instalação destes componentes.

+ + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + + diff --git a/unifai2018/index.html b/unifai2018/index.html new file mode 100644 index 00000000..4add2e7b --- /dev/null +++ b/unifai2018/index.html @@ -0,0 +1,185 @@ + + + + + + + + Informações sobre o minicurso "Introdução aos testes unitários automatizados com NUnit e C#" | carlos schults / blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + pt +
+ + +
+
+
+ +
+

Informações sobre o minicurso "Introdução aos testes unitários automatizados com NUnit e C#"

+
+ +
+

Informações sobre workshop e minicurso ministrados na Semana de Informática da UNIFAI

+ +

Esta página vai servir para agregar todo o conteúdo relevante relativo ao workshop e minicurso ministrados por mim na XXII Semana de Informática da UNIFAI, em Adamantina - SP, nos dias 12, 13 e 14 de setembro de 2018.

+ +

Workshop: Introdução ao Controle de Versão com Git

+ +

O workshop de git foi ministrado no dia 12 de setembro de 2018, das 19h30 às 22h na laboratório 1 da Unifai.

+ + + +

Minicurso: Projeto em C# com Banco de Dados

+ + + +
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + +