Cómo marcar una clase como en desarrollo en Java

12

Estoy trabajando en un proyecto de pasantía, pero tengo que irme antes de poder terminar todo.

Tengo 1 clase que no es lo suficientemente estable para uso en producción. Quiero marcar / marcar esta clase para que otras personas no la usen accidentalmente en la producción. Ya he puesto el aviso en Javadoc, pero eso no parece suficiente. Algún error o advertencia del compilador sería mejor.

El código está organizado así:

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

Si hubiera una sola clase de fábrica que llame a esas clases en métodos públicos, podría haber establecido el método class3como private. Sin embargo, la API NO está expuesta de esa manera. Los usuarios usarán directamente esa clase, por ejemplo new Class1();, pero no puedo hacer que una clase de nivel superior sea privada. ¿Cuál es la mejor práctica para lidiar con esta situación?

Wei Shi
fuente
1
¿Qué quiere decir con "La API no está expuesta a través de métodos?" ¿Esta clase está destinada a ser utilizada a través de la API de Reflection?
Tom G
55
¿Un error del compilador? ¿Por qué no simplemente lanzar una excepción en el constructor?
Mchl
Perdón por la confusion. He editado mi publicación.
Wei Shi
1
No puede hacer que la clase sea privada, pero puede hacer que su constructor sea privado.
Peter Taylor

Respuestas:

15

¿Por qué no simplemente verifica todas las clases inestables en una rama diferente en su sistema de control de versiones?

