Como sinalizar uma classe como em desenvolvimento em Java

12

Estou trabalhando em um projeto de estágio, mas tenho que sair antes que eu possa terminar tudo.

Eu tenho 1 classe que não é estável o suficiente para uso em produção. Quero marcar / sinalizar esta classe para que outras pessoas não a usem acidentalmente na produção. Eu já coloquei o aviso em Javadoc, mas isso não parece suficiente. Algum erro ou aviso do compilador seria melhor.

O código está organizado assim:

[Package] | company.foo.bar.myproject
          |-- Class1.java
          |-- Class2.java
          |-- Class3.java <--(not stable)

Se houvesse uma única classe de fábrica que chama essas classes em métodos públicos, eu poderia ter definido o método class3como private. No entanto, a API NÃO é exposta dessa maneira. Os usuários usarão diretamente essa classe, por exemplo new Class1();, mas eu não posso tornar uma classe de nível superior privada. Qual é a melhor prática para lidar com essa situação?

Wei Shi
fonte
1
O que você quer dizer com "A API não é exposta por métodos?" Esta classe deve ser usada através da API de reflexão?
Tom G
5
Um erro do compilador? Por que não apenas lançar uma exceção no construtor?
Mchl
Desculpe pela confusão. Eu editei minha postagem.
Wei Shi
1
Você não pode tornar a classe privada, mas pode tornar seu construtor privado.
Peter Taylor #

Respostas:

15

Por que não apenas verificar todas as classes instáveis ​​em uma ramificação diferente no seu sistema de controle de versão?

Andrew Moss
fonte
2
Parece-me que isso "ocultaria" o código. E se o código quase fizer o que os outros precisam fazer com alguns pequenos ajustes. Se você colocá-lo em uma ramificação, eles podem nunca vê-lo e apenas reimplementam a coisa toda.
c_maker
3
@c_maker: Avisar os outros que o ramo existe e o que está nele deve fazer parte do que é passado quando ele sai.
Blrfl
2
@ Birlf Se ele está preocupado com os outros que não vêem a explicação no JavaDoc do código que eles estão usando, duvido que eles procurem a outra documentação que ele produz.
KeithB
Minha preocupação é que o recurso ainda esteja evoluindo, mas o scrum master optou por deixá-lo de lado por qualquer motivo (moratória que bloqueia o teste E2E, no nosso caso). Se não juntarmos a ela para dominar, pode haver muito trabalho de mesclagem no caminho. Acabamos de tornar o c'tor privado e anotamos a classe @Experimental, como no Spark
Joey Baruch
11

Se você tiver comentado corretamente a classe, poderá marcar os bits da funcionalidade incompleta como "obsoletos" e / ou comentar os detalhes do método e colocar a throw new UnsupportedOperationException();.

Consulte Existe algo como o NotImplementedException do .NET em Java? para detalhes.

Heath Lilley
fonte
2
Esta é a maneira de lidar defacto hit wit como eu entendo as coisas
Martijn Verburg
4

Não conheço esse aviso do compilador.

Na sua situação, eu provavelmente usaria a @Deprecatedanotação. Ele cruzará as chamadas de método, para que seja óbvio para os outros que algo está acontecendo. Quando eles analisarem o que está acontecendo, eles verão seus comentários sobre "a produção não está pronta" e serão enviados para a AHA.

c_maker
fonte
2
As chamadas de método somente serão riscadas se o IDE suportar.
FrustratedWithFormsDesigner
5
É verdade, mas a maioria das pessoas provavelmente usará um desses IDEs que o suporta.
c_maker
3

Eu não acho que há uma maneira padrão de marcação código como WIP, Incompleteou algo parecido.

Você pode criar uma nova exceção chamada ClassUnstableExceptione, em seguida, aumentá-la no Class3construtor com uma mensagem que explica como eles não devem usá-la. Isso é ruim, porque apenas os avisa em tempo de execução.

Você também pode tentar tornar a classe incompilável de alguma forma e, em seguida, adicionar uma nota à seção de código que aciona o compilador, de modo que, se alguém for consertar o código, esperançosamente verá uma explicação de por que não deve usar essa classe. . Isso pode não funcionar se eles usarem uma ferramenta semi-automatizada de "corrigir esse problema" que alguns IDEs possuem. Isso também é ruim porque pode quebrar as compilações.

