¿Cuándo es aceptable NO reparar ventanas rotas?


21

En referencia a las ventanas rotas , ¿hay momentos en que es mejor dejar la refactorización para una actividad futura?

Por ejemplo, si un proyecto para agregar algunas características nuevas a un sistema interno existente se asigna a un equipo que no ha trabajado con el sistema hasta ahora, y se le da una breve línea de tiempo para trabajar, ¿puede justificarse alguna vez? diferir las refactorizaciones importantes al código existente en aras de cumplir con la fecha límite en este escenario?


66
A veces, el jefe decide que las ventanas rotas no se arreglarán, porque sabe que ganará mucho más dinero arreglando toda la casa más tarde.
mouviciel

1
regla básica: la deuda técnica está bien para alcanzar una fecha límite, pero eventualmente debe ser compensada y cuanto antes mejor
JF Dion

44
¡Felicidades! Usted describió perfectamente la "filosofía de diseño" de PHP.
ThomasX


44
El mañana nunca llega ...
Eric King

Respuestas:


25

La refactorización es, y debería ser, un proceso continuo. No es suficiente simplemente cumplir los requisitos con una implementación funcional y probada que todavía está un poco incompleta.

"Haz que funcione, luego haz que funcione mejor" .

No recuerdo dónde leí esa cita, pero esta es la clave para aplicar bien la refactorización, y lo considero poco profesional para hacer lo contrario.

La refactorización continua es como limpiar los derrames mientras cocina y limpiar los platos después de haber comido. La refactorización dirigida es como encontrar una cocina sucia, pero solo tener tiempo para lavar uno o dos vasos sucios. ¿Prefieres vivir con una cocina continuamente sucia o prefieres mantener las cosas limpias a medida que avanzas?

Obtiene el código para trabajar, luego refactoriza su código para asegurarse de que tiene la mejor implementación que pueda usar. Si está haciendo algo familiar, puede ser que implemente el mejor código la primera vez, sin embargo, lleva un momento verificar dos veces su trabajo para estar seguro. Si parece que podría mejorar su código, entonces intente refactorizar para asegurarse de que su código sea al menos tan simple y limpio como pueda hacerlo. Esto significa que está reduciendo la cantidad de deuda técnica que deja atrás, y hace que sea más fácil de leer y refactorizar la próxima vez que deba tratar el código. Este es el valor central detrás del mantra TDD "Red-Green-Refactor", excepto que en TDD refactoriza principalmente para eliminar la duplicación, también vale la pena revisar otros elementos que podrían ser refactorizados, como clases grandes, métodos largos,

Si se enfrenta a un rediseño importante, entonces tal vez pueda posponerlo por un tiempo, especialmente si se está quedando sin tiempo en su agenda. Sin embargo, esto siempre que la funcionalidad de su código no se vea comprometida, y también siempre que la implementación continúe cumpliendo con los requisitos. Este tipo de situación debería ser algo raro, y puede ayudar a garantizar que sea aún más raro si está refactorizando continuamente a medida que avanza. Sin embargo, aún más importante es que no puede arriesgarse a dejar sus cambios importantes durante demasiado tiempo, de lo contrario terminará creando una carga de trabajo aún más grande que podría ser mucho más costosa de arreglar o podría resultar en un costo aún más costoso fracaso del proyecto

Tengo la impresión de que muchas personas tienden a confundir las definiciones de Refactorización y Reingeniería . Los dos términos describen estrategias para manejar situaciones muy diferentes. Si desea rediseñar, se compromete a realizar un cambio drástico que alterará el comportamiento de un sistema. Esto invalidará algunas pruebas y también requerirá nuevas pruebas. Cuando refactoriza, se asegura de que su sistema continúe comportándose exactamenteigual que antes del cambio, sin embargo, también se asegura de que su código tenga longevidad y que sea más fácil de mantener con el tiempo. No está "proxenetizando" su código por el mero hecho de hacerlo, se está comprometiendo con un estándar profesional de código limpio que reducirá el riesgo de falla y garantizará que su código siga siendo un placer trabajar con él y con un estándar profesional .

