Cómo determinar los niveles de abstracción


35

Hoy estaba leyendo un libro llamado "Código limpio" y me encontré con un párrafo donde el autor hablaba sobre los niveles de abstracción por función, clasificó algunos códigos como bajo / intermedio / alto nivel de abstracción.

Mi pregunta es ¿cuál es el criterio para determinar el nivel de abstracción?

Cito el párrafo del libro:

Para asegurarnos de que nuestras funciones estén haciendo "una cosa", debemos asegurarnos de que las declaraciones dentro de nuestra función estén todas en el mismo nivel de abstracción. Es fácil ver cómo el Listado 3-1 viola esta regla. Hay conceptos allí que se encuentran en un nivel muy alto de abstracción, como getHtml (); otros que están en un nivel intermedio de abstracción, como: String pagePathName = PathParser.render (pagePath); e incluso otros que tienen un nivel notablemente bajo, como: .append ("\ n").


Respuestas:


27

El autor explica que en la subsección "Código de lectura de arriba a abajo" de la parte que habla de abstracciones (muesca jerárquica mía):

[...] queremos poder leer el programa como si fuera un conjunto de párrafos TO , cada uno de los cuales describe el nivel actual de abstracción y hace referencia a los siguientes párrafos TO en el siguiente nivel inferior.

  • Para incluir las configuraciones y desmontajes, incluimos configuraciones, luego incluimos el contenido de la página de prueba y luego incluimos las desmontajes.
    • Para incluir las configuraciones, incluimos la configuración de la suite si es una suite, luego incluimos la configuración regular.
      • Para incluir la configuración de la suite, buscamos en la jerarquía principal la página "SuiteSetUp" y agregamos una declaración de inclusión con la ruta de esa página.
        • Para buscar al padre ...

El código que acompañaría esto sería algo como esto:

public void CreateTestPage()
{
    IncludeSetups();
    IncludeTestPageContent();
    IncludeTeardowns();
}

public void IncludeSetups()
{
    if(this.IsSuite())
    {
        IncludeSuiteSetup();
    }

    IncludeRegularSetup();
}

public void IncludeSuiteSetup()
{
    var parentPage = FindParentSuitePage();

    // add include statement with the path of the parentPage
}

Y así. Cada vez que profundiza en la jerarquía de funciones, debería cambiar los niveles de abstracción. En el ejemplo anterior, IncludeSetups, IncludeTestPageContenty IncludeTeardownsestán todos en el mismo nivel de abstracción.

En el ejemplo dado en el libro, el autor sugiere que la gran función debería dividirse en otras más pequeñas que sean muy específicas y que solo hagan una cosa. Si se hace correctamente, la función refactorizada sería similar a los ejemplos aquí. (La versión refactorizada se da en el Listado 3-7 del libro).


10

Creo que para entender esta pregunta, necesitas entender qué es una abstracción. (Soy demasiado vago para encontrar una definición formal, así que estoy seguro de que estoy a punto de ser criticado, pero aquí va ...) Una abstracción es cuando tomas un tema o entidad compleja y ocultas la mayoría de sus detalles mientras expone la funcionalidad que aún define la esencia de ese objeto.

Creo que el ejemplo que te dio el libro fue una casa. Si observas la casa muy detalladamente, verás que está hecha de tablas, clavos, ventanas, puertas ... Pero un dibujo de dibujos animados de una casa junto a una fotografía sigue siendo una casa, aunque falta Muchos de esos detalles.

Lo mismo con el software. Siempre que programe, tal como lo recomienda el libro, debe pensar en su software como capas. Un programa dado puede tener fácilmente más de cien capas. En la parte inferior, es posible que tenga instrucciones de ensamblaje que se ejecutan en una CPU; en un nivel superior, estas instrucciones pueden combinarse para formar rutinas de E / S de disco; en un nivel aún mayor, no necesita trabajar con Disco I / O directamente porque puede usar las funciones de Windows para simplemente abrir / leer / escribir / buscar / cerrar un archivo. Estas son todas abstracciones incluso antes de llegar a su propio código de aplicación.

Dentro de su código, las capas de abstracción continúan. Es posible que tenga rutinas de manipulación de cadena / red / datos de nivel inferior. En un nivel superior, puede combinar esas rutinas en subsistemas que definen la administración de usuarios, la capa de interfaz de usuario y el acceso a la base de datos. Sin embargo, otra capa de estos subsistemas podría combinarse en componentes de servidor que se unen para formar parte de un sistema empresarial más grande.

La clave para cada una de estas capas de abstracción es que cada una oculta los detalles expuestos por las capas anteriores y presenta una interfaz muy limpia para ser consumida por la siguiente capa. Para abrir un archivo, no debería tener que saber cómo escribir sectores individuales o qué interrupciones de hardware procesar. Pero si comienza a viajar por la cadena de capas de abstracción, definitivamente podrá rastrear desde la llamada de función Write (), hasta la instrucción exacta que se envía al controlador del disco duro.

Lo que el autor le dice que haga es que cuando defina una clase o una función, piense en qué capa es usted. Si tiene una clase que administra subsistemas y objetos de usuario, la misma clase no debe realizar una manipulación de cadenas de bajo nivel o contener un montón de variables solo para realizar llamadas de socket. Esa sería la violación de cruzar capas de abstracción y también de hacer que una clase / función haga solo una cosa (SRP - Principio de responsabilidad única).


2

Mi pregunta es ¿cuál es el criterio para determinar el nivel de abstracción?

Se supone que el nivel de abstracción es obvio. Es abstracto si es parte del dominio del problema, no parte del lenguaje de programación. Es difícil ser más claro que "altamente abstracto" == "no real" == "dominio problemático". Y "no abstracto == concreto == parte del lenguaje". Se supone que es trivial decidir el nivel de abstracción. No se supone que haya ninguna sutileza en absoluto.

.append("\n")No es abstracto. Simplemente pone un personaje en una cadena. Eso sería concreto. No abstracto

String pagePathName = PathParser.render(pagePath);trata con cadenas. Cosas concretas En parte sobre características concretas del lenguaje de programación. Trabajando en parte con conceptos abstractos de "ruta" y "analizador sintáctico".

getHtml(); Abstracto. Trata con "Marcado" y cosas que no son triviales, concretas, características del lenguaje.

Resumen == no es una característica del idioma.

Concreto == una característica del lenguaje.


1
Si define el resumen como una cualidad que describe las cosas que crea un programador, es decir, abstracciones generadas por el programador, entonces estoy dispuesto a aceptar sus definiciones de palabras. Pero todos los lenguajes de programación son abstracciones sobre algo más concreto. La elección del lenguaje de programación determina, en gran medida, en qué nivel de abstracción comienza.
Robert Harvey

1

Creo que el nivel de abstracción es simple ... si la línea de código no implementa directamente la responsabilidad única del método, es otro nivel de abstracción. Por ejemplo, si el nombre de mi método es SaveChangedCustomers () y toma una lista de TODOS los clientes como parámetro, la única responsabilidad es salvar a los clientes de la lista que hayan cambiado:

foreach(var customer in allCustomers)
{
    if (CustomerIsChanged(customer)
        customer.Save();
}

A menudo, en lugar de llamar al método CustomerIsChanged (), encontrará la lógica para determinar si el cliente ha cambiado incrustado en el bucle foreach. ¡Determinar si el registro del cliente ha cambiado NO es responsabilidad de este método! Es un nivel diferente de abstracción. Pero, ¿qué pasa si la lógica para hacer esa determinación es solo una línea de código? ¡¡¡No importa!!! Es un nivel diferente de abstracción y debe estar fuera de este método.

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.