arrow_back Volver
Inicio keyboard_arrow_right Artículos keyboard_arrow_right Artículo

¿Por qué no es buena idea implementar nuestros propios algoritmos?

Eduardo Ismael Garcia

Full Stack Developer at Código Facilito.

av_timer 4 Min. de lectura

remove_red_eye 7104 visitas

calendar_today 05 Septiembre 2023

Si estás comenzando el desarrollo de software y quieres mejorar el rendimiento de tus aplicaciones un consejo que puedo darte es: NO implementes tus propios algoritmos.

Sí, sé que puede sonar un consejo algo contradictorio y quizás controversial, principalmente cuando uno termina algún tutorial, libro o curso y lo primero que deseamos hacer es simplemente implementar nuestros conocimientos y sumar valor al proyecto en el que estemos trabajando.

Sin embargo, en este vídeo, te demostraré mediante un par de ejemplos, el por que no es una muy buena idea, en la mayoría de los casos, implementar nuestros propios algoritmos.

Será un post sumamente interesante y lleno de código, así que te invito a que te quedes. 🐊

Bien, sin más introducción comencemos con el vídeo.

Introducción

Bien, para ejemplificar el porque no es una muy buena idea implementar nuestros propios algoritmos partamos de 3 sencillos ejemplos. Ejemplos que definitivamente vemos a lo largo de nuestra carrera.

Veamos.

Ejemplo número 1

Cuando comenzamos en la carrera de desarrollo de software uno de los primeros algoritmos a implementar es sin duda alguna el del factorial.
Cuando implementamos el factorial, por ejemplo en Python, nuestro código puede quedar de la siguiente manera.

def factorial(n):
    resultado = 1
    for i in range(1, n + 1):
        resultado *= i

    return resultado

>>> factorial(5)
120

En este caso un código bastante sencillo, pasamos de usar recursividad. El código funciona bastante bien. Si debemos conocer el factorial de algún número pudiésemos llegar a decir que hemos solventado la problemática 🦀

Sin embargo déjame decirte que Python, de forma nativa, ya nos permite conocer el factorial de un número mediante el
módulo math.
Veamos un ejemplo.

import math

result = math.factorial(5)
print(result)

Un código mucho más legible y limpio. 🍃

Ahora, ¿Cual es las 2 implementaciones es mejor? ¿Cual deberíamos usar en nuestro día a día?

Si comparamos el performance y medimos el tiempo de ejecución de nuestra implementación en comparación con la que Python ya nos ofrece tendemos un claro ganador. 🤓

import math
from timeit import timeit

def custome_factorial(n):
    resultado = 1
    for i in range(1, n + 1):
        resultado *= i

    return resultado

result = timeit(lambda: custome_factorial(100_000), number=1)
print("Custome factorial", result)

result = timeit(lambda: math.factorial(100_000), number=1)
print("Pyhon factorial:", result)

Snap list.png

Para este ejemplo, donde hemos obtenido el factorial del número 100_000 (cien mil) a mi implementación le toma 3.5 segundos finalizar, y a la implementación de python poco más de 0.11 segundos. 😱

Es decir, la implementación de python es prácticamente 30 veces más eficiente que la nuestra.
En este sentido no vale la pena implementar algo que ya el lenguaje nos ofrece de forma nativa.

Un segundo ejemplo puede ser el uso de alguna estructura de datos, por ejemplo una pila.

En libros, artículos, cursos, etc… es algo muy común ejemplificar el funcionamiento de este tipo de estructuras mediante clases. 🤩

Por ejemplo aquí un stack en Python.

class Stack:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return len(self.items) == 0

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.isEmpty():
            return self.items.pop()
        else:
            raise IndexError("La pila está vacía")

    def peek(self):
        if not self.isEmpty():
            return self.items[-1]
        else:
            raise IndexError("La pila está vacía")

    def size(self):
        return len(self.items)

Definimos los métodos push, pop y peek comunes en las pilas, así mismo manejamos los elementos mediante una lista de Python. Hasta aquí, probablemente todo bien.

Esto de igual forma funciona, mediante esta clase podemos representar y hacer uso de una cola. Añadir y quitar elementos del top.

Sin embargo, si comparamos nuestra implementación con la clase deque, la cual ya se nos ofrece de forma nativa en Python, veremos que el performance para trabajar con cientos, miles o millones de registros sin duda alguna es mucho mejor que la nuestra. 😧

Aquí otro ejemplo de tiempos.

from collections import deque

def stack_test():
    stack = Stack()

    for x in range(0, 10_000_000):
        stack.push(1)

    for x in range(0, 10_000_000):
        stack.pop()

def deque_test():
    stack = deque()

    for x in range(0, 10_000_000):
        stack.append(1)

    for x in range(0, 10_000_000):
        stack.pop()

result = timeit(stack_test, number=1)
print("Stack class", result)

result = timeit(deque_test, number=1)
print("Deque class:", result)


Snap list.png

Para este segundo ejemplo, donde añadimos un diez millones de registros y quitamos esos diez millones del stack, vemos que a deque le toma 0.724 segundos completar todas estas operaciones, por su parte, a mi clase 3.19 segundos. Nuevamente, la implementación de python es superior a la que uno pudiera presentar en primera instancia. 🤩

Palabras finales.

Estos son tan solo 2 ejemplos, pero la lista puede ser mucho más extensa, desde algoritmos de búsqueda, ordenamientos, estructuras de datos, algoritmos de encriptación, protocolos de comunicación etc.

Las implementación que podemos encontrar en los lenguajes de programación, librerías o frameworks a menudo serán mucho más eficientes que nuestras propias implementaciones.

Y no es de extrañarnos, en la gran mayoría de los casos estas implementaciones ya fueron testadas por cientos de miles de programadores alrededor del mundo, además, en algunos casos, estas implementaciones fueron escritas por equipos 100% enfocados solo en esas funcionalidades, así como equipos multidisciplinarios, pasando por programadores, físicos, matemáticos, personas de ciencias de datos entre otros.

Pero oye, no te sientas mal, esto no quiere decir que no debamos conocer el cómo funcionan ciertos algoritmos, protocolos o estructuras de datos, eso esta super bien, y de hecho lo recomiendo ampliamente, lo que digo es que, para proyectos en los cuales el performance o la seguridad sean temas críticos, lo mejor sería dejar a un lado nuestras implementaciones y utilizar herramientas que ya nos ofrezca el lenguaje, librería o framework. Herramientas que fueron diseñadas por expertos y expertas en la industria y que fueron probadas cientos de miles de veces.

Esto tampoco quiere decir que nunca implementaremos nuestros propios algoritmos, o que nunca escribiremos nada nuevo, solo hay que tomar en cuenta que para las tareas más comunes en el desarrollo de software es probable que existan alternativas mejores a las nuestras.

Tampoco se trata de reinventar la rueda, si algo ya existe y fue testeado, creo que vale la pena darle una oportunidad. Recordemos, el performance y la legibilidad cuentan. 🍻