'Progettare prima con i tipi' in definitiva equivale a 'progettare prima con le interfacce'?

2

In Object Oriented Programming, ci viene insegnato a pensare in termini di Polymorphism (l'idea che l'implementazione sia disaccoppiata dall'interfaccia) e che abbia senso pensare prima all'interfaccia).

Questo è espresso da Eric Gamma (autore di Quaderno di Gang of Four Design Patterns )

Program to an interface, not an implementation

Successivamente abbiamo appreso che questo è un modo per risolvere Il problema dell'espressione .

Altre lingue come l'indirizzo Clojure "The Expression Problem" utilizzando i protocolli .

Ora uscendo da Scala (e forse influenzato da Haskell) stiamo assistendo a un movimento del design che dice "Progetta i tuoi tipi prima" . Quando l'ho sentito, pensavo di averlo sentito prima.

La mia domanda è: "Il design con i tipi prima di tutto" è in definitiva lo stesso di "progettare prima le interfacce"?

    
posta hawkeye 04.09.2014 - 14:08
fonte

3 risposte

2

Nei linguaggi Java, le interfacce descrivono i tipi di oggetto, le classi descrivono i tipi di dati astratti. "Progettare prima le interfacce" non è lo stesso di "progettare prima i tipi", semplicemente perché in una classe di linguaggio Java (e primitive) ci sono anche tipi (ma non tipi di oggetti). Quindi, "progettare prima con le interfacce" significa davvero "fai OO".

Tuttavia, "progettare prima i tipi" non significa esattamente ciò che pensi significhi. L'idea è di usare i tipi per modellare il dominio del problema e lasciare che i tipi guidino la progettazione e lo sviluppo. È più simile al TDD in questo senso: in TDD, i test ti dicono cosa fare dopo, ti dicono cosa fare, ti dicono come farlo, ti dicono quale sia il tuo design, ti dicono come strutturare il tuo codice e ti dicono quando hai finito.

Lo chiamerei forse lo sviluppo basato sui tipi (che può essere abbreviato in modo conveniente e confuso con TDD), perché si usano i tipi nello stesso modo in cui si usano i test in TDD. Non si tratta di progettare prima con i tipi, si tratta dei tipi che guidano tutto: progettarli prima è semplicemente un prerequisito per questo.

    
risposta data 05.09.2014 - 01:45
fonte
3

Un piccolo case study: un pattern matcher in due pseudo-lingue, prima OO e poi funzionale

In OOP, progettazione dell'interfaccia prima

interface IPatternMatcher {
    bool Match(string toMatch)
}

Quanto sopra è l'unica interfaccia di cui abbiamo bisogno, ma in realtà non ci fornisce alcun indizio su come progettare i nostri tipi di implementazione. Probabilmente vorrai dei compositi, quindi implementerai un OrPatternMatcher

class OrPatternMatcher : IPatternMatcher {
    OrPatternMatcher(list<IPatternMatcher> submatchers);

    bool Match(string toMatch) {
        return _submatchers.Any(s => s.Match(toMatch));
    }
}

Ma ora hai iniziato ad implementare funzionalità, senza aver completato la tua gerarchia. È praticamente impossibile separare questi due stadi in OOP perché le tue funzioni e tipi sono così intrecciati

In FP, progettazione di tipo prima

type PatternMatcher =
| OrPatternMatcher        : list<PatternMatcher>
| AndPatternMatcher       : list<PatternMatcher>
| SubstringPatternMatcher : string
| RegexPatternMatcher     : regex

Qui abbiamo tutti i tipi necessari progettati in anticipo, che coprono tutti i casi a cui puoi pensare. Il tipo di unione PatternMatcher in FP è correlato all'interfaccia IPatternMatcher OOP, con la differenza cruciale che l'unione dichiara la sua struttura di tipo senza funzioni , mentre l'interfaccia dichiara le sue funzioni con no type structure .

Ora è banale implementare una funzione match semplicemente osservando la forma dei tipi che hai disposto. Se hai progettato i tipi in modo ragionevole per il tuo dominio, sei già quasi tutto il modo di avere un componente funzionante. Questo è ciò che significa prima progettare i tuoi tipi - per modellare accuratamente il tuo dominio senza preoccuparti di comportamento

Secondo me le interfacce OOP e i tipi FP sono quasi l'opposto l'uno dell'altro, ei vantaggi ottenuti dalla progettazione dei tuoi tipi FP in anticipo sono molto diversi da quelli ottenuti dalla programmazione su un'interfaccia.

Come ulteriore ripensamento, la frase "progetta le tue interfacce prima" non è la stessa cosa di "programma su un'interfaccia" e quindi quest'ultima non può essere veramente paragonata a "progetta i tuoi tipi prima".

  • "programma su un'interfaccia" sostiene il disaccoppiamento dei componenti non assumendo i dettagli di implementazione
  • "progetta i tuoi tipi prima" è un consiglio su come modellare sensibilmente il tuo dominio prima di implementare il comportamento

I due in realtà non sono paragonabili, in quanto si riferiscono a situazioni diverse

    
risposta data 04.09.2014 - 16:38
fonte
2

Per prima cosa, non vedo come la programmazione delle interfacce risolva il problema delle espressioni.

In breve, il problema dell'espressione afferma che puoi solo aggiungere nuovi dati o nuove funzioni a un tipo di dati (senza ricompilare) - non entrambi.

La programmazione sulla maggior parte delle interfacce consente di creare nuove funzioni che utilizzano tale interfaccia, ma non è possibile aggiungere dati all'interfaccia senza ricompilarla.

Ora, sulla carne della domanda:

Is 'design with types first' ultimately the same as 'design with interfaces first'?

Non proprio.

Le interfacce di design per prime implicano l'approccio al design da come verrà utilizzato, piuttosto che il modo in cui verrà implementato.

I tipi di progetto prima implicano anche questo, ma in un linguaggio come scala alcuni dettagli dell'implementazione avranno un impatto su come può essere strutturato. Utilizzerai tipi strutturali? Utilizzerai le classi di casi? Hai intenzione di mescolare alcuni tratti? Il modo in cui dividi le parti riutilizzabili cambierà la modalità di presentazione dell'interfaccia per l'uso del codice.

    
risposta data 04.09.2014 - 17:21
fonte