Volviendo a la analogía de las ventanas rotas, si rompe la ventana, debe repararla de inmediato. Si no se ha dado cuenta de que una ventana está rota, debe decidir el costo si deja la ventana rota. Ahora, repita las dos oraciones anteriores, pero sustituya Bug por ventana. Terminas necesitando una estrategia diferente. Si ha creado un error mientras codifica, lo arregla de inmediato, o ve si los cambios requerirán un esfuerzo de reingeniería, y toma una decisión comercial sobre cuándo será mejor solucionar el problema. Por lo tanto, no refactoriza para solucionar un problema, refactoriza para asegurarse de que sea más fácil encontrar y solucionar problemas. No me importa lo increíble que creas que es tu código, los sistemas complejos siempre tendrán problemas que deberán abordarse con el tiempo. De esto se trata la deuda técnica, y por qué la refactorización debe ser un proceso continuo a medida que implemente su código , y no dejarla para un tiempo futuro arbitrario.

En resumen, la respuesta de que en raras ocasiones puede ser aceptable diferir los cambios importantes en el código para establecer una fecha límite, sin embargo, no debe considerarse una práctica normal tratar la refactorización como un ejercicio independiente de su trabajo de implementación diario, y ciertamente nunca utilizado como una excusa por equipos que no están familiarizados con el código base como una opción para evitar asegurarse de que su implementación sea tan simple y limpia como puedan hacerlo bajo las circunstancias.


Me gusta la cita.
Marjan Venema

1
En demasiados lugares, los "tiempos raros" son la norma.
ozz

2
Si solo los "diseñadores" de PHP reconocieran esa cita ...
ThomasX

1
Gran cita, piense en esto: ¿quiere que el pintor de su automóvil aplique la misma lógica para reparar su Toyota 1999? Y si es así, ¿está preparado para pagar por un acabado de pintura Roll Royce en un automóvil de $ 1000?
mattnz

@mattnz Su analogía realmente no es válida para el desarrollo de software. Este no es un caso de "chapado en oro", es un anticipo de costo relativamente bajo para garantizar que obtenga el máximo rendimiento de su inversión. Robar su analogía de la pintura, también es la diferencia entre golpear una capa de pintura en su automóvil con una brocha ancha o usar una cabina de pintura para obtener un acabado uniforme y agradable. Obtienes lo que pagas, ¿quieres pagar la tarifa de un profesional y recibir un trabajo a medio terminar? Cortar esquinas puede ahorrar un poco en el corto plazo, pero incurrirá en una mayor deuda técnica a largo plazo.
S.Robins

11

Algunos desarrolladores dicen que están "arreglando ventanas rotas" cuando realmente están "reorganizando las tumbonas en el Titanic". Refactorizar el código que funciona pero ofende su sentido del olfato es relativamente fácil. Si descubre que sigue volviendo a ese tipo de tarea en lugar de agregar nuevas capacidades para sus usuarios o hacer que la aplicación sea más útil para ellos (la optimización significa que hacer que la aplicación funcione más rápido es bueno aquí, la optimización significa que el código sea más legible es diferente) entonces quizás estás ordenando demasiado. No porque ordenar es malo, sino porque la compañía está pagando por el desarrollo para desarrollar algo. Sin duda, no quieren una solución frágil, difícil de leer y mal diseñada, pero tampoco quieren una media solución hermosa y pulida.

Ordene cuando necesite hacer algo simple "para ponerse en marcha", o cuando esté esperando que otro equipo le diga si su problema es realmente culpa suya, o cuando esté esperando una decisión. Habrá muchas oportunidades. Si tienes la oportunidad de mover toda la aplicación hacia adelante, tómala, a menos que comiences a sentir que todo se ha vuelto frágil. Probablemente no lo haya hecho. Tendrá la oportunidad de refactorizar, no necesita preocuparse por eso.

Para volver a la segunda mitad de su pregunta, un sprint para agregar características que se enfrentan a una línea de tiempo corta, sería un error decir "y no haremos ninguna refactorización, no hay tiempo". También sería un error decir "Sé que han pasado 6 semanas y parece exactamente igual para los usuarios, pero estas ventanas rotas realmente necesitan ser reparadas". Ajuste la refactorización en las brechas que suceden en cualquier proyecto. No se refugie en ordenar a costa de cumplir con el objetivo del proyecto.


44
Algunos desarrolladores dicen que están "arreglando ventanas rotas" cuando realmente están "reorganizando las tumbonas en el Titanic" ; de hecho, a menudo parece difícil para los desarrolladores distinguir entre "deuda técnica" y "no de la forma en que yo lo haría". lo he hecho "
RevBingo