Você pode criar uma anotação chamada WIP(já que a mais próxima que eu consigo pensar é, Deprecatedmas na verdade não significa a mesma coisa) e usá-la para anotar a classe. Provavelmente isso seria um pouco mais trabalhoso, e o que apoiaria a anotação?

Por fim, você pode colocá-lo nos comentários, mas isso só funcionará se as pessoas realmente os lerem .

EDITAR:

Isso pode ser relevante: Como causar intencionalmente uma mensagem de aviso do compilador java personalizado?

FrustratedWithFormsDesigner
fonte
Uma exceção de lançamento faz o eclipse reclamar de código inacessível. Alguma solução alternativa?
Wei Shi
@ Usavich: Não tenho certeza, pois não vi o código, mas talvez isso também ajude a impedir que futuros desenvolvedores usem o código?
FrustratedWithFormsDesigner
@Usavich: Dê uma olhada no link que eu adicionei no EDIT no meu post, é uma pergunta semelhante em que o OP queria adicionar um aviso de compilador personalizado. Pode ajudar a adicionar uma anotação "UnstableCode" personalizada.
FrustratedWithFormsDesigner
3

Por que está lá em primeiro lugar?

Você verificou código instável na linha principal? Por quê?

O código instável não deve ser verificado no tronco / principal / mestre ou seja qual for o nome do tronco principal. Isso é considerado um desenvolvimento de alto risco e, em vez disso, deveria ter sido isolado em seu próprio ramo em que você trabalhou, em vez de fazer o check-in no main.

Eu o incentivaria fortemente (e o líder da sua equipe) a ler Estratégias avançadas de ramificação do SCM . Em particular, preste atenção ao papel do desenvolvimento e ao que ele diz sobre o que é considerado desenvolvimento de alto risco:

Em geral, considere o uso de ramificações separadas para cada projeto de alto risco. Projetos de alto risco são caracterizados por tamanho grande, grande número de pessoas, assuntos desconhecidos, assuntos altamente técnicos, prazos muito curtos, datas de entrega incertas, requisitos incompletos ou voláteis e equipes de projeto distribuídas geograficamente. Da mesma forma, considere designar uma única ramificação para desenvolvimento de baixo risco em cada release. Várias fontes, incluindo [WING98], recomendam o uso da linha principal para esse fim. Considere os fatores discutidos acima para a linha principal antes de se comprometer com este curso de ação. O desenvolvimento de baixo risco pode ter uma política diferente da linha principal, mesmo se você tiver vários membros de uma família de produtos coordenando a linha principal.

Permitir que as pessoas verifiquem código instável (ou não usado) na linha principal significa que você confundirá esforços futuros de desenvolvimento sobre a tentativa de manter esse código. Cada ramo e clone do representante a partir de agora até o final dos tempos conterá isso até que alguém diga "seu código morto" e o exclua.

Há quem diga "bem, se estiver em um ramo, ele será esquecido" e, embora isso possa ser verdade, ter esquecido o código morto (e instável) na linha principal é muitas vezes pior, pois confunde todo o desenvolvimento futuro até que seja removido - e então é ainda mais esquecido. Um ramo bem nomeado de "/ fooProject / branches / WeisBigIdea" (ou equivalente) é visível e mais fácil de se trabalhar no futuro - especialmente se funcionar.

@Deprecated

A primeira coisa é a @Deprecatedanotação. Isso vai além do javadoc e cospe avisos do compilador. javacfornece um -deprecationsinalizador descrito como:

Mostre uma descrição de cada uso ou substituição de um membro ou classe reprovada. Sem -deprecation, javacmostra um resumo dos arquivos de origem que usam ou substituem membros ou classes obsoletos. -preciação é uma abreviação de -Xlint:deprecation.

Como observado, isso vai além dos avisos padrão do compilador.

Em muitos IDEs, métodos e valores obsoletos são mostrados com um rasurado:

foo.bar();

E produziria saída como:

