jueves, 22 de agosto de 2024

"Programación Copy-Paste", ¿qué tan mala es?



"Programación Copy-Paste" es el nombre informal que en algún lugar se le da a copiar y pegar código encontrado en foros o en sitios de preguntas y repuestas(sobre todo Stackoverflow), y más recientemente, de bots de chat.
Me he encontrado unas cuantas veces con comentarios respecto a este estilo de programación, y todos los que he encontrado fallan en mencionar gran parte de los problemas que esto puede acarrear.
¿Cuales son estos problemas?, pues empezando por los más conocidos:
  • Copiar y pegar sin entender lo que se está haciendo puede ser una oportunidad desaprovechada para aprender algo y mejorar como desarrollador.
  • Es fácil pasar por alto varios detalles si simplemente se copia y pega, la mente es una experta en engañarnos haciéndonos creer que leyó algo cuando no fue así. El tener que teclearlos forza a asegurarse de que se está leyendo con detenimiento todo (un tip que me dieron en un grupo de escritores es que para revisar un escrito es buena idea leerlo en voz alta, así evitas saltarte cosas accidentalmente).
  • Si en tu programa hay código que no entiendes, en el momento que tengas que hacerle cambios no vas a saber qué hacer.
... si bien todo esto es cierto, desafortunadamente también he escuchado la opinión de que puede ser conveniente recurrir al famoso Ctrl+C, Ctrl+V (ó Ctrl + Insert, Shift + Insert para los nostálgicos) si la prioridad no es aprender sino entregar el proyecto rápido.
El problema con esta forma de ver las cosas es que ignora por completo la calidad del trabajo o incluso la posibilidad de implicaciones legales.
¿Cuales son estois otros problemas de copiar y pegar código de internet?, pues estos puntos son los que me gustaría que se mencionaran más:
  • El código escrito dentro de respuestas a preguntas(como en Stackoverflow o incluso el que es escrito por bots de chats) tiene el propósito de ser un código fácil de entender y auto-contenido.
    No tiene como prioridad ser eficiente, ni versatil, ni mucho menos acoplarse al proyecto que estés desarrollando (es decir, seguir su estilo de código, usar las funciones que ya se hayan escrito, y separarse en varias funciones/clases si es pertinente).
    Sería como estar escribiendo una novela, preguntar en un chat de Whatsapp por inspiración, y copiar y pegar directamente los mensajes en lugar de entender lo que dicen y escribir ésas ideas siguiendo el tono y narrativa presentes en la novela.
    No hay que olvidar que nuestro código está escrito para ser leido tanto por programas(compiladores/interpretes) como por humanos.
  • Mucho código de internet está licenciado, si se toma de un proyecto de software libre es posible que tenga en su licencia condiciones que exijan que sólo se use únicamente en proyectos de software libre.
    Si se toma de una publicación de Stackoverflow, existe el riesgo de que hayan copiado el código de otro lado y se trate de código licenciado.
    Incluso en teoría el que escribe algo es automáticamente dueño del copyright de lo que escriba, y salvo que ceda los derechos explícitamente a la comunidad, es posible meterse en problemas legales si se utiliza su código sin su permiso.
    Hay ocasiones en las cuales el autor da su permiso, sin embargo, si no lo hace en términos legales claros, es posible meterse en problemas debido a posibles ambigüedades del lenguaje.
    El pequeño esfuerzo de escribir el código por uno mismo es bastante menor que lo que supondría consultar con un abogado la posibilidad de copiar y pegar.
