Publicado el 29 de Julio del 2020
1.343 visualizaciones desde el 29 de Julio del 2020
1,2 MB
19 paginas
Creado hace 4a (28/07/2020)
Extensibilidad y flexibilidad.
28 de julio de 2020
En muchas organizaciones establecidas, su trabajo diario como desarrolla-
dor implica no solo escribir nuevas aplicaciones, sino también actualizar
las existentes. Cuando tiene la tarea de agregar una nueva característica
a una aplicación existente, su objetivo es extender la funcionalidad de esa
aplicación, introduciendo un nuevo comportamiento al agregar código.
Algunas aplicaciones son flexibles para este tipo de cambio y pueden adap-
tarse a los requisitos cambiantes. Otros pueden luchar contra usted con
uñas y dientes. En este texto, aprenderá estrategias para escribir software
que sea flexible y extensible.
1. ¿Qué es el código extensible?
Se dice que el código es extensible si agregarle nuevos comportamientos
tiene poco o ningún impacto en los comportamientos existentes. Dicho de
otra manera, el software es extensible si puede agregar un nuevo compor-
tamiento sin cambiar el código existente.
Piense en un navegador web como Google Chrome o Mozilla Firefox. Proba-
blemente haya instalado algo en uno de estos navegadores para bloquear
anuncios o para guardar fácilmente el artículo que está leyendo en una
herramienta de notas como Evernote.
1
Firefox llama a estos complementos de software instalables, mientras que
Chrome los llama extensiones, y ambos son ejemplos de un sistema de
complementos. Los sistemas de complementos son implementaciones de
extensibilidad. Chrome y Firefox no se crearon teniendo en cuenta los blo-
queadores de anuncios o Evernote específicamente, pero fueron diseñados
para permitir la creación de tales extensiones.
Los proyectos masivos como los navegadores web tienen éxito cuando pue-
den satisfacer las necesidades de cientos de miles de usuarios. Sería una
hazaña enorme predecir de antemano todas esas necesidades, por lo que
un sistema extensible permite la creación de soluciones a esas necesida-
des después de que el producto sea lanzado al mercado. No siempre tendrá
que ser tan progresista, pero recurrir a algunos de los mismos conceptos lo
ayudará a construir un mejor software.
Al igual que con muchas facetas del desarrollo de software, la extensibili-
dad es un espectro y algo en lo que iterará. Al practicar conceptos como la
separación de tareas y el acoplamiento débil, puede mejorar la extensibili-
dad de su código con el tiempo. A medida que mejora la extensibilidad de
su código, encontrará que agregar nuevas funciones se vuelve más rápido
porque puede enfocarse casi por completo en ese nuevo comportamiento
sin preocuparse por cómo afectará a las funciones que lo rodean. Esto tam-
bién significa que será más fácil mantener y probar su código, ya que las
características están más aisladas y, por lo tanto, es menos probable que
introduzcan errores difíciles debido al comportamiento entremezclado.
1.1. Agregar nuevos comportamientos
En un sistema extensible ideal, agregar un nuevo comportamiento impli-
ca agregar nuevas clases, métodos, funciones o datos que encapsulan el
nuevo comportamiento sin cambiar el código existente (figura 1).
Compare esto con un sistema menos extensible, donde la nueva funcio-
nalidad puede requerir agregar declaraciones condicionales a una función
aquí, un método allí, etc. (figura 2). Esa amplitud de cambios y su gra-
nularidad a veces se conoce como cirugía de escopeta, porque agregar
2
Figura 1: Agregar un nuevo comportamiento al código extensible
una característica requiere cambios importantes en todo el código1. Esto
a menudo apunta a una mezcla de preocupaciones o una oportunidad pa-
ra abstraer o encapsular de una manera diferente. El código que requiere
este tipo de cambios no es extensible; crear un nuevo comportamiento no
es un esfuerzo directo. Debe buscar en el código exactamente las líneas
correctas para actualizar.
1Lea más sobre la cirugía de escopeta y otros olores de código en "Una inves-
tigación de malos olores en el diseño orientado a objetos", Tercera Conferen-
cia Internacional sobre Tecnología de la Información: Nuevas Generaciones (2006),
https://ieeexplore.ieee.org/document/1611587.
3
Figura 2: Agregar un nuevo comportamiento al código que no es extensible
Consejo
Duplicar un código y actualizar esa nueva copia para hacer lo que
necesita es un enfoque de extensión perfectamente válido. Utilizo
este enfoque ocasionalmente en mi camino para hacer que el códi-
go original sea más extensible. Al crear una versión duplicada, alte-
rarla y ver cómo difieren las dos versiones, puedo refactorizar más
fácilmente ese código duplicado en una sola versión multipropósito
más adelante. Si intenta deduplicar el código sin un conocimiento
profundo de todas las formas en que se está utilizando, corre el ries-
go de asumir demasiado y hacer que su código sea inflexible a los
cambios futuros. Así que recuerda, la duplicación es mejor que la
abstracción incorrecta.
Debido a que los sistemas reales rara vez son ideales, necesitará realizar
cambios en el código existente regularmente (figura 3). ¿Cómo se aplica la
flexibilidad en estas situaciones?
4
Figura 3: Cómo se ve la extensibilidad en la práctica
1.2. Modificar comportamientos existentes
Hay una serie de razones por las que es posible que deba cambiar el código
que usted u otra persona ya haya escrito. Es posible que deba cambiar el
comportamiento del código, como cuando está reparando un error o abor-
dando un cambio en los requisitos. Es posible que deba refactorizar para
que el código sea más fácil de trabajar, manteniendo el comportamiento
consistente. En estos casos, no necesariamente busca extender el código
con un nuevo comportamiento, pero la flexibilidad del código todavía juega
un papel importante.
La flexibilidad es una medida de la resistencia del código al cambio. La fle-
xibilidad ideal significa que cualquier parte de su código puede cambiarse
fácilmente por otra implementación. El código que requiere cirugía de es-
copeta para cambiar es rígido; luchar contra los cambios hace que trabajes
más duro. Kent Beck dijo ingeniosamente: "for each desired change, make
5
the change easy (warning: this may be hard), then make the easy chan-
ge"2. Desglosando primero la resistencia del código, a través de prácticas
como descomposición, encapsulación, etc. allanan el camino para permitir-
le realizar el cambio específico que originalmente pretendía.
En mi propio trabajo, realizo pequeñas refactorizaciones continuas en el
área de código en la que estoy trabajando. Por ejemplo, el código en el que
trabaja puede contener un conjunto complicado de declaraciones if/else,
como en el listado 1. Si necesita cambiar un comportamiento en este con-
junto de condicionales, es probable que necesite leer la mayor parte para
comprender dónde se debe realizar el cambio. Y si el cambio que desea
hacer se aplica al cuerpo de cada condicional, deberá aplicar el cambio
muchas veces.
Listado de código 1: Un mapeo rígido de condiciones a resultados
# Ref_1
if choice == ’A’:
# Ref_2
print(’A is for apples’)
elif choice == ’B’:
print(’B is for bats’)
...
Ref_1 Este condicional debe actualizarse correctamente para cada opción.
Ref_2 Las tareas de asignar una opción a un mensaje e imprimir el men-
saje se mezclan.
¿Cómo podría mejorarse esto?
1. Extraiga información de los controles y cuerpos condicionales en un
dict.
2Kent
Beck
en
Twitter
(25
de
septiembre
de
2012),
https://twitter.com/kentbeck/status/250733358307500032.
6
2. Use un bucle for para verificar cada opción disponible.
Debido a que cada elección se asigna a un resultado específico, extraer
el mapeo de comportamientos en un diccionario (opción 1) sería el enfo-
que correcto. Al asignar la letra de la elección a la palabra que aparece
en el mensaje, una nueva versión del código puede recuperar la palabra
correcta de la asignación independientemente de la opción elegida. Ya no
necesita seguir agregando declaraciones elif a un condicional y definir el
comportamiento para el nuevo caso. En su lugar, puede agregar una nueva
asignación de la letra elegida a la palabra que usará en el mensaje, impri-
miendo solo al final, como en el listado 2. La asignación de opciones a los
mensajes actúa como la configuración: información que un programa usa
para determinar cómo ejecutarse. La configuración es a menudo más fácil
de entender que la lógica condicional.
Listado de código 2: Una forma más flexible de asignar condiciones a
resultados
# Ref_1
choices = {
’A’: ’apples’,
’B’: ’bats’,
...
}
# Ref_2
print(f’{choice} is for {choices[choice]}’)
Ref_1 La extracción de la asignación de opciones a mensajes hace que
agregar una nueva opción sea más simple.
Ref_2 El resultado está centralizado y el comportamiento de impresión
está algo separado.
Esta versión del código es más legible. Mientras que el ejemplo en el listado
1 requiere que comprenda las condiciones y lo que hace cada condición, la
7
versión aquí está más claramente estructurada como un conjunto de op-
ciones y una línea que imprime información sobre una opción específica.
Agregar más opciones y cambiar el mensaje que se imprime también es
más fácil, porque se han separado. Todo esto está en la búsqueda de aco-
plamiento débil.
1.3. Bajo acoplamiento
Sobre todo, la extensibilidad surge de los sistemas débilmente acoplados.
Sin acoplamiento débil, la mayoría de los cambios en un sistema requerirán
una variedad de desarrollo de cirugía de escopeta. Esta versión es difícil
de leer, en parte debido a su diseño físico (tenga en cuenta la anidación
profunda) y también porque están sucediendo muchas cosas en una sola
porción de código3.
Listado de código 3: Un enfoque procesal
if __name__ == ’__main__’:
options = [...]
while True:
for option in options:
Ref_1
print(option)
choice = input(’Choose an option: ’)
# Ref_2
if choice == ’A’:
...
# Ref_3
sqlite3.connect(...).execute(...)
elif choice == ’D’:
...
3El exceso de anidación suele ser un mal síntoma. Cuando eso pase, intente una nueva
abstracción,
Comentarios de: Python - Extensibilidad y flexibilidad (0)
No hay comentarios