Suena bastante básico, lo sé, pero recientemente tuve un colega que me dijo que un método llamado startHttpServer
es demasiado complicado de entender porque solo inicia el servidor si aún no se está ejecutando. Encuentro que me meto en problemas cuando respondo: "¿En serio? He estado haciendo esto durante décadas, es un patrón común en la programación". Más a menudo de lo que me importa admitir que regresa con alguna evidencia documentada que muestra que toda la comunidad de programación está detrás de su punto de vista y termino sintiéndome avergonzado.
Pregunta : ¿Existe un patrón de diseño documentado detrás del concepto de un método que no funciona si la acción requerida ya está vigente? O, si no es un patrón, ¿tiene un nombre? Y si no, ¿hay alguna razón para pensar que es demasiado complicado considerar escribir un método de esta manera?
fuente
startHttpServer
), y sí, el término "idempotente" se aplica aquí bien.Respuestas:
Como NickWilliams ya ha dicho : el concepto que describe el OP se llama idempotente (sustantivo Idempotency ). De hecho, es una práctica común, especialmente en las API de alto nivel.
PERO: Cambiar el nombre de la función.
En lugar de
startHttpServer
llamarlomakeSureHttpServerIsRunning
oensureHttpServerIsRunning
.Cuando se llama a una función
startHttpServer
, los lectores esperan que inicie un servidor HTTP; cuando me llamen diez veces seguidas, tendré diez servidores ejecutándose. Su función no hace eso la mayor parte del tiempo. Además, el nombre con "inicio" sugiere que si quiero que solo se ejecute un servidor, tendré que hacer un seguimiento de si la función ya se ha llamado o no.Cuando se llama a una función
makeSureHttpServerIsRunning
, supongo que hará lo necesario para asegurarse de que se está ejecutando un servidor HTTP, lo más probable es que verifique si ya se está ejecutando y lo inicie de otra manera. También supongo que la función se asegura de que el servidor se esté ejecutando realmente (iniciar un servidor puede implicar un tiempo en el que aún no se está ejecutando).fuente
Renombrarlo a
EnsureServerRunning
.Completamente inequívoco y está claro que se asegura de que se esté ejecutando (si no lo está) sin implicar un reinicio si lo está.
(Alternativa
StartServerIfNotRunning
:?)fuente
No es realmente un patrón de diseño, pero llamaría idemotente a su método . Su término generalmente se usa para referirse a llamadas remotas, pero la descripción parece coincidir con lo que está haciendo.
El efecto secundario del servidor aquí es que el servidor http se inicia una vez que se llama al método. No veo nada de malo con un método que haga esto.
Si necesita un patrón de diseño, supongo que podría exponer su httpServer como un singleton que se inicia cuando se inicializa.
fuente
Como el que implementar esta herramienta ,
startHttpServer
, usted debe estar tratando de hacer que sea lo más simple, suave y sin costuras para uso ...La lógica de la función
Técnicamente, al dividir
startHttpServer
la lógica en 2 funciones y llamarlas por separado , todo lo que haces es moverstartHttpServer
la idempotencia al código que llama a ambas funciones en su lugar ... Además, a menos que envuelva ambas lógicas en una tercera función (que es lo que hacestartHttpServer
en primer lugar), esto te obliga a escribir código sin DRY, duplicándolo exponencialmente en todas partes a las que deberías llamarstartHttpServer
. En resumen,startHttpServer
tiene que llamarse a sí mismo laisHttpServerRunning
función.Entonces mi punto es:
isHttpServerRunning
función porque esto puede ser necesario independientemente de todos modos ...startHttpServer
hacer que se useisHttpServerRunning
para definir su próxima acción en consecuencia ...Aún así, puede
startHttpServer
devolver cualquier valor que el usuario de esta función pueda necesitar, por ejemplo:0
=> falla de inicio del servidor1
=> servidor iniciando con éxito2
=> el servidor ya se inicióEl nombre de la función.
En primer lugar, ¿cuál es el objetivo principal del usuario? Para iniciar el servidor HTTP , ¿verdad?
Fundamentalmente, no hay ningún problema al intentar comenzar algo que ya se ha iniciado, también conocido como AKA
1*1=1
. Entonces, al menos para mí, llamarlo "ensureHttpServerIsRunning
" parece no ser críticamente necesario, me importaría más cuánto tiempo, natural y memorable sea el nombre de la función.Ahora, si desea saber cómo funciona en detalle la función bajo el capó, existe la documentación o el código fuente para eso, me refiero a cualquier otra función de biblioteca / marco / API / etc ...
Usted aprenderá la función de una vez mientras que escribir varias veces ...
De todos modos, me quedaría con lo
startHttpServer
que es más corto, más simple y más explícito queensureHttpServerIsRunning
.fuente
Supongo que su colega quería decir que
startHttpServer
está haciendo demasiado:Esas son dos partes de código no relacionadas. Por ejemplo, existe una situación similar cuando una aplicación de escritorio debe asegurarse de que no se esté ejecutando cuando se inicia; habrá una parte del código que maneja las instancias de la aplicación (por ejemplo, usando un mutex), y el código que iniciará el bucle de mensajes de la aplicación.
Esto significa que debe tener no uno, sino al menos dos métodos :
isHttpServerRunning: boolean
startHttpServer
El punto de entrada de la aplicación llamará al primer método, y luego al segundo si el valor de retorno es
false
. Ahora, cada método está haciendo una cosa y es fácil de entender.¹ Si la lógica necesaria para saber si el servidor ya se está ejecutando es demasiado compleja, puede requerir una separación adicional en varios métodos.
fuente
startHttpServer
se llama más de un lugar en el código? ¿Deberían copiarse múltiples líneas similares en todas partes? ¿Debería hacerse esto con todas las funciones? Muy pronto su programa tendrá un tamaño infinito.startHttpServer
método será más o menos similarif (isHttpServerRunning()){ return; }
. Usted está afirmando una regla de negocios que "no es válido iniciar el servidor http si ya se está ejecutando", pero luego es responsabilidad de otra persona hacer cumplir esa regla. Ad-hoc y repetidamente en cada lugar donde puedan llamarstartHttpServer
.Como no especifica un idioma, en JavaScript muchas bibliotecas tienen una función de "una vez", por ejemplo, subrayado . Entonces, si eso le resulta familiar, llámelo "una vez" y posiblemente cambie el nombre de su método.
Yo mismo, viniendo más de Java, me vienen a la mente los términos "almacenamiento en caché" o "evaluación perezosa". "Idempotente" es técnicamente correcto y una buena opción, especialmente. si tienes un fondo más funcional.
fuente
restartHttpServer()
método raramente utilizado . Pero solo parando : ¿cuál es el caso de uso allí? ¿Te gustan los fallos de conexión esporádicos? :-)ensureRunning()
? :-) En cuanto a que el administrador lo detenga, tener este otro código reiniciando constantemente mientras el administrador intenta modificar o arreglar algo sería increíblemente molesto e incorrecto. Deje que el administrador lo reinicie, no el código.Yo prefiero
startHttpServerIfNotIsRunning
.De esta manera, la condición ya se menciona claramente en el nombre del método.
Ensure
o memakeSure
parece un poco vago, ya que no es una expresión técnica. Parece que no sabemos exactamente qué va a pasar.fuente
Ensure
significa. Todavía no me gusta esta palabra para una expresión técnica.Ensure
Es algo humano. Un sistema no puede garantizar nada, solo hará lo que se supone que debe hacer.Lo que su colega debería haberle dicho es que no tiene por qué escribir ese método. Ya se ha escrito muchas veces, y se ha escrito mejor de lo que es probable que lo escriba. Por ejemplo: http://docs.ansible.com/ansible/latest/systemd_module.html https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html
Desde una perspectiva arquitectónica, tener un poco de código arbitrario para administrar un servidor web es cosa de pesadillas. A menos que administrar servicios sea exclusivamente lo que hace su código. Pero supongo que no escribiste monit (o kubernetes o ...).
fuente
startServer
función o similar es algo poco común . Eso no significa que va a escribir los detalles esenciales de bajo nivel.