2013-04-01 12 views
8

(Sto usando la parola "flusso di lavoro" - non nel senso di flussi di lavoro asincroni - ma piuttosto nel senso del "workflow", cioè come lo si utilizza come parte del proprio sviluppo)F # Flussi di lavoro/Processo di sviluppo

Dopo aver giocato con F # per un po ', ho iniziato a sviluppare la mia prima app F #. Sono di C#/vb. Dopo aver assistito a vari demo/discorsi, a torto oa ragione, ho iniziato a utilizzare FSI come "motore" di sviluppo principale ea lavorare su quell'area. Se riscontro un problema che ho bisogno di eseguire il debug, tendo a suddividere la funzione problematica in bit più piccoli e controllo quei lavori per provare a eseguire il debug del problema.

Tuttavia, per mantenere la quantità di codice gestibile in fsi, una volta che sono soddisfatto di ciò che ho fatto, lo spostamento in un file .fs e # carica il file .fs in fsi. Man mano che l'app diventa più grande, questo può iniziare a sentirsi un po 'sgraziato da quando ho bisogno di refactoring, finisco per dover riportare il contenuto dal file fs cambiarlo per far funzionare qualcosa di nuovo, prima di spingere indietro il codice nel file .fs. Inoltre, questo stile non è in realtà un primo approccio di prova e quindi non sto ottenendo il beneficio di creare una serie di test. (Posso anche perdere la possibilità di impostare punti di interruzione/passaggio del codice che, in determinate situazioni, ad esempio la ricorsione, può essere più veloce per diagnosticare errori piuttosto che scomporre parti di una funzione, anche se forse è disponibile in VS11 e non sono impostato giusto) .. quindi penso che forse non sto facendo le cose in modo ottimale o altrimenti non penso alle cose nel modo giusto.

Mi chiedevo se altri potrebbero offrire come sviluppano le app. Utilizzi principalmente fsi o inizi con tdd. L'approccio tdd dovrebbe essere il veicolo di sviluppo primario e l'FSI utilizzato in modo più selettivo per l'implementazione, ad esempio, di algoritmi più complessi, esplorazione dei dati ecc.

Ho guardato a this question e ovviamente è utile consultare vari framework TDD per F #, ma sarei ancora interessato a scoprire il flusso di lavoro degli sviluppatori stagionati di F #.

Molti thx

S

+0

