2009-08-27 18 views
7

Así que existe la regla "Hacer una cosa" en el libro "Código limpio". Pero, ¿hasta dónde debemos realmente tomar esto?Hacer una cosa: ¿qué tan lejos tomar esta regla?

Por ejemplo las siguientes afirmaciones:

Settings.Default.BaudRate = baudRate; 
Settings.Default.COMPort = port; 
Settings.Default.DataBits = dataBits; 
Settings.Default.Handshake = handshake; 
Settings.Default.Parity = parity; 
Settings.Default.ReadTimeout = readTimeout; 
Settings.Default.WriteTimeout = writeTimeout; 
Settings.Default.CommunicationTimeout = communicationTimeout; 
Settings.Default.Save(); 

bien, seguro que hay más de una sentencia aquí, pero se siente que me gusta que sólo están haciendo una cosa. Guardando la configuración.

Lo tengo en una sola función. ¿Realmente tomarías esta appart y tendrías un único método para cada configuración?

¿Cuándo te apegas a esta regla y cuándo no?

+1

Si esos son propiedades, entonces usted tiene esencialmente un método diferente para cada uno de ellos, ¿verdad? No soy un tipo C#, pero esos parecen accesorios. –

+0

Gracias a todos por sus respuestas :-) – TimothyP

Respuesta

18

Parece perfectamente válida para mí. El nombre del método obvio para ese código es SaveSettings, lo que indica que el método hace exactamente una cosa. Nada de que preocuparse.

+0

o saveSettings depende del estilo de codificación. Esta respuesta es perfecta sin embargo. – wlashell

+0

Sí, hace *** una cosa ***: guarde la configuración. No se preocupe ... – awe

6

Los mantendría todos en una sola función SaveSettings() - si los pone cada uno en su propia función, igual tendría que llamar a todas esas funciones desde otra función.

4

Supongo que esta regla hace referencia a cuándo dividir una función en varias funciones secundarias.

Tiene la idea correcta: guardar la configuración es "una cosa" y podría estar en su propia función. Poner cada configuración en su propia función sería excesivo.

Otra directriz que he escuchado que podría ayudarlo a comprender el concepto de "una cosa": si la función es más larga que una o dos páginas, probablemente se pueda escribir mejor dividiendo su contenido en varias funciones secundarias.

18

La siguiente sección del libro, Un nivel de abstracción por función, va un largo camino hacia la respuesta a esta pregunta. Todas estas declaraciones están en el mismo nivel de abstracción, por lo que esta función ya está haciendo una cosa, guardando la configuración.

+0

Todavía necesito llegar a esa parte: p – TimothyP

6

Sí, cada método debe hacer solo una cosa. Pero, ¿qué es esa única cosa?

Esto depende del nivel de abstracción en el que está el método. Un método (propiedad) para guardar una configuración única es una abstracción bastante baja. La siguiente abstracción más alta sería el método SaveSettings propuesto.

derecho en la parte superior que tiene un solo método/función main que también lo hace sólo una cosa: Todo el programa ...

2

En nuestro equipo tratamos de seguir el propósito para cada directriz función. Para ayudar a los desarrolladores agregamos una sugerencia a nuestros estándares que consideran la refactorización si una función excede las 25 líneas. Entonces, si tuviera 100 líneas de propiedades de configuración de código, podría considerar dividirlas por categorías como SaveUserSettings, SaveNetworkSettings, etc.

El objetivo final es hacer que el código sea más legible. Si tomó su método y lo dividió en 20 llamadas cada una configurando una propiedad, creo que sería más lento de seguir y apoyar.

4

Mirando su código de forma aislada, es difícil de decir.Podría argumentar que su función hace dos cosas: actualizar la configuración y luego guardar los cambios. Además, ¿cómo llenas los valores, se pasan como argumentos a tu función (preferible) o tu función obtiene los valores en sí misma (haciendo otra cosa)?

Me gustaría seguir el Single Responsibility Principle que se resumen en:

Nunca debe haber más de una razón para una clase para cambiar

e igualmente se puede aplicar a los métodos. En su ejemplo, ¿habrá algún motivo para actualizar la configuración, pero no para guardarla?

+0

No realmente. Nunca los actualizaría a menos que tenga que guardarlos – TimothyP

1

