Os problemas com Evitando Classes de Nomenclatura Smurf com namespaces

39

Peguei o termo smurf nomeando daqui (número 21). Para salvar alguém que não conhece o problema, a nomeação Smurf é o ato de prefixar um monte de classes, variáveis ​​etc. relacionadas com um prefixo comum, para que você acabe com "a SmurfAccountViewpassa a SmurfAccountDTOpara SmurfAccountController", etc.

A solução que geralmente ouvi sobre isso é criar um espaço para nome de smurf e soltar os prefixos de smurf. Isso geralmente me serviu bem, mas estou com dois problemas.

  1. Estou trabalhando com uma biblioteca com uma Configurationclasse. Poderia ter sido chamado, WartmongerConfigurationmas está no espaço de nomes do Wartmonger, por isso é chamado Configuration. Da mesma forma, tenho uma Configurationclasse que poderia ser chamada SmurfConfiguration, mas é no espaço para nome Smurf, portanto seria redundante. Há lugares no meu código em que Smurf.Configurationaparece ao lado Wartmonger.Configuratione digitar nomes totalmente qualificados é desajeitado e torna o código menos legível. Seria melhor lidar com ae SmurfConfiguration(se fosse meu código e não uma biblioteca) WartmongerConfiguration.

  2. Eu tenho uma classe chamada Serviceno meu namespace Smurf que poderia ter sido chamada SmurfService. Serviceé uma fachada no topo de uma complexa biblioteca Smurf que executa tarefas Smurf. SmurfServiceparece um nome melhor, porque Servicesem o prefixo Smurf é incrivelmente genérico. Eu posso aceitar que SmurfServicejá era um nome genérico, inútil, e tirar smurf apenas tornou isso mais aparente. Mas poderia ter sido nomeado Runner, Launcheretc, e ainda me "sentiria melhor" como SmurfLauncherporque não sei o que Launcherfaz, mas sei o que SmurfLauncherfaz. Você poderia argumentar que o que um Smurf.Launcherfaz deve ser tão aparente quanto umSmurf.SmurfLauncher, mas eu pude ver o `Smurf.Launcher sendo algum tipo de classe relacionada à instalação, em vez de uma classe que lança smurfs.

Se houver uma maneira aberta e fechada de lidar com qualquer uma dessas opções, isso seria ótimo. Caso contrário, quais são algumas práticas comuns para atenuar seu aborrecimento?

Daniel Koverman
fonte
3
Faz Smurf.LauncherSmurfs lançamento, ou ele lançar SmurfJobs? Talvez pudesse ser chamado Smurf.JobLauncher?
Blorgbeard
2
É um cheiro de código nomear uma classe XService, XManager, etc. Isso não significa nada. É como um Util. Se você estiver examinando os nomes dos arquivos, qualquer coisa pode estar lá ou estar faltando. Não há como saber a menos que você olhe para dentro. Eu o renomearia do SmurfService para outra coisa completamente.
precisa
1
Na verdade, ele lança SmurfJobou executa tecnicamente para ser consistente com o idioma da documentação do Smurf. À luz disso e das outras respostas, vou mudar o nome SmurfServicepara SmurfJobRunner. Parece que o número 1 não possui uma melhor resolução independente de idioma, como eu esperava. Eu posso ver casos em que ir SmurfConfigurationseria a decisão certa, mas no meu caso, acho que Configurationé melhor mesmo com o incômodo de Wartmonger.Configuration.
precisa
6
Estou tentando entender por que você tem uma única classe que se preocupa em configurar os Wartmongers e os Smurfs.
Donal Fellows
Por que Smurf.Configuratione se SmurfConfigurationsentir diferente? Certamente não é o char extra, é? (Reduza para Configse o comprimento é o problema.) Smurf.ConfigurationHá algum problema que SmurfConfigurationnão existe?
Pablo H

Respostas:

16

Você levanta alguns bons pontos.

  1. No que diz respeito a ter classes duplicadas, você pode alternar as classes em C #. Use por exemplo using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;Veja esta postagem no StackOverflow . Você não indicou sua linguagem de programação, mas deduzi-a do que escreveu. Portanto, onde você lida com dois projetos diferentes, é possível aliasá-los como SmurfConfiguratione WartmongerConfigurationque liberariam ambiguidade ao consumir as duas classes.

  2. Como um serviço é exposto a aplicativos externos, não vejo problema em marcar o serviço com o nome do seu aplicativo, portanto, nesse caso, SmurfServiceseria válido, pois desambiguaria grupos de serviços no aplicativo consumidor.

Sinto que os namespaces devem ser usados ​​para evitar esse estilo de nomeação. Isso torna mais difícil o grok do código e ver o valor nominal de uma classe sem ler MyCompanyMyProductMyAreaClassName. O uso da técnica de aliasing permite reduzir a ambiguidade quando necessário. A única vez em que acho que você deve introduzir complexidade em sua nomeação é, como mostrei no item 2, quando as pessoas estarão consumindo um serviço. É aqui que faz todo o sentido ter esse estilo de nomeação, porque se o consumidor tiver uma variedade de serviços, ele estará consumindo a ambiguidade que pode ser confusa.

Sam
fonte
5
aliases apenas atrapalham as coisas. Em vez de Smurf.Service, você agora tem SmurfService = Smurf.Service. Então, você deve ter o SmurfService como o nome da coisa em primeiro lugar. Eles têm um lugar, mas não para esse problema em particular. No entanto, é provavelmente a melhor resposta para um problema que não tem resposta :)
gbjbaanb
O c # em mim saiu na minha pergunta, mas atualmente estou lidando com java e org.apache.smurfville.wartmonger.configuration. Infelizmente, isso exclui aliases. 2 é um ponto sólido, por isso vou manter a marca Smurf para o Serviço.
precisa
25

O objetivo dos espaços para nome é que você possa ter classes com o mesmo nome de diferentes bibliotecas sem que elas colidam. Quando você precisar usar a mesma classe nomeada de ambos, precisará remover a ambiguidade prefixando uma ou ambas com seu escopo de espaço para nome.

Dito isto, não é tão ruim ter um monte de aulas de Smurf se o Smurf lhe disser algo específico sobre a classe. Os nomes das classes devem ser descritivos o suficiente para fornecer algumas informações sobre o que a classe faz.

      Session
       ^   ^
      /     \
DBSession   HttpSession

Da mesma forma, um DBSessionpode pegar um DBRequestobjeto que retorna um DBResponseobjeto. O HttpSessionpoder também operam em HttpRequeste HttpResponseobjetos.

Estas são aulas de Smurf com um propósito.

Eles podem viver no MyCompanyespaço de nomes, mas MyCompanyHttpSessione MyCompanyDBSessionnão dar-lhe mais alguma informação que você tinha antes. Nesse caso, solte o Smurf e faça dele um espaço para nome.

MyCompany.HttpSession
Dave Rager
fonte
3

Eu já enfrentei esse mesmo ponto de confusão antes e geralmente é realmente uma questão de incluirmos o tipo de coisa que faz parte do nome.

Você menciona SmurfConfiguratione WartmongerConfigurationcomo possíveis tipos de configurações. Você indica que removeu o adjetivo (seu tipo) em seu espaço para nome, de modo que o que resta é apenas a baunilha Configuration. Eu evitaria fazer isso.

É como decidir que sorvete de morango é apenas sorvete no espaço para nome de morango e da mesma forma com chocolate, mas o que aconteceu é que você se divorciou do adjetivo que lhe dá identidade da coisa em si. Não é sorvete na categoria de morango. É sorvete de morango - um tipo de sorvete.

Vamos imaginar que, no seu aplicativo, você importe a Strawberry.IceCreamclasse e comece a instanciar diretamente IceCream.

var ic = new IceCream(); //actually I'm strawberry ice cream

Isso pode parecer bom e bom, até o momento em que você acaba importando outra IceCreamaula. Agora você está de volta ao problema original de ter que, de alguma forma, distinguir entre eles, o que é problemático. O que você queria o tempo todo era:

var sic = new StrawberryIceCream();
var cic = new ChocolateIceCream();

É melhor deixar espaços de nome para evitar possíveis conflitos entre terceiros que possam representar incidentalmente os mesmos conceitos em suas bibliotecas. Quando um desenvolvedor cria uma biblioteca ou projeto, no entanto, ele deve nomear cada conceito exclusivamente e usar espaços de nome como pastas apenas para organização. Muitas vezes, o nome da pasta é encontrado no nome dos conceitos que ela organiza e tudo bem.

Mario T. Lanza
fonte
2

Definitivamente, é uma boa regra geral que, se você tiver um prefixo comum em várias classes, provavelmente eles merecem entrar em seu próprio espaço de nome. Para lidar com o problema, então, quando você precisar usar classes nomeadas de maneira semelhante em dois namespaces:

1) Alias ​​os namespaces, embora eu o abrevie e seja direto, qualquer abreviação natural, talvez até apenas uma letra:

using Sm = Smurf;
using W = Wartmonger;

Em seguida, sempre prefixe onde quer que seja usado e nomeie as instâncias adequadamente:

Sm::Configuration smConf; 
W::Configuration wConf;

2) Alias ​​da turma, conforme sugerido em outra resposta.

using SmConf = Smurf.Configuration;

3) Qualquer biblioteca que você tem controle, considere não usar o termo 'Configuração'. Use o dicionário de sinônimos: por exemplo, 'Configurações', 'Modelo', 'Parâmetros'. De qualquer maneira, pode ser mais significativo para o contexto: por exemplo, se o Smurf fosse algum tipo de módulo de análise numérica que você tivesse escrito, talvez 'Parâmetros' seria melhor para sua configuração. Use o vocabulário específico associado ao contexto de um módulo para sua vantagem e crie nomes exclusivos que possuem exclusividade, mesmo quando misturados em outros espaços para nome. Acho que isso pode ser uma resposta à pergunta 2 do OP.

4) Refatorar o código para que você não precise misturar o uso da configuração de dois lugares diferentes. Detalhes disso são com você.

5) Combine as duas configurações em uma antes de passar para sua classe. Use uma classe conf combinada para representar:

struct Conf {
    SmurfConfiguration smurf;
    WartmongerConfiguation wart;
}

Os nomes curtos das variáveis ​​de membro agora estão conseguindo o mesmo que aliasing a classe / namespace.

Bento
fonte
0

Parece estranho que adicionar um ponto ao nome o incomode.

Wartmonger.Configuration configuration = Wartmonger.Configuration .new();

// vs

WartmongerConfiguration configuration = WartmongerConfiguration.new();

Se ambas as configurações Smurfe Wartmongerusadas em conjunto em um local, mas separadamente, são usadas em vários locais - o espaço para nome é definitivamente uma boa abordagem.

Tendo namespace dará possibilidade de usar nomes "limpos" em código interno, onde com prefixos que você acaba usando SmurfConfigurationdentro SmurfServicedo código interno, o que pode tornar-se cada vez chato você abrir esse código.

Fabio
fonte