Perché la coesione sequenziale per le operazioni in un metodo non è una buona idea?

3

Ho letto dal seminale codice Completato il libro che le istruzioni del metodo che richiedono di essere eseguite nell'ordine che passa parametro da uno a uno è un odore di codice ed è un esempio di coesione sequenziale . Perché non è una buona idea?

Un esempio forzato di coesione sequenziale:

public Part createPart(input) {
        PartOne partOne = computePartOne(input);
        PartTwo partTwo = computePartTwo(partOne);
        PartThree partThree = computePartThree(partTwo);
        PartsBuilder partsBuilder = new PartsBuilder();
        return partsBuilder.add(partOne).add(partTwo).add(partThree).build();
    }

Ecco l'azione:

Several other kinds of cohesion are normally considered to be less than ideal:

Sequential cohesion exists when a routine contains operations that must be performed in a specific order, that share data from step to step, and that don't make up a complete function when done together.

An example of sequential cohesion is a routine that, given a birth date, calculates an employee's age and time to retirement. If the routine calculates the age and then uses that result to calculate the employee's time to retirement, it has sequential cohesion. If the routine calculates the age and then calculates the time to retirement in a completely separate computation that happens to use the same birth-date data, it has only communicational cohesion.

How would you make the routine functionally cohesive? You'd create separate routines to compute an employee's age given a birth date and compute time to retirement given a birth date. The time-to-retirement routine could call the age routine. They'd both have functional cohesion. Other routines could call either routine or both routines.

    
posta Geek 03.03.2013 - 18:20
fonte

5 risposte

8

Penso che l'esempio sia in realtà Coeso funzionale non Sequenzialmente coesivo . Gli input e gli output si sono appena verificati, ma i metodi potrebbero essere stati usati indipendentemente. "Altre routine potrebbero chiamare routine o entrambe le routine." - altre routine potrebbero chiamare qualsiasi dei metodi computePart.

Ecco un esempio che ritengo migliore dimostra la coesione sequenziale.

public Part createPart(input) {
        setInput(input);
        computePartOne();
        computePartTwo();
        computePartThree();
        PartsBuilder partsBuilder = new PartsBuilder();
        return partsBuilder.add(this.PartOne).add(this.PartTwo).add(this.PartThree).build();
    }

Dove l'esempio sopra riportato ha un accoppiamento tra gli stadi in quanto le parti si trovano all'interno dell'oggetto e non è possibile utilizzarle in modo indipendente. Sono strettamente accoppiati - in realtà "condividono i dati da un passaggio all'altro".

    
risposta data 03.03.2013 - 18:58
fonte
0

Secondo me sopra è un semplice esempio di sequential cohesion . Se osservate la funzione, noterete che contiene funzioni che dipendono dagli input e dagli output delle altre funzioni ( pipeline ). Non so perché ci sia una confusione riguardo a questo concetto.

    
risposta data 18.06.2013 - 07:17
fonte
0

Penso che gran parte di questo problema sia stata la scelta delle parole. "Meno che ideale" non implica necessariamente un codice errato. Se guardi nel libro originale di Ed Yourdon e Larry Constantine Structured Design, vedrai che gli autori attribuiscono una scala soggettiva ai diversi livelli di coesione:

  • 0 - coincidente
  • 1 - logico
  • 3 - temporale
  • 5 - procedurale
  • 7 - comunicativo
  • 9 - sequenziale
  • 10 - funzionale

Si noti che la scala non è lineare e sequenziale (9) è molto vicino al funzionale (10). Gli autori affermano anche che "i tre più alti suggeriscono progetti semplici ed economici".

Come vedi, questo non supporta l'affermazione che il codice dell'esempio "non è una buona idea".

    
risposta data 12.03.2014 - 15:23
fonte
0

La gerarchia di coesione è molto utile, ma in questo caso ti stai sforzando con gli gnats. Ci sono delle distinzioni utili, se sottili, da fare all'estremità superiore dello spettro. Tuttavia, tali distinzioni non equivalgono ad un "odore". Quando arrivi all'estremità inferiore, puoi parlare di odore (e persino di puzza, nei casi peggiori).

L'esempio è artificioso. Potremmo modificare leggermente l'esempio, ad esempio, rendendo il processo di calcolo dell'età non lineare, con una serie di calcoli a intervalli che richiedono la lettura di una tabella di database. Pertanto, dal punto di vista della funzionalità, il calcolo dell'età è coeso e, per estensione, anche il calcolo del ritiro che dipende da un calcolo dell'età corretto è funzionale.

Esiste ancora una dipendenza sequenziale tra i due calcoli: l'età DEVE essere calcolata prima della data di ritiro. Quindi, un calcolo deve avvenire prima dell'altro, indipendentemente dal fatto che siano chiamati dalla stessa funzione o meno. Quando si deve imporre l'ordine delle chiamate di funzione, qualcosa deve essere responsabile della sequenza delle chiamate.

In conclusione. Nessun odore di codice. Solo qualcosa che potrebbe essere migliorato con pochissimi benefici.

    
risposta data 12.03.2014 - 17:07
fonte
0

Non ho idea se questo fosse quello che gli autori avevano in mente, ma ...

Se è necessario eseguire un set di metodi per passare il parametro da uno a quello successivo, ci sono due possibilità ...

  1. La tipizzazione statica applica l'ordinamento corretto a causa dei parametri richiesti e dei valori restituiti.

  2. La tipizzazione statica non può imporre l'ordinamento, forse perché gli stessi tipi si ripetono in più punti ma i valori non sono intercambiabili.

Dal mio punto di vista, il secondo caso è piuttosto negativo perché o c'è una certa applicazione della sequenza in fase di esecuzione (stato di tracciamento all'interno dell'oggetto) o non c'è alcun controllo degli errori. Per quanto possibile, preferisco che i miei errori di codifica vengano rilevati in fase di compilazione.

Il primo caso è quasi altrettanto negativo per lo stesso motivo. OK, non è possibile ottenere la sequenza sbagliata senza ottenere un errore in fase di compilazione. Ma tu puoi lasciare la sequenza incompleta. Oppure chiama due volte lo stesso metodo, scartando i risultati della prima chiamata. Ci sono molti modi per fare in modo creativo cose sbagliate che i controlli statici non rilevano.

Naturalmente se stai bene con il controllo dello stato di runtime all'interno della classe, va bene. Ma perché restituire i dati al chiamante solo per richiederne di nuovo alcune chiamate dopo? Perché non tenerlo con lo stato che stai già monitorando?

Inoltre, quali sono le alternative? Uno è quello di utilizzare una singola chiamata, il che potrebbe significare fornire un enorme elenco di parametri per quella chiamata, che è un altro odore di codice. Per evitare ciò, potresti raggruppare quei parametri: fornire un blocco di parametri a una singola chiamata.

Piuttosto che un vecchio blocco di parametri in stile C, probabilmente preferiresti una classe. Ma una volta che i dati vengono forniti a quella classe tramite le chiamate al metodo, sei tornato al punto di partenza: molti metodi rispetto a uno con molti parametri e probabilmente la necessità di sequenziare i metodi.

    
risposta data 03.03.2013 - 19:09
fonte