Andrew Moss
fuente
2
Me parece que esto 'ocultaría' el código. ¿Qué pasa si el código casi hace lo que otros necesitan hacer con algunos ajustes menores? Si lo pones en una rama, es posible que nunca lo vean y simplemente lo vuelvan a implementar.
c_maker
3
@c_maker: Dejar que otros sepan que la rama existe y lo que contiene debe ser parte de lo que se transmite cuando se va.
Blrfl
2
@Birlf Si le preocupa que otros no vean la explicación en el JavaDoc del código que están utilizando, dudo que busquen la otra documentación que él produce.
KeithB
Mi preocupación es que la característica todavía está evolucionando, pero el scrum master eligió dejarla de lado por cualquier motivo (moratoria que bloquea las pruebas E2E, en nuestro caso). Si no lo unimos para dominar, puede haber mucho trabajo de fusión en el futuro. Acabamos de hacer que el c`tor sea privado y anotamos la clase @Experimental, como en Spark
Joey Baruch
11

Si ha comentado correctamente la clase, puede marcar los bits de funcionalidad incompleta como "obsoletos" o comentar las tripas del método y poner un throw new UnsupportedOperationException();.

Consulte ¿Hay algo como la excepción NotImplementedException de .NET en Java? para detalles.

Heath Lilley
fuente
2
Esta es la forma de facto de lidiar con el ingenio cuando entiendo las cosas
Martijn Verburg
4

No conozco esa advertencia del compilador.

En su situación, probablemente usaría la @Deprecatedanotación. Tachará las llamadas a métodos, por lo que será obvio para los demás que algo está pasando. Cuando examinen qué sucede, verán sus comentarios sobre 'no está listo para la producción' y se convertirán en AHA.

c_maker
fuente
2
las llamadas al método solo se tachan si el IDE lo admite.
FrustratedWithFormsDesigner
55
Es cierto, pero la mayoría de las personas probablemente usarán uno de esos IDE que lo soporten.
c_maker
3

Creo que no hay una forma estándar de marcaje código como WIP, Incompleteo algo por el estilo.

Puede crear una nueva excepción llamada ClassUnstableExceptiony luego generarla en el Class3constructor con un mensaje que explique cómo no deberían usarla. Sin embargo, esto es malo, ya que solo les advierte en tiempo de ejecución.

También podría intentar hacer el incompilable clase de alguna manera, y luego añadir una nota a la sección de código que dispara el compilador de modo que si alguien va a arreglar el código que van de esperar ver una explicación de por qué no deberían usar esa clase . Es posible que esto no funcione si usan alguna herramienta semiautomática para "solucionar este problema" que tienen algunos IDE. Esto también es malo porque podría romper las compilaciones.

Puede crear una anotación llamada WIP(ya que lo más parecido que puedo pensar es Deprecatedpero realmente no significa lo mismo) y usarla para anotar la clase. Esto probablemente sería un poco más de trabajo, y ¿qué respaldaría la anotación?

Finalmente, podría ponerlo en los comentarios, pero eso solo funcionará si la gente realmente los lee .

EDITAR:

Esto puede ser relevante: ¿Cómo causar intencionalmente un mensaje de advertencia personalizado del compilador de Java?

FrustratedWithFormsDesigner
fuente
La excepción de lanzamiento hace que el eclipse se queje de un código inalcanzable. ¿Alguna solución?
Wei Shi
@Usavich: ¿No estoy seguro ya que no he visto el código, pero tal vez eso también podría ayudar a evitar que los futuros desarrolladores lo usen ?
FrustratedWithFormsDesigner
@Usavich: Eche un vistazo al enlace que agregué en EDITAR en mi publicación, es una pregunta similar en la que el OP quería agregar una advertencia de compilador personalizada. Podría ayudarlo a agregar una anotación personalizada "UnstableCode".
FrustratedWithFormsDesigner
3

¿Por qué está allí en primer lugar?

¿Ha verificado código inestable en la línea principal? ¿Por qué?

El código inestable no debe registrarse en trunk / main / master ni en el nombre principal de la troncal. Esto se considera un desarrollo de alto riesgo y, en cambio, debería haber sido secuestrado en su propia rama en la que trabajó en lugar de registrarse en main.

Le recomiendo encarecidamente (y a su líder de equipo) que lea Estrategias avanzadas de ramificación SCM . En particular, preste atención al rol de desarrollo y lo que dice sobre lo que se considera desarrollo de alto riesgo:

En general, considere usar sucursales separadas para cada proyecto de alto riesgo. Los proyectos de alto riesgo se caracterizan por un gran tamaño, un gran número de personas, un tema desconocido, un tema altamente técnico, plazos muy ajustados, fechas de entrega inciertas, requisitos incompletos o volátiles y equipos de proyectos distribuidos geográficamente. Del mismo modo, considere designar una sola rama para el desarrollo de bajo riesgo en cada versión. Varias fuentes, incluida [WING98], recomiendan utilizar la línea principal para este propósito. Considere los factores discutidos anteriormente para la línea principal antes de comprometerse con este curso de acción. El desarrollo de bajo riesgo puede tener una política diferente de la línea principal, incluso si tiene varios miembros de una familia de productos que coordinan a través de la línea principal.

Permitir que las personas verifiquen el código inestable (o no utilizado) en la línea principal significa que confundirá los futuros esfuerzos de desarrollo al tratar de mantener este código. Cada rama y clon del representante desde ahora hasta el final de los tiempos contendrá esto hasta que alguien diga "su código muerto" y lo elimine.

Hay algunos que dicen "bueno, si está en una rama se olvida" y aunque eso puede ser cierto, haber olvidado el código muerto (e inestable) en la línea principal es muchas veces peor, ya que confunde todo el desarrollo futuro hasta que se elimine, y entonces es aún más olvidado. Una rama bien nombrada de "/ fooProject / sucursales / WeisBigIdea" (o equivalente) es visible y más fácil de trabajar en el futuro, especialmente si funciona.

@Deprecated

Lo primero es la @Deprecatedanotación. Esto va más allá del javadoc y escupe advertencias del compilador. javacproporciona una -deprecationbandera que se describe como:

Mostrar una descripción de cada uso o anulación de un miembro o clase en desuso. Sin -deprecation, javacmuestra un resumen de los archivos de origen que usan o anulan miembros o clases en desuso. -deprecation es la abreviatura de -Xlint:deprecation.

Como se señaló, esto va más allá de las advertencias estándar del compilador.

En muchos IDEs, los métodos y valores obsoletos se muestran con un tachado:

foo.bar();

Y produciría resultados como:

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

Dependiendo de su estructura de construcción, es posible que haya advertencias que rompan la construcción. Esto solo rompería la compilación si se usara una de sus clases (no si simplemente se compila).

@CustomAnnotation

Hay muchos enfoques para esto. Por ejemplo, la anotación Lightweight javac @Warning que proporciona un procesador de anotación que dispara una advertencia en el momento de la compilación cuando se usa algo con esa anotación ( un tutorial de netbeans sobre procesadores de anotación personalizados para que pueda tener una idea de lo que está sucediendo detrás del escenas)

Oracle incluso describe un ejemplo del uso de anotaciones personalizadas para una @Unfinishedanotación en Cómo aprovechar al máximo los metadatos de Java, Parte 2: Anotaciones personalizadas .

Con el AnnotationProcessor , puede ejecutar código arbitrario en tiempo de compilación. Realmente depende de usted decidir qué quiere que haga. Advertir, romper la construcción cuando se usa algo. Existen numerosos tutoriales en la web sobre cómo escribir este tipo de código. Si desea generar un error cuando se compila (esto será molesto y provocará que se elimine) o si se usa (bastante más complejo de escribir).

Tenga en cuenta que todo esto implica cambiar las compilaciones para utilizar realmente el procesador de anotaciones.


fuente
2

Usted podría introducir procesamiento de anotación de tiempo de compilación , pero esto haría cumplir todos los miembros del equipo para ajustar su proceso de compilación.

Sin embargo, encuentro todo el proceso un poco confuso. Una API inestable debe separarse claramente creando una rama en su sistema de control de versiones. Si realmente tiene que estar en el resto de la base de código, se ha documentado como inestable y, sin embargo, se ha utilizado, el problema no es realmente técnico, sino que se encuentra dentro de la organización y la comunicación. Sí, podría introducir verificaciones técnicas (como el procesamiento de anotaciones) pero eso no resolvería el problema, simplemente muévalo a otro nivel.

Entonces, mi recomendación es: si no puede separar la base del código colocándola en diferentes ramas, hable con las personas y explíqueles por qué no deben usar la API.

perdian
fuente
0

¿Podría mover todas las clases incompletas a un subpaquete llamado algo obvio como "NO COMPLETO"? Es un truco, pero puede ser lo suficientemente visible.

(Si no están todos en el mismo paquete, puede volver a crear la estructura del paquete debajo).

Alex Feinman
fuente
0

No sé si realmente hay una buena manera de hacer esto en el código. Da un paso atrás:

Cree dos copias de todo el proyecto, una con la clase y otra sin ella. Marque la versión sin la clase como una base de código estable, lista para el lanzamiento de producción, y la versión con la clase como desarrollo para un lanzamiento futuro. Documente lo que debe suceder antes de que esta clase pueda considerarse calidad de producción.

Idealmente, debe hacer esto utilizando ramas en la solución de control de origen de su elección. Sin embargo, es posible que tenga que hacer un poco de trampa, ya que parece que no ha estado utilizando una estrategia de ramificación de este tipo. Elimine cuidadosamente la nueva clase, registre una versión sin ella y realice algunas pruebas de regresión. Cuando esté satisfecho de que es estable, puede etiquetar esa revisión, crear una rama de desarrollo a partir de la etiqueta y luego agregar la clase nuevamente en la rama de desarrollo.

Adam Jaskiewicz
fuente
0

Optaría por hacer que la clase sea abstracta y comentar apropiadamente; de ​​esa manera, el código todavía está allí como referencia, pero buena suerte a cualquiera que intente instanciarlo :)

Phil Lello
fuente
-1

¿Qué hay de hacer una dependencia que el compilador no puede resolver? Solo agrega:

import this.is.not.done.yet.do.not.use.it;

a la cima. Los usuarios no podrán compilar con él.

Si desea probar la clase, simplemente cree un paquete / clase con ese nombre (o use uno más simple como "experimental.danger") y puede probar el nuevo código.

Neal Tibrewala
fuente
1
La compilación fallará incluso si no la uso ... mala idea ...
Silviu Burcea