9

Desde una perspectiva comercial, la refactorización es una inversión especulativa: invertir tiempo y esfuerzo (dinero) ahora, con la esperanza de que ahorrará más tiempo y esfuerzo (dinero) en algún momento en el futuro.

Sin entrar en el debate sobre cuánto ahorrará el esfuerzo para refactorizar en el futuro (esto depende de demasiadas variables para que sea una discusión significativa aquí), está claro que es el momento de refactorizar cuando el "valor presente neto" del costo que lo deja excede el costo de hacerlo ahora.

Eso es fácil, excepto que no tienes idea de cuánto costará el futuro. También debe tener en cuenta todas las ideas normales de planificación financiera, como el retorno de la inversión, la gestión del riesgo (valor de la marca, responsabilidad legal, riesgo asegurable frente a no asegurable), costo de la operación, etc.

En la mayoría de los casos, es mejor decidir cuándo refactorizar a las personas que dirigen el negocio. A pesar de lo que dicen muchos carteles en este foro, los gerentes generalmente saben más sobre la administración de un negocio que los programadores. Tienen una idea más amplia en mente que incluye maximizar la rentabilidad para el accionista. Es raro que arreglar cosas que no están rotas contribuya a esto, el código no es una excepción.

Editar: He leído un artículo interesante sobre programas de mantenimiento en infraestructura crítica. La esencia es que el movimiento está lejos de la rutina de mantenimiento (refactor) para reparar cuando sea necesario (corregir errores). La principal diferencia son los niveles de monitoreo: por ejemplo, una planta de energía nuclear monitorea con gran detalle y repara cuando está "rota" pero mucho antes de fallar. Lo que se ha encontrado es que la fijación a un esquema de mantenimiento no solo cuesta más, sino que es menos confiable debido a interrupciones causadas por el programa de mantenimiento. Se requiere una idea similar para el software: refactorizar los bits que están a punto de romperse, lo que solo se puede saber por medición.


44
+1 a pesar de los errores ortográficos :); la mayoría de las veces el cliente no está pagando por un código limpio, está pagando por un resultado. Si tiene un código limpio y no tiene resultados, no se le paga y no estará refactorizando por mucho tiempo.
jasonk

2
Solo quiero señalar que es bastante común que el Gerente tenga una mejor idea del negocio en general. Desafortunadamente, a menudo tienen un sentido MUCHO peor de lo que costará el código incorrecto en el futuro, así que asegúrese de que su gerente tenga algunos datos de costos razonables para trabajar, si va a confiar en el gerente para tomar esta decisión.
Michael Kohne

La otra forma de ver la Refactorización no es algo que decida hacer como una tarea objetivo, sino como un medio para asegurarse de que no se tropiece mientras desarrolla un sistema. A menudo, encontrará un código mal factorizado que le hará seguir modificando las pruebas y tratando de apagar incendios mientras avanza. Como resultado, esto puede costarle a su cliente más por adelantado. Mantener el código limpio no debe verse como un chapado en oro de su código, sino como un estándar profesional para ofrecer resultados exitosos.
S.Robins

1
@ S.Robins Estamos hablando de refactorización y no de código mal factorizado (en mi opinión, el segundo es un problema, el primero es bueno tenerlo).
jasonk

5

Es aceptable cuando el daño al negocio al repararlos es mayor que al no repararlos.

Las situaciones en las que esto ocurre pueden ser:

  • donde se puede perder una fecha límite u oportunidad de negocio debido al tiempo necesario para arreglar
  • donde un código está (genuinamente) programado para ser retirado en una escala de tiempo muy corta, por lo tanto, casi no hay ningún beneficio en refactorizarlo.

Y estas situaciones sí ocurren: las situaciones comerciales a menudo idearán plazos artificiales que deben cumplirse cuando haya pasado la oportunidad de negociarlos, y requisitos que tienen un componente de tiempo, por ejemplo, un cambio en la legislación o las normas fiscales que entran en vigor una fecha específica: existen.

El truco está en identificar estas situaciones y evaluarlas adecuadamente. El código que está programado para ser retirado a menudo se mantendrá durante años. Es posible que se deban cumplir plazos artificiales, pero a menudo se pueden cumplir de diferentes maneras (por ejemplo, el software puede presentarse, demostrarse y "lanzarse" en una fecha determinada sin que la versión de lanzamiento final esté necesariamente terminada hasta más tarde).