Por último, cabe abordar el caso de copiar y pegar código dentro del propio proyecto (en lugar de tomarlo desde internet). En este caso me parece súmamente útil para las pruebas unitarias, pero fuera de las pruebas unitarias hay que tener algo de cuidado, ya que hay que seguir el principio DRY(don't repeat yourself).
Yo no soy nadie para decirles que es malo copiar y pegar tu propio código para producción, e incluso yo mismo lo hago a veces. Cada quien tiene su manera de escribir código y de organizarse y es algo enteramente personal.
Mi intención con decir que hay que tener cuidado y seguir el principio DRY no se trata de decirles que no escriban código repetido sino que libren a sus compañeros (o a sus yos del futuro) de tener que leer código repetido.
No importa si su procedimiento para escribir código implica repetición, lo que importa es el código que llega al repositorio al final del día, y ése código debe de evitar la repetición (salvo para tapar un mal mayor).

"Los buenos programadores copian"
"... los grandes pegan"

miércoles, 14 de agosto de 2024

7 Usos de los Algoritmos en la Vida Real

 Me he encontrado varias veces con esta pregunta "¿Los algoritmos sirven en la vida real?", principalmente por 2 fuentes diametralmente opuestas:

  1. Gente de programación competitiva que se pregunta si todo éso le va a servir en su vida profesional, al sentirse un tanto intimidados por la cantidad de cosas que desconocen.
  2. Gente enojada porque dicen que hay demasiados algoritmos en las entrevistas técnicas de programación.
Respuesta corta: Sí sirven.
Respuesta larga:

Aunque sí sirvan, dista mucho de ser como en la programación competitiva:
  • Hay algunas cosas de la algoritmia que sirven más que otras; las cosas más útiles en la programación competitiva no siempre son tan útiles de conocer profesionalmente (en particular cosas relacionadas al multi-threading, y optimizaciones en la compilación resultan altamente efectivas a pesar de que en programación competitiva son casi ignoradas)
  • La gran mayoría de las optimizaciones aplicables a la vida real utilizan ideas mucho más sencillas que cualquier problema de IOI
  • Con la mayoría de los algoritmos más avanzados que pudieran ser útiles, resulta que es mejor usar la implementación de alguien más en lugar de reimplementarlos.
...y sobre los problemas de entrevista, yo pienso que su grado de complejidad es el correcto: aunque nunca programemos listas enlazadas o árboles binarios directamente, recorrer todos los campos de un objeto json o de una estructura de directorios son tareas comunes, y creo más razonable esperar que el candidato se pueda ajustar a usar una estructura super genérica en lugar de usar un framework en específico, que seguramente sería más complicado (además de que no es necesario llegar a la solución optima del problema, lo que se evalúa es mayoritariamente otras cosas).

Ahora, seguramente con esta información se están preguntando, si sí son útiles los algoritmos pero no de la forma de programación competitiva, entonces, ¿de qué manera son útiles?. Pues aquí les traigo unos cuantos ejemplos (los intentaré ordenar por qué tan frecuente/útil aparece el ejemplo, no por qué tan emocionante sea).

1. Análisis de Complejidad

Si bien esto no es saberse un algoritmo en particular, el análisis de complejidad es fundamental y hay que estarlo usando todo el tiempo.
No es raro que quienes no estén muy familiarizados con él, inadvertidamente produzcan cuellos de botella. A veces con cosas tan simples como utilizar un array.find dentro de un bucle y a veces con cosas menos obvias, como realizar demasiadas consultas a una base de datos, o saltarse la parte de la documentación de una biblioteca donde menciona el rendimiento.
En general siempre que se está planenado un proyecto hay que preguntarse cuáles van a ser los requerimientos y elegir el algoritmo que se ajuste mejor a dichos requerimientos.
Generalmente será un algoritmo que ya fue implementado por alguien más, pero poder elegir desde un momento temprano qué framework o bibliotecas usar puede ser determinante para saber si el proyecto será un éxito o no y éso requiere análisis de complejidad.

2. Memorización

El truco de memorizar las llamadas computacionalmente pesadas para no tener que recalcularlas es súmamente útil, y al combinarse con el análisis de complejidad es posible saber donde aplicarlo para obtener resultados palpables.
La gran diferencia es que la memorización suele utilizarse menos para evitar repetir cálculos grandes y más para evitar repetir llamadas a red o lecturas de archivos.

3. Recursividad

La recursividad es especialmente útil cuando se requiere recorrer árboles, y en programación hay árboles en todos lados: un objeto Json es un árbol, el sistema de archivos es otro árbol, los mismos documentos HTML y los CSS son árboles y también en los videojuegos hay muchos árboles involucrados (desde las estructuras de componentes, hasta la estructura jerárquica para simular cinemática directa o calcular cinemática inversa).

4. Programación Asíncrona

Es común que varios de los procesos con los que se trabaja sean asíncronos (es decir, no se realizan de manera inmediata sino que requieren de esperar y durante ése tiempo el programa puede continuar ejecutándose).
Prácticamente todos los lenguajes de programación modernos tienen cierto soporte para asincronía.
La manera en la que se cordinan dichas tareas puede tener un gran impacto en el rendimiento final del programa.
Para poder realizar todas estas tareas efectivamente hay que poder analizar los algoritmos y saber en qué momentos es conveniente esperar a una respuesta, y cómo ir procesando los resultados a medida que llegan.

5. Multi-threading

Esto también es parte de la programación asíncrona pero va un paso mas allá, en este caso varios hilos corren a la vez, cada uno ejecutando su propio pedazo de código y es necesario ser capaz de idear maneras de que los hilos trabajen juntos y no produzcan bugs en el momento que interactúan con esturcturas de datos que comparten.
Esto requiere un diseño minucioso de estructuras de datos para ver cómo evitar lo más posible bloquear hilos sin sacrificar mucho rendimiento.
También está el detalle de que todo lo que es sólo lectura es seguro para multi-threading, pero actualizar una estructura que es sólo lectura sin necesidad de copiar la estructura completa requiere técnicas que se utilizan bastante en la persistencia.

6. Geometría Computacional

Tanto en mi trabajo desarrollando videojuegos como en mi trabajo en un buscador de hoteles necesité usar geometría computacional extensivamente.

7. Máscaras de Bits

A veces resultan útiles para ahorrar memoria o para hacer algunas operaciones con las que normalmente se usarían arreglos booleanos pero de una forma más simple y además más eficiente.  También varias APIs las usan extensivamente para evitar pasar demasiados parámetros booleanos.

De StackOverflow a ChatGPT: El Arte de Pegar sin Pensar

 Es curioso cómo apenas en Agosto del año pasado critiqué duramente la práctica de copiar código de páginas de internet para pegarlo dentro ...