Hai provato [file di script] (http://blogs.msdn.com/b/carlnol/archive/2011/08/09/creating-f-fsx-script-files- da-fs-source-files.aspx? Redirected = true)? Sembra una buona opportunità per aggiungere alcuni test lungo la strada –

+0

Thx. Qualche possibilità di espandermi un po 'su TDD? Li ho usati semplicemente come un modo "più libero" di far eseguire le cose in fsi. Mi manca ovviamente qualcosa! –

+0

Il REPL non sostituisce i test appropriati. Piuttosto si completano a vicenda. https://twitter.com/missingfaktor/status/314452078682595328 –

risposta

12

penso che sei sulla strada giusta.

Il processo di sviluppo è una questione di gusti. Condividerò il mio approccio comunque.

  • Iniziare con alcuni file fs. Ogni file rappresenta un modulo, che consiste in un gruppo di funzioni strettamente correlate tra loro. Non deve essere preciso dall'inizio; muovi spesso cose tra i moduli.
  • Creare alcuni file fsx per test rapidi una volta che lo scheletro dei moduli è pronto.
  • Creare un progetto di test e configurare i pacchetti NuGet. Io uso spesso NUnit e FsUnit insieme.
  • Ogni volta che lo script fsx dà risultati corretti, spostarli in casi di test. Fallo ripetutamente.
  • Includere un Program.fs nel progetto principale e compilarlo in eseguibile per eseguire il debug se necessario.

In generale, F # REPL è il motore di sviluppo principale. Mi dà feedback istantanei e consente modifiche incrementali, che sono molto utili nella prototipazione. In F #, il TDD è meno critico in quanto il tasso di errore è molto inferiore rispetto ad altre lingue. E non collaudo tutto, concentrati solo sulle funzionalità principali e garantisco una copertura di prova elevata.L'utilizzo del componente aggiuntivo testdriven.net o Visual Studio 2012 Premium and Ultimate può fornire statistiche utili sulla copertura del test.

Utilizzando F # REPL e TDD, non ho quasi mai bisogno di usare il debug. Ogni volta che c'è un comportamento sbagliato, mi fermo e penso. Poiché i tuoi codici non hanno effetti collaterali, puoi ragionarli facilmente. In molte occasioni il ragionamento e alcuni comandi di stampa possono darmi la risposta giusta.

È possibile utilizzare TDD in F # REPL con Unquote e FsCheck. Il primo offre test tramite citazioni, il che è piuttosto impressionante. Quest'ultimo utilizza un approccio di test casuale che è attraente nella gestione dei casi d'angolo dei tuoi codici. Trovo davvero utile quando i tuoi programmi devono soddisfare determinate proprietà. Tuttavia, potrebbe essere necessario del tempo per imparare a utilizzare correttamente questi framework.

+0

Thx. Molto utile. –

+0

@GuyCoder: Grazie, aggiungi una frase sulla copertura del codice. – pad

3

pad ha dato un'ottima risposta che è molto pratica e utile per una persona nuova a F #. Darò un mezzo diverso in modo che gli altri non pensino che ci sia solo un modo in cui i F # lo fanno.

Nota: se si è principianti nella programmazione, quindi attenersi alla risposta del pad, è molto meglio per un nuovo programmatore.

Nel mondo Object Oriented si pensa con gli oggetti e in tali lingue Vorrei iniziare con la scrittura oggetti giù su carta e lavorare con vari diagrammi quali use-case, state transition, sequence diagram, ecc, fino a quando ho sentito che dovevo abbastanza per iniziare a creare oggetti in file C# cs, rimpolpando gli oggetti con metodi, proprietà, eventi, ecc.

Nel mondo funzionale in genere inizio con concetti astratti e li converto in discriminated unions (DU) in un file F # fs, saltando l'uso di un REPL, ovvero F# Interactive, quindi iniziare ad aggiungere alcune funzioni. Dopo aver alcune funzioni, ho impostato un progetto di test utilizzando NUnit e FsUnit tramite NuGet. Dal momento che il DU è astratto, i test case sono tipicamente più difficili da scrivere, quindi creo le stampanti per il DU e poi le inserisco nel caso di test in cui catturo l'output dei risultati dalla stampante nello strumento NUnit, per tagliare e incollare nuovamente nel test case che apporta le modifiche necessarie. Vedi these per esempi del motivo per cui non li scrivo da zero a mano.

Una volta eseguito il DU astratto, posso quindi passare al codice per convertire la forma umana/concreta in DU astratto e convertire l'DU in astratto in forma umana/concreta. In alcuni casi questi sarebbero parsers e pretty printers.

Il punto principale che sto cercando di fare è che non mi concentro sugli strumenti che uso ma sul concetto astratto del problema e portare gli strumenti quando necessario.

Noterò che programma anche in PROLOG e lì comincio con REPL e sposta il codice in un negozio una volta che la logica funziona. Quindi non sono contrario all'utilizzo di un REPL, è solo un modo diverso di affrontare il problema.

EDIT

Per una richiesta da parte Ken per un esempio.

See: Discriminated Unions (F#) e cercare la sezione
Using Discriminated Unions Instead of Object Hierarchies

Così, invece di un tipo di base di forma con tipi ereditati di Cerchio, EquilateralTriangle, rettangolo e del quadrato si potrebbe creare un'Unione discriminata come notato:

type Shape = 
| Circle of float 
| EquilateralTriangle of double 
| Square of double 
| Rectangle of double * double 

Dato che la tua domanda renderebbe una domanda indipendente molto migliore e ottenere risposte con molti più dettagli di quelli che posso dare, ti suggerirei di chiederlo.

anche se si cerca sulla ricerca anche con le seguenti sostituzioni per un'unione discriminata (DU):

+0

Thx vm. C'è un po 'da digerire lì - specialmente gli esempi! Ho ragione nel pensare che crei DU in circa lo stesso punto in cui inizieresti a creare gerarchie di oggetti se lavori in C#, o stai dicendo qualcosa di leggermente diverso? Inoltre, hai un esempio di cosa intendi quando dici "creare stampanti per la DU" - StructuredFormatDisplayAttribute? –

+1

"Ho ragione nel pensare che crei DU in circa lo stesso punto in cui avresti iniziato a creare gerarchie di oggetti se lavoravi in ​​C#," Sì che è fondamentalmente corretto. Con OO pensate prima agli oggetti, ma con funzioni funzionali pensate prima, ma le funzioni necessitano di alcuni tipi prima di poterle scrivere e quindi per qualcosa oltre le basi avrete probabilmente bisogno di un DU. Nota: è possibile fare progetti che non hanno bisogno di un DU perché sono tutte funzioni dei tipi di base, quindi non pensare che sia sempre necessaria una DU, proprio come potresti non aver bisogno di un oggetto in un linguaggio OO per risolvere un problema. –

+1

"Inoltre, hai un esempio di cosa intendi quando dici" creare stampanti per la DU ". Questa è davvero una buona domanda che dovresti chiedere qui su SO. Ti indicherò alcuni qui, ma chiederò seriamente come altri puoi dare più informazioni di questo.Vedi: [fol.fs] (https://github.com/jack-pappas/fsharp-logic-examples/blob/master/FSharpx.Books.AutomatedReasoning/fol.fs) Hai anche bisogno per sapere di AddPrinter, vedere: [fol.fsx] (https://github.com/jack-pappas/fsharp-logic-examples/blob/master/Examples/fol.fsx) –

Problemi correlati