El código de ejemplo mejoraría con la pregunta, cuándo usar propiedades y cuándo usar parámetros en un constructor o método para establecer el estado del objeto. Sé que hay una sección sobre esto en el .NET framework guidelines, donde se analiza el patrón básico del componente (muchas propiedades y el estado interno de los componentes puede no ser válido entre la primera y la última asignación) frente al otro patrón (muchos parámetros de constructor y parámetros del método) y el estado interno de los objetos es válida después de cada línea de código se ejecuta.

+0

Voy a investigar eso – TimothyP

4

no he leído ese libro en particular, pero en cuanto al concepto ...

"una cosa" no significa "una línea de código "." Una cosa "significa que todo en la función debe estar lógicamente relacionado.

Me refiero a algunos de los carteles anteriores al decir que" saveSetti " ngs "es" una cosa ". Tal vez es solo un descuido con la redacción, pero aprovecharé la oportunidad para señalar la trampa potencial. En su caso, es más como "saveCommunicationSettings", que creo que se ajusta fácilmente a la definición de "una cosa". Si agregó "Settings.Default.customerLoyaltyDiscount = ..." a esa lista, diría que probablemente se encuentre en terreno peligroso, porque ahora está mezclando las configuraciones de comunicación con las configuraciones de cálculo de precios.

En la vida real, decidir qué cohesión es razonable no es una fórmula sino una decisión que requiere el ejercicio de la inteligencia. ¿Debe una función que calcula el monto total de un pedido incluir el cálculo del impuesto a las ventas? Podría decirse que son dos cosas: el precio total de todos los artículos en el pedido Y calcular los impuestos a las ventas. Pero también podría argumentar que es solo uno: encuentre el precio total del pedido, sea lo que sea que eso involucre. En la práctica, a menudo tomo la decisión en función de la complejidad de la lógica. Si todo lo que se requiere para calcular el total de un pedido es un simple recorrido por todos los artículos que suman sus precios y luego tomar una tasa de impuestos de ventas de una tabla y multiplicar, probablemente lo haría todo en una función. Si hay algo más que eso, como el sistema en el que estoy trabajando estos días, el cálculo de precios implica pedidos de stock versus personalizados, buscar todo tipo de posibles descuentos, agregar garantías, etc., etc., realmente tenemos que romperlo. arriba.

0

Si quisiera dividir su método, consideraría interrumpir la asignación de valores del almacenamiento real del objeto. Se podría decir que el mapeo de valores es un nivel separado de abstracción. Entonces usted tendría:

public void save(){ 
    mapSettings(); 
    Settings.Default.Save(); 
} 

private void mapSettings(){ 
    Settings.Default.BaudRate = baudRate; 
    Settings.Default.COMPort = port; 
    Settings.Default.DataBits = dataBits; 
    Settings.Default.Handshake = handshake; 
    Settings.Default.Parity = parity; 
    Settings.Default.ReadTimeout = readTimeout; 
    Settings.Default.WriteTimeout = writeTimeout; 
    Settings.Default.CommunicationTimeout = communicationTimeout; 
} 

Parece que el mapeo podría ser reutilizado en otro lugar o es posible que desee. Además, si la configuración de números creció, podrían dividirse aún más por categoría.

En casos como este, no diría que valga la pena, y si lo hice dependerá de mi estado de ánimo o de la cantidad de nubes en el cielo. Pero sí, técnicamente hay dos niveles que podrían dividirse.

0

cómo saber si una función hace una cosa o más? depende del nivel de abstracciones. Intento describir el nivel de abstracción en los ejemplos de remolque (libro de código limpio, capítulo 3) ver el código

public function buildPage() { 
    $page = header(); 
    $page .= body(); 
    $page .= footer(); 
    return $page; 
} 

esta función sólo hace una cosa y todas las subfunciones son parte de la frase buildPage

public function sendMail() { 
    $user = $this->getUser(); 
    $this->mailer->content("send this message!") 
     ->to($user->email)->send(); 
} 

esta función necesita el correo electrónico del usuario, por lo que con la ayuda de la función getUser sendMail logra obtener el correo electrónico del usuario. pero $ user = getUser() no se describen en la frase sendMail las mejores prácticas para esta función es

public function sendMail($email,$message) { 
    $this->mailer->content($message)->to($email)->send(); 
} 
Cuestiones relacionadas