Cuando se le presenta este tipo de cosas, debe abordarlo con una mente abierta, pero siempre pregunta si es lo que parece. ¿Son realistas los supuestos involucrados? ¿Hay otra forma de cumplir con el objetivo sin enviar un código deficiente? Si no existe, ¿cómo uso mejor el tiempo que tengo disponible?

Y si no hay alternativa siempre está bien, pero ¿cuándo lo arreglaremos?

Porque debería ser casi, casi, casi siempre cuando , no si .


Re: plazos artificiales; En el mundo ideal, cualquier proyecto decente debe tener una fecha límite. He oído hablar de que los equipos de productos están de acuerdo en pasar una semana (¿una semana no es gran cosa, verdad?), Sin darse cuenta del incentivo comercial, que esto te estaba poniendo después del sábado negro , antes que antes. Mal movimiento.
jasonk

3

Si los gerentes deciden que quieren acumular deuda técnica . Esta es una decisión justa si uno, por ejemplo, solo quiere un prototipo temprano para que algunos clientes iniciales reciban sus comentarios.


44
Ocurre con demasiada frecuencia, donde los gerentes permiten que la deuda técnica se acumule para cumplir con una fecha límite ajustada, solo que en lugar de pagar la deuda lo más rápido posible, ven que se acerca la próxima fecha límite y en lugar de programar a tiempo para el próximo trabajo y la deuda anterior , se ignora la deuda y se llena el tiempo necesario con nuevas características adicionales para el lanzamiento. En otras palabras, la deuda nunca se paga, y antes de que te des cuenta de la profundidad del proyecto, es demasiado tarde para hacer algo para evitar que el problema se salga de control. Está bien acumular deuda, siempre y cuando realmente la pague rápidamente.
S.Robins

2
Algunos gerentes (especialmente no técnicos) no tienen idea de lo que está hablando cuando menciona la deuda técnica. Algunos incluso piensan que estás tratando de engañarlos para que simplemente se vayan y jueguen con cosas en lugar de hacer un trabajo real.
rápidamente_abr

Esa es la razón por la cual nuestra organización no tiene gerentes: Open-Org.com;)
David

1
La mayoría de los gerentes no son lo suficientemente inteligentes como para comprender los inconvenientes de la deuda técnica, por lo que terminas con una deuda técnica que se acumula continuamente hasta que estás técnicamente en bancarrota y te ves obligado a reescribir todo el sistema.
Wayne Molina

1

Puede pensarlo de la misma manera que pedir crédito. ¿Está bien pedir dinero prestado para invertir en X a corto plazo y pagarlo a largo plazo? No hay una respuesta definitiva, puede ser en el mejor interés de la organización (por ejemplo, para cumplir con las expectativas actuales del cliente), o puede ser un desastre si se hace de manera irresponsable.

Todo se reduce a las prioridades, y la administración debe ser consciente de que, aunque la prioridad número uno es hacer que el "código funcione", implementar nuevas funciones y cumplir con las expectativas del cliente, cada vez que abandona las ventanas rotas, la prioridad número uno es más lenta , más difícil y que requiere más inversión de recursos. Además, el 99% de las veces no es posible dejar de desarrollar nuevas funciones y concentrar todos los esfuerzos en "arreglar la base de código".

En conclusión, sí, es aceptable dejar ventanas rotas a veces, al igual que es aceptable pedir un préstamo ... solo recuerde que realmente tiene que pagarlo en el futuro. Y en el futuro, el tiempo para hacerlo probablemente no será mucho mayor que el tiempo que tiene ahora.


0

Normalmente, cuando pueda, debe solucionarlo. Esto evitará el tiempo potencial dedicado al mantenimiento. Sin embargo, algunas prácticas bárbaras no ágiles tienden a dejar el statu quo mientras esté funcionando. Algunos gerentes temen los "efectos imprevistos" del cambio.

Mi decisión es dejarlo solo si funciona como debería (solo se rompe por la optimización pero no por la funcionalidad) y no tiene tiempo para probarlo, si realiza alguna refactorización. Sin embargo, debe tener en cuenta que se debe solucionar más tarde lo antes posible.

Si está roto por la funcionalidad y sus nuevas características dependen de él, sería mejor arreglarlo lo antes posible también.