$ javac -Xlint:all Foo.java Bar.java
Bar.java:2: warning: [deprecation] Foo in unnamed package has been deprecated
interface Bar extends Foo { }
                      ^

Dependendo da sua estrutura de construção, você pode receber avisos para interromper a construção. Isso apenas interromperia a compilação se uma de suas classes fosse usada (não se for simplesmente compilada).

@CustomAnnotation

Existem muitas abordagens para isso. Por exemplo, a anotação Lightweight javac @Warning, que fornece um processador de anotações que dispara um aviso no momento da compilação quando algo com essa anotação é usado ( um tutorial do netbeans sobre processadores de anotações personalizados, para que você possa ter uma idéia do que está acontecendo por trás do cenas).

A Oracle ainda descreve um exemplo de uso de anotações personalizadas para uma @Unfinishedanotação em Aproveitando ao máximo os metadados do Java, parte 2: anotações personalizadas .

Com o AnnotationProcessor , você pode executar código arbitrário em tempo de compilação. É realmente você quem decide o que deseja fazer. Aviso, quebre a construção quando algo for usado. Existem inúmeros tutoriais disponíveis na Web sobre como escrever esse tipo de código. Se você deseja gerar um erro quando ele é compilado (isso será irritante e leva à exclusão) ou se é usado (um pouco mais complexo de escrever).

Observe que tudo isso implica alterar as compilações para realmente usar o processador de anotações.


fonte
2

Você pode introduzir o processamento da anotação em tempo de compilação, mas isso forçaria todos os membros da equipe a ajustar seu processo de compilação.

No entanto, acho todo o processo um pouco confuso. Uma API instável deve ser claramente separada criando uma ramificação em seu sistema de controle de versão. Se ele realmente precisa estar no restante da base de código, foi documentado como instável e, no entanto, usado, o problema não é realmente técnico, mas está dentro da organização e da comunicação. Sim, você pode introduzir verificações técnicas (como o processamento de anotações), mas isso não resolveria o problema - basta movê-lo para outro nível.

Portanto, minha recomendação é: se você não pode separar a base de código colocando-a em diferentes ramos, converse com as pessoas e explique a elas por que elas não devem usar a API.

perdian
fonte
0

Você poderia mover todas as classes incompletas para um subpacote chamado algo óbvio como "NOTCOMPLETE"? É um pouco complicado, mas pode ser visível o suficiente.

(Se eles não estiverem todos no mesmo pacote, você poderá recriar a estrutura do pacote.)

Alex Feinman
fonte
0

Não sei se existe realmente uma boa maneira de fazer isso no código. Dê um passo para trás:

Crie duas cópias de todo o projeto, uma com a classe e outra sem. Marque a versão sem a classe como uma base de código estável, pronta para o release de produção e a versão com a classe como desenvolvimento para um release futuro. Documente o que precisa acontecer antes que essa classe possa ser considerada como qualidade de produção.

Idealmente, você deve fazer isso usando ramificações em sua solução de controle de origem de sua escolha. Talvez você precise trapacear um pouco, pois parece que você não está usando uma estratégia de ramificação. Remova com cuidado a nova classe, faça o check-in de uma versão sem ela e faça alguns testes de regressão. Quando estiver satisfeito, é estável, você pode marcar essa revisão, criar um ramo de desenvolvimento a partir da marca e adicionar a classe novamente no ramo de desenvolvimento.

Adam Jaskiewicz
fonte
0

Eu optaria por tornar a classe abstrata e comentar adequadamente - dessa forma, o código ainda está lá para referência, mas boa sorte para quem tentar instanciar :)

Phil Lello
fonte
-1

Que tal criar uma dependência que o compilador não pode resolver? Basta adicionar:

importar este.não.um.done.no.do.não.utilizar;

para o topo. Os usuários não poderão compilar com ele.

Se você quiser testar a classe, simplesmente crie um pacote / classe com esse nome (ou use um mais simples como "experimental.danger") e poderá testar o novo código.

Neal Tibrewala
fonte
1
A compilação irá falhar, mesmo se eu não usá-lo ... má idéia ...
Silviu Burcea