O C # permite o uso de #region
/ #endregion
keywords para tornar áreas de código recolhíveis no editor. Sempre que faço isso, faço isso para ocultar grandes pedaços de código que provavelmente poderiam ser refatorados para outras classes ou métodos. Por exemplo, vi métodos que contêm 500 linhas de código com 3 ou 4 regiões apenas para torná-lo gerenciável.
Então, o uso criterioso das regiões é um sinal de problemas? Parece ser assim para mim.
c#
code-smell
Craig
fonte
fonte
Respostas:
Um cheiro de código é um sintoma que indica que há um problema no design que potencialmente aumentará o número de bugs: esse não é o caso de regiões, mas as regiões podem contribuir para a criação de odores de código, como métodos longos.
Desde a:
regiões são anti-padrões. Eles exigem mais trabalho que não aumente a qualidade ou a legibilidade do código, o que não reduz o número de bugs e que só pode tornar o código mais complicado de refatorar.
Não use regiões dentro de métodos; refatorar
Os métodos devem ser curtos . Se houver apenas dez linhas em um método, você provavelmente não usaria regiões para ocultar cinco delas ao trabalhar em outras cinco.
Além disso, cada método deve fazer uma única coisa . As regiões, por outro lado, pretendem separar coisas diferentes . Se o seu método faz A e B, é lógico criar duas regiões, mas essa é uma abordagem errada; em vez disso, você deve refatorar o método em dois métodos separados.
O uso de regiões nesse caso também pode dificultar a refatoração. Imagine que você tem:
Colapsar a primeira região a se concentrar na segunda não é apenas arriscado: podemos facilmente esquecer a exceção que interrompe o fluxo (poderia haver uma cláusula de guarda com uma
return
alternativa, que é ainda mais difícil de detectar), mas também teria um problema se o código deve ser refatorado desta maneira:Agora, as regiões não fazem sentido e você não pode ler e entender o código na segunda região sem examinar o código na primeira.
Outro caso que vejo às vezes é este:
É tentador usar regiões quando a validação de argumentos começa a abranger dezenas de LOC, mas existe uma maneira melhor de resolver esse problema: aquele usado pelo código-fonte do .NET Framework:
Não use regiões fora dos métodos para agrupar
Algumas pessoas as usam para agrupar campos, propriedades, etc. Essa abordagem está errada: se o seu código for compatível com StyleCop, os campos, propriedades, métodos privados, construtores, etc. já estarão agrupados e fáceis de encontrar. Caso contrário, é hora de começar a pensar em aplicar regras que garantam uniformidade em toda a sua base de código.
Outras pessoas usam regiões para ocultar muitas entidades semelhantes . Por exemplo, quando você tem uma classe com cem campos (que cria pelo menos 500 linhas de código se você contar os comentários e os espaços em branco), poderá ficar tentado a colocar esses campos em uma região, recolhê-los e esquecê-los. Novamente, você está fazendo errado: com tantos campos em uma classe, você deve pensar melhor sobre o uso de herança ou dividir o objeto em vários objetos.
Finalmente, algumas pessoas são tentadas a usar regiões para agrupar coisas relacionadas : um evento com seu delegado ou um método relacionado ao IO com outros métodos relacionados ao IO etc. No primeiro caso, torna-se uma bagunça difícil de manter , Leia e compreenda. No segundo caso, o melhor design provavelmente seria criar várias classes.
Existe um bom uso para regiões?
Não . Havia um uso herdado: código gerado. Ainda assim, as ferramentas de geração de código precisam usar classes parciais. Se o C # tem suporte para regiões, é principalmente porque esse legado é usado e porque agora muitas pessoas usavam regiões em seu código, seria impossível removê-las sem quebrar as bases de código existentes.
Pense nisso como sobre
goto
. O fato de a linguagem ou o IDE suportar um recurso não significa que ele deva ser usado diariamente. A regra StyleCop SA1124 é clara: você não deve usar regiões. Nunca.Exemplos
Atualmente, estou revisando o código do meu colega de trabalho. A base de código contém muitas regiões e é realmente um exemplo perfeito de como não usar regiões e por que regiões levam a códigos incorretos. aqui estão alguns exemplos:
4 000 monstro LOC:
Li recentemente em algum lugar no Programmers.SE que quando um arquivo contém muitos
using
s (após executar o comando "Remover usos não utilizados"), é um bom sinal de que a classe dentro desse arquivo está fazendo muito. O mesmo se aplica ao tamanho do próprio arquivo.Ao revisar o código, deparei-me com um arquivo LOC de 4.000. Parecia que o autor desse código simplesmente copiou e colou o mesmo método de 15 linhas centenas de vezes, alterando levemente os nomes das variáveis e o método chamado. Um regex simples permitiu cortar o arquivo de 4.000 LOC para 500 LOC, apenas adicionando alguns genéricos; Tenho certeza de que, com uma refatoração mais inteligente, essa classe pode ser reduzida a algumas dezenas de linhas.
Ao usar regiões, o autor encorajou-se a ignorar o fato de que o código é impossível de manter e mal escrito e a duplicar fortemente o código em vez de refatorá-lo.
Região "Fazer A", Região "Fazer B":
Outro excelente exemplo foi um método de inicialização de monstros que simplesmente executava a tarefa 1, depois a tarefa 2, depois a tarefa 3, etc. Havia cinco ou seis tarefas totalmente independentes, cada uma inicializando algo em uma classe de contêiner. Todas essas tarefas foram agrupadas em um método e agrupadas em regiões.
Isso tinha uma vantagem:
Os problemas, por outro lado, eram múltiplos:
Não era óbvio se havia dependências entre as regiões. Felizmente, não houve reutilização de variáveis; caso contrário, a manutenção poderia ser um pesadelo ainda mais.
O método era quase impossível de testar. Como você saberia facilmente se o método que faz vinte coisas de cada vez faz corretamente?
Região de campos, região de propriedades, região de construtor:
O código revisado também continha muitas regiões, agrupando todos os campos, todas as propriedades, etc. Isso tinha um problema óbvio: crescimento do código-fonte.
Quando você abre um arquivo e vê uma lista enorme de campos, você está mais inclinado a refatorar a classe primeiro e depois trabalhar com o código. Com as regiões, você tem o hábito de recolher coisas e esquecê-las.
Outro problema é que, se você fizer isso em qualquer lugar, estará criando regiões de um bloco, o que não faz sentido. Na verdade, esse foi o caso no código que revi, onde havia muitos que
#region Constructor
continham um construtor.Finalmente, campos, propriedades, construtores etc. já devem estar em ordem . Se eles são e correspondem às convenções (constantes começando com uma letra maiúscula, etc.), já está claro onde o tipo de elemento para e o outro começa, para que você não precise criar regiões explicitamente para isso.
fonte
É incrível para mim quantas pessoas odeiam regiões tão apaixonadamente!
Eu concordo completamente com muitas de suas objeções: colocar código em um
#region
para ocultá-lo é uma coisa ruim. Dividir uma classe em#regions
quando deve ser refatorada em classes separadas é claramente um erro. Usar um#region
para incorporar informações semânticas redundantes é, bem, redundante.Mas nenhuma dessas coisas significa que há algo inerentemente errado em usar regiões no seu código! Só posso supor que as objeções da maioria das pessoas vêm de trabalhar em equipes em que outras pessoas estão inclinadas a usar recursos IDE como este incorretamente. Tenho o luxo de trabalhar primária sozinho e aprecio a maneira como as regiões ajudaram a organizar meu fluxo de trabalho. Talvez seja o meu transtorno obsessivo-compulsivo, mas não gosto de ver um monte de código na tela de cada vez, por mais organizado e elegante que seja. Separar as coisas em regiões lógicas me permite recolher o código que não me interessa trabalhar no código que façose importar. Não estou ignorando código mal escrito, não faz sentido refatá-lo mais do que é, e a organização "meta" adicional é descritiva, e não inútil.
Agora que passei mais tempo trabalhando em C ++, programando mais diretamente a API do Windows, me vejo desejando que o suporte para regiões fosse tão bom quanto para C #. Você poderia argumentar que o uso de uma biblioteca GUI alternativa tornaria meu código mais simples ou mais claro, eliminando assim a necessidade de obter ruído de código irrelevante na tela, mas tenho outros motivos para não querer fazer isso. Sou proficiente o suficiente com meu teclado e IDE para que a expansão / recolhimento do código subdividido em regiões leve menos de uma fração de segundo. O tempo que economizo em inteligência, tentando limitar meu foco consciente apenas ao código em que estou trabalhando atualmente, vale mais que isso. Tudo pertence a uma única classe / arquivo, mas nem tudo pertence à minha tela ao mesmo tempo.
O ponto é que usar
#regions
para separar e dividir logicamente seu código não é uma coisa ruim a ser evitada a todo custo. Como Ed aponta, não é um "cheiro de código". Se seu código cheirar, você pode ter certeza de que ele não vem das regiões, mas de qualquer código que você tentou enterrar nessas regiões. Se um recurso ajuda você a ser mais organizado ou a escrever um código melhor, eu digo que o use . Se isso se tornar um obstáculo, ou se você o usar incorretamente, pare de usá-lo. Se o pior acontecer, e você for forçado a trabalhar em uma equipe com pessoas que o usam, memorize o atalho do teclado para desativar o esquema de código: Ctrl+ M, Ctrl+P. E pare de reclamar. Às vezes, sinto que essa é outra maneira pela qual aqueles que querem ser vistos como programadores "verdadeiros" e "hardcore" gostam de tentar provar a si mesmos. Não é melhor evitar regiões do que evitar a coloração de sintaxe. Isso não faz de você um desenvolvedor mais machista.Tudo isso dito, regiões dentro de um método são pura bobagem. Sempre que você desejar fazer isso, refatorá-lo para um método separado. Sem desculpas.
fonte
Primeiro, eu não aguento mais o termo "cheiro de código". É usado com muita frequência e é usado na maioria das vezes por pessoas que não conseguiam reconhecer um bom código se ele o mordesse. Enfim...
Eu pessoalmente não gosto de usar muitas regiões. Isso dificulta o acesso ao código, e o código é o que me interessa. Gosto de regiões quando tenho um grande pedaço de código que não precisa ser tocado com muita frequência. Além disso, eles parecem me atrapalhar, e regiões como "Métodos Privados", "Métodos Públicos" etc. etc. me deixam louco. Eles são parecidos com comentários da variedade
i++ //increment i
.Eu também acrescentaria que o uso de regiões não pode realmente ser um "antipadrão", pois esse termo é comumente usado para descrever padrões de lógica / design de programa, não o layout de um editor de texto. Isso é subjetivo; Use o que funciona para você. Você nunca vai acabar com um programa impossível de manter devido ao uso excessivo de regiões, que é o objetivo dos anti-padrões. :)
fonte
Sim regiões são um cheiro de código!
Ficaria feliz em ver regiões removidas do compilador por completo. Todo desenvolvedor cria seu próprio esquema inútil de preparação que nunca será de valor para outro programador. Eu tenho tudo a ver com programadores que querem decorar e embelezar seu bebê, nada a ver com qualquer valor real.
Você pode pensar em um exemplo em que "nossa, eu gostaria que meu colega usasse algumas regiões aqui!"?
Embora eu possa configurar meu IDE para expandir automaticamente todas as regiões, elas ainda são dolorosas e prejudicam a leitura do código real.
Eu realmente me importaria menos se todos os meus métodos públicos fossem agrupados ou não. Parabéns, você sabe a diferença entre uma declaração de variável e inicialização, não é necessário exibi-la no código!
Preparação sem valor!
Além disso, se o seu arquivo precisar e 'arquitetura da informação' através do uso de regiões, você poderá combater o problema principal: Sua classe é muito grande! Dividir em partes menores é muito mais benéfico e, quando feito corretamente, adiciona verdadeira semântica / legibilidade.
fonte
Eu pessoalmente uso as regiões como uma maneira de agrupar vários tipos de métodos ou partes de código.
Portanto, um arquivo de código pode ficar assim ao abri-lo:
Eu não coloco regiões dentro de métodos. IMHO que é um sinal de cheiro de código. Uma vez me deparei com um método com mais de 1200 linhas e cinco regiões diferentes. Foi uma visão assustadora!
Se você o estiver usando como uma maneira de organizar seu código de maneira a tornar mais rápido encontrar coisas para outros desenvolvedores, não acho que seja um sinal de problema. Se você estiver usando para ocultar linhas de código dentro de um método, eu diria que é hora de repensar esse método.
fonte
Usar
#region
blocos para tornar uma classe muito grande legível geralmente é um sinal de violação do Princípio de Responsabilidade Única. Se eles estão sendo usados para agrupar comportamentos, também é provável que a classe esteja fazendo muito (mais uma vez violando o SRP).Seguindo a linha de pensamento "cheiro de código", os
#region
blocos não são cheiros de código por si só, mas são mais "Febreze para código", na medida em que tentam esconder cheiros. Enquanto eu os usei muito no passado, quando você começa a refatorar, você começa a ver menos porque eles acabam não se escondendo muito.fonte
A palavra-chave aqui é "criteriosa". É difícil imaginar um caso em que colocar uma região dentro de um método seja criterioso; é muito provável que oculte código e preguiça. No entanto, pode haver boas razões para ter algumas regiões aqui e ali no código de alguém.
Se existem muitas regiões, acho que é um cheiro de código. As regiões costumam ser uma sugestão de um local possível para refatoração futura. Muitas regiões significam que alguém nunca está realmente entendendo a dica.
Usados criteriosamente, eles fornecem um bom meio termo entre a estrutura de uma única classe com muitos métodos e a estrutura de muitas classes com apenas alguns métodos em cada. Eles são mais úteis quando uma classe começa a se aproximar do ponto em que deve ser refatorada em várias classes, mas ainda não está lá. Ao agrupar métodos relacionados, eu facilito mais tarde extrair um conjunto de métodos relacionados para sua própria classe, se eles continuarem a crescer em número. Por exemplo, se eu tiver uma classe que se aproxima de 500 linhas de código, esse conjunto de métodos usando 200 linhas de código coletadas em uma região provavelmente é uma boa peça para refatorar de alguma forma - e essa outra região com 100 linhas de código em sua região. métodos também podem ser um bom alvo.
Outra maneira que eu gosto de usar regiões é reduzir um dos efeitos negativos da refatoração de um método grande: muitos métodos pequenos, concisos e facilmente reutilizados que um leitor precisa percorrer para chegar a outro método não relacionado. Uma região pode ser uma boa maneira de encapsular um método e seus auxiliares para os leitores, para que alguém que esteja trabalhando com um aspecto diferente da classe possa recolhê-los e descartar rapidamente essa parte do código. Obviamente, isso só funciona se suas regiões estiverem realmente bem organizadas e estiverem sendo usadas como outra maneira de documentar seu código.
Em geral, acho que as regiões me ajudam a me manter organizado, a "documentar" meu código e a encontrar lugares para refatorar muito mais cedo do que se eu não usasse regiões.
fonte
Uso principalmente regiões para classes de servidor CRUD para organizar os vários tipos de operações. Mesmo assim, eu poderia alegremente ficar sem eles.
Se usado extensivamente, levantaria uma bandeira vermelha. Eu estaria atento a aulas com muita responsabilidade.
Na minha experiência, um método com centenas de linhas e um código é definitivamente um cheiro.
fonte
Minha regra de ouro é: se você tem mais de 5 regiões em um arquivo, é um cheiro de código
Ou seja, pode ser bom delinear campos, métodos, propriedades e construtores, mas se você estiver começando a agrupar todos os outros métodos em uma região própria, algo está seriamente errado
..e sim, já participei de muitos projetos onde esse é o caso, geralmente por causa de padrões de codificação ruins, geração de código ou ambos. É muito rápido ter que alternar todos os tópicos no visual studio para obter uma boa visão geral do código.
fonte
AS REGIÕES TÊM SEU USO
Eu os usei pessoalmente para eventos de interface de "codificação manual" antes para aplicativos de formulários do Windows.
No entanto, no meu trabalho, usamos um gerador de código para lidar com SQL e ele automaticamente usa regiões para classificar seus tipos de métodos de seleção, atualização, exclusão, etc.
Portanto, embora eu não os use com frequência, eles são perfeitamente adequados para remover grandes pedaços de código.
fonte
Se você tiver regiões IN código certamente terá um problema (exceto o caso do código gerado). Colocar regiões no código é basicamente dizer "refatorar isso".
No entanto, existem outros casos. Alguém que me lembra que fiz um tempo atrás: uma mesa com alguns milhares de itens pré-calculados. É uma descrição da geometria. Com exceção de um erro na tabela, nunca haverá uma ocasião para examiná-la. Claro, eu poderia ter obtido os dados de um recurso ou algo parecido, mas isso impediria o uso do compilador para facilitar a leitura.
fonte
Em um projeto recente, havia um método de linha de 1700 com várias regiões incorporadas. O interessante é que as regiões demarced ações distintas que estavam sendo feitas dentro do método. Consegui fazer um método refactor -> extract em cada uma das regiões sem afetar a funcionalidade do código.
Em geral, as regiões usadas para ocultar o código da placa da caldeira são úteis. Eu desaconselharia o uso de regiões para ocultar propriedades, campos e afins, porque se eles forem muito difíceis de serem vistos ao trabalhar dentro da classe, provavelmente é um sinal de que a classe deve ser mais detalhada. Mas como regra geral, se você estiver colocando uma região dentro de um método, provavelmente será melhor extrair outro método que explique o que está acontecendo do que agrupar esse bloco em uma região.
fonte
As regiões podem ser usadas em código de boa qualidade? Provavelmente. Aposto que são, em muitos casos. No entanto, minha experiência pessoal me deixa muito desconfiada - vi regiões quase exclusivamente mal utilizadas. Eu diria que estou cansado, mas ainda otimista.
Posso dividir aproximadamente o código de região que vi até agora em três categorias:
Código mal fatorado: a maior parte do código que eu vi usa regiões como uma ferramenta de fator pobre. Por exemplo, uma classe que cresceu a ponto de fazer sentido especializá-la para propósitos diferentes pode ser dividida em regiões separadas, uma para cada finalidade.
Código escrito usando as bibliotecas erradas e, às vezes, a linguagem errada, para o domínio do problema Freqüentemente, quando um programador não está usando o conjunto certo de bibliotecas para o domínio do problema, você vê o código se tornando incrivelmente detalhado - com muitas pequenas funções auxiliares que realmente não pertencem (provavelmente pertencem à sua própria biblioteca).
Código escrito por estudantes ou recém-formados. Alguns programas e cursos parecem tentar inculcar os alunos no uso de regiões para todos os tipos de propósitos estranhos. Você verá regiões espalhando o código-fonte até o ponto em que a proporção de tags de região e linhas de código está no intervalo de 1: 5 ou pior.
fonte
Eu diria que é um "cheiro de código".
Antipadrões são geralmente problemas estruturais fundamentais em um software, enquanto regiões, por si só, causam um comportamento desagradável em um editor. Usar regiões não é realmente inerentemente ruim, mas usá-las bastante, especialmente para ocultar trechos de código, pode indicar que existem outros problemas independentes e maiores acontecendo em outros lugares.
fonte
Uso regiões apenas para uma coisa (pelo menos não consigo pensar em outros lugares em que as uso): agrupar testes de unidade para um método.
Normalmente, tenho uma classe de teste por classe e, em seguida, agrupo os testes de unidade para cada método usando regiões que têm o nome do método. Não tenho certeza se é um cheiro de código ou algo assim, mas como a idéia básica é que os testes de unidade não precisam ser alterados, a menos que quebrem porque algo no código mudou, fica mais fácil encontrar todos os testes para um método específico bem rápido.
Talvez eu tenha usado regiões para organizar código no passado, mas não me lembro da última vez que o fiz. Mas eu continuo com minhas regiões nas aulas de teste de unidade.
fonte
Acredito que sejam anti-padrão e, francamente, acho que eles devem ser eliminados. Mas se você estiver na situação infeliz de trabalhar em um local onde eles são um padrão, o Visual Studio oferece uma ferramenta incrível para minimizar a quantidade que você gostaria de vomitar toda vez que vir uma região que eu odeio # Regiões
Este plugin irá maximizar o tamanho da fonte das regiões muito pequenas. Eles também serão expandidos para que você não precise pressionar ctr + m + l para abrir todas as regiões. Ele não corrige essa forma de câncer de código, mas a torna suportável.
fonte
Uso regiões para conter cada combinação de visibilidade e tipo de membro. Assim, todas as funções privadas vão para uma região, etc.
A razão pela qual faço isso não é para que eu possa dobrar o código. É porque eu tenho meu editor em script para poder inserir, por exemplo, uma referência a um proxy:
no código e coloque cada parte cuidadosamente na região apropriada.
Nesse caso, a macro analisaria meu projeto, me forneceria uma caixa de listagem de proxies e injetaria o código para o que eu quero. Meu cursor nem se move.
No começo do aprendizado do C #, eu havia considerado o uso de regiões para manter a comunalidade unida, mas essa é uma proposta de acerto e fracasso, porque não é um relacionamento individual em todos os momentos. Quem quer se preocupar com um membro usado por duas regiões, ou mesmo começar a dividir as coisas nesses termos.
O único outro tipo de segregação são os métodos - dividirei os métodos em Comandos, Funções e Manipuladores, para ter uma região para comandos públicos, privados, etc.
Isso me dá granularidade, mas é uma granularidade consistente e inequívoca em que posso confiar.
fonte
Regiões são expressões de pré-processador - em outras palavras, são tratadas como comentários e basicamente ignoradas pelo compilador. Eles são puramente uma ferramenta visual usada no Visual Studio. Portanto, #region não é realmente um cheiro de código, porque simplesmente não é código. O cheiro do código é bastante o método das 800 linhas, com muitas responsabilidades diferentes incorporadas, etc. Portanto, se você ver 10 regiões em um método - provavelmente está sendo usado para ocultar o cheiro do código. Dito isto, eu os vi usados de maneira extremamente eficaz para tornar uma aula mais agradável aos olhos e mais navegável - em uma aula muito bem escrita e estruturada também!
fonte
As regiões eram uma idéia organizacional bacana, mas não levaram em conta algumas tendências dos desenvolvedores de querer colocar categorias demais em tudo, e geralmente desnecessárias de acordo com as práticas modernas de OOP dos dias de hoje ... elas são um "cheiro", no sentido de que usá-las frequentemente indica que sua classe / método é muito grande e deve ser refatorada, pois você provavelmente está violando o "S" dos princípios do SOLID ... mas, como qualquer cheiro, não necessariamente significa algo está indo mal.
As regiões servem mais a propósito no código funcional do que no código orientado a objeto, IMO, onde você tem longas funções de dados sequenciais que faz sentido desmembrar, mas houve momentos em que eu os usei pessoalmente em c #, e eles quase sempre concentre-se no código que você não precisa / deseja ver. Para mim, essas eram geralmente constantes de string SQL brutas na base de código usada para o NPoco ou suas variantes. A menos que você realmente se importe com a forma como os dados preenchem o objeto POCO através do seu ORM, eles são completamente inúteis de se olhar ... e se você se importa, ei, basta expandir a região e o BAM! Mais de 150 linhas de algumas consultas SQL complicadas para o seu prazer.
fonte