0

La mayoría de los programadores están en el negocio de ganar dinero para su empleador. Entonces, ¿cuándo debería suceder la refactorización ?: cuándo se gana dinero. La refactorización es el tiempo dedicado no gastado en otros proyectos y el tiempo ahorrado en el futuro en este proyecto.

Si vale la pena, depende principalmente de su gerente.


1
-1; Este tipo de actitud es lo que hace que los sistemas de software se infecten porque la refactorización se ve como "tiempo que podría dedicarse a cosas nuevas".
Wayne Molina

1
Refactorizar ES tiempo no gastado en cosas nuevas.
Pieter B

@Wayne M: Las cosas son que los ingenieros de software generalmente no pueden decidir qué cosas se hacen, lo hacen el negocio y los gerentes. Por supuesto, a todos les gustaría llegar a refactorizar cuando quisieran, pero realmente no es la realidad ... al menos en mis 7 años de experiencia en la profesión.
James

+1 Este tipo de actitud es lo que ofrece valor a quien paga su salario. Sin él, todo su trabajo podría ser subcontratado.
MarkJ

0

Los programadores deben informar a la parte comercial sobre el alcance de la deuda técnica, para que puedan tomar una decisión informada. Si la necesidad de llegar al mercado antes supera el riesgo de su código, no tiene muchas opciones. La falta de flujo de efectivo prevalecerá sobre muchas decisiones técnicas.

Para poner algunos de los problemas en una perspectiva no técnica, señale el tiempo extendido para corregir errores y agregar nuevas características. Si la gerencia tiene experiencia en ventas y mercadeo, pueden entender esto. Odian tener que decirles a los clientes que estas cosas llevarán más tiempo.

Si está pensando en expandir su equipo, este puede ser un buen momento para contratar a un desarrollador junior. La cobertura de prueba será un gran salvador en este caso. Aprenderán más haciendo que leyendo la documentación.


0

¿Puede ser justificable diferir las refactorizaciones importantes al código existente en aras de cumplir el plazo en este escenario?

  • Si algo está roto, lo más probable es que no. No conducirás un automóvil con frenos parcialmente funcionando, ¿verdad? (A menos que el riesgo de no llegar a algún lugar a tiempo sea mayor que el riesgo de estrellarse debido a los frenos defectuosos). Lejos de ser la solución ideal, pero desafortunadamente sucede.

Sin embargo, si está hablando de volver a factorizar el código de trabajo, entonces consideraría lo siguiente:

  • Si dependiera de nuestros desarrolladores sénior o director técnico, nunca lanzaríamos ningún software. Siempre re-factorizamos y luchamos por el perfeccionismo.

  • Si la refactorización tendrá un impacto negativo en la rentabilidad del negocio, entonces debe reprogramarse.

  • Si su empresa ha prometido entregar cierta funcionalidad en una fecha determinada, entonces la refactorizará más adelante. Piense en la organización benéfica del Día de la Nariz Roja: cada año pueden recolectar donaciones por un período de 24 o 48 horas. No hay forma de que vuelvan a factorizar su base de código si pensaran que podría evitar que reciban donaciones en ese lapso de tiempo. Además, si hay una ventana rota, pero no afectará su capacidad de recibir donaciones, es muy probable que elijan no re-factorizar.

  • Siempre encontrarás una mejor manera de hacer algo. Es un proceso natural y es muy importante poder dibujar una línea.


Sería bueno recibir comentarios sobre los votos
negativos

2
De acuerdo, con tantos votos negativos, parece que alguien acaba de tener un mal día, y se apuntó con un montón de votos negativos.
Sam Goldberg

-1

En respuesta a su pregunta sobre la refactorización, diría "sí". Como alguien más señaló en las respuestas anteriores, la refactorización es un proceso continuo, y algunas veces hay decisiones tácticas y comerciales que reemplazan la necesidad de reescribir el código que ya está funcionando (aunque quizás de una manera deslucida).

Con respecto a "ventanas rotas": escuché este término por primera vez en el contexto del desarrollo de software, hace unos 10 años. Pero en ese momento, se usó para describir permitir pruebas unitarias rotas . Esto describía el escenario en el que las personas tienen la tentación de no reparar las pruebas unitarias rotas, porque parece más conveniente recordar qué pruebas están "bien para fallar", en lugar de arreglar las pruebas rotas (que se rompieron válidamente debido a la interfaz o los requisitos cambios, por ejemplo).

Creo que aplicar la metáfora de la ventana rota a las pruebas unitarias rotas es más apropiado y más descriptivo del peligro de permitir "ventanas rotas" en el vecindario del software. En mi opinión, si estaba hablando de pruebas unitarias rotas (como ventanas rotas), entonces la respuesta sería que nunca está bien. (En la medida en que podamos decir nunca ...)


¿Cuál es la razón del voto negativo? Algo dicho aquí no es correcto? ¿O solo editores vengativos?
Sam Goldberg

-1

Si realmente está roto, entonces debe ser reparado.

¿Pero está realmente roto? ¿Estás seguro de que no solo estás equiparando "no bonito" con roto.

Debe aplicar un cálculo de "valor hundido" antes de volver a factorizar el código de trabajo porque no le gusta el estilo o porque cree que causará problemas en el futuro.

Para re-factorizar el código que escribió la semana pasada, el costo hundido es el tiempo que pasó codificando la semana pasada, no vale la pena preocuparse si el código se mejora sustancialmente.

Refactorización de código que ha sido sometido a prueba unitaria. Ahora no solo necesita volver a escribir, debe redefinir y volver a ejecutar todas las pruebas realizadas hasta ahora, esto está empezando a parecer costoso.

Refactorización de código que se ha pasado a producción. Aún más pruebas por hacer, más un despliegue para los usuarios y el riesgo de entregar algo que no funciona tan bien como la versión anterior. Debe justificar esto y aclararlo con el gran jefe antes de seguir adelante.

Vuelva a factorizar el código que ha estado en producción durante un tiempo y ha pasado por varias versiones y correcciones de errores. A menos que sepa que el software dejará de funcionar, ¡ni siquiera vaya allí!


Por lo general, "no bonito" va de la mano con "roto". El código que no está escrito correctamente es más difícil de mantener y agregar nuevas funciones, por lo que eventualmente tendrá que volver a escribir ese código ya que descuidó la refactorización en el camino.
Wayne Molina

2
El código que se prueba y está en producción sin informes de errores pendientes es un código de trabajo. Se invirtió mucho tiempo y dinero para llevarlo a ese estado. Un código bonito es solo eso: un código bonito.
James Anderson

Estoy en desacuerdo. El código puede funcionar, pero puede ser una molestia para mantener y agregar características; un código como este está roto porque es rígido y "maloliente". El código que se escribe correctamente suele ser bonito y probado, y lo que es más importante, es fácil de mantener y mejorar.
Wayne Molina

@Wayne M: Wow, Wayne, realmente no tienes idea. Si alguna vez llega a PM, sus desarrolladores lo amarán, pero su carrera probablemente no será larga. Tienes que dibujar la línea en algún momento. ¿Supongo que eres tú quien ha rechazado a todos los que no están de acuerdo con tus sueños?
James

1
@WayneM: por lo tanto, generaría un "defecto" porque no le gusta la apariencia del código. El código está escrito para hacer un trabajo; si lo hace, está funcionando. Los costos de mantenimiento pueden ser altos, pero debe ser más barato que una reescritura.
James Anderson

-2

Según mi experiencia, la fecha límite es lo más importante para el negocio. Realmente depende de quién va a usar su aplicación. En mi caso, fue para el software del sistema operativo del teléfono móvil ... los plazos incumplidos significaron objetivos de ventas incumplidos y golpes en los precios de las acciones.

Nos encontramos con muchos momentos de WTF cuando miramos el código que heredamos y que claramente necesitábamos cambiar. Sin embargo, debido a que este código funcionó "casi" (la asincronía es poco conocida) no hubo ningún incentivo para que la administración realmente permitiera la refactorización, mientras que había compromisos pendientes por cumplir. No fue hasta que se vio un error 'en la naturaleza' que se nos permitió cambiar cualquier cosa, a pesar de que podríamos romperlo fácilmente a través de casos de borde oscuro. Una vez refacturé aproximadamente 10k líneas de código en mi propio tiempo y terminé teniendo que tirarlo a la basura. El tiempo necesario para las pruebas y otras personas que revisan, etc., no se pueden justificar.


Me alegro de que la realidad del desarrollo de software parezca perderse en algunas personas
James
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.