F#工作流程/开发流程

时间:2013-04-01 07:56:29

标签: f# tdd

(我正在使用“工作流程”这个词 - 不是在异步工作流程的意义上 - 而是在“git工作流程”意义上,也就是说,如何将其用作开发的一部分)

玩了一段时间的F#,我开始开发我的第一个F#应用程序。我来自c#/ vb。观看了各种演示/演讲 - 无论是对还是错 - 我开始使用fsi作为主要的开发“引擎”并在该领域内开展工作。如果我遇到了需要调试的问题,我倾向于将有问题的功能分解成更小的位并检查那些工作以尝试调试问题。

但是,为了在fsi中保持代码量可管理,一旦我对我所做的事情感到满意,我就把它移到.fs中并将#fs重新加载到fsi中。随着应用程序变得越来越大,这可能会开始变得有点笨拙,因为当我需要重构时,我最终不得不从fs文件中恢复内容更改它运行的东西以使某些东西再次运行,然后再将代码推回去进入.fs文件。此外,这种风格并不是真正的测试第一种方法,因此我没有获得构建一组测试的好处。 (我也可以错过设置断点/步进代码的能力,在某些情况下,例如递归,可以更快地诊断错误而不是破坏函数的某些部分 - 虽然这可能在VS11中可用而且我没有设置对...)所以我认为我可能没有以最佳方式做事,或者没有以正确的方式思考问题。

我想知道其他人是否可以提供他们开发应用程序的方式。你主要使用fsi还是从tdd开始?应该将tdd方法作为主要的开发工具,并且FSI更有选择性地用于帮助实施更复杂的算法,数据探索等等。

我看过this question,显然它有助于指出F#的各种tdd框架,但我仍然有兴趣找出经验丰富的F#开发人员的工作流程。

很多thx

取值

2 个答案:

答案 0 :(得分:12)

我认为你走在正确的轨道上。

开发过程是一个品味问题。无论如何,我会分享我的方法。

  • 从几个fs文件开始。每个文件代表一个模块,它由一组彼此密切相关的功能组成。从一开始就没有必要精确;你经常在模块之间移动东西。
  • 创建一些fsx文件,以便在模块的骨架准备就绪后进行快速测试。
  • 创建一个测试项目并设置NuGet包。我经常一起使用NUnit和FsUnit
  • 每当fsx脚本提供正确的结果时,请将它们移至测试用例。 反复这样做。
  • 在主项目中加入Program.fs并编译为可执行文件,以便在需要时进行调试。

通常,F#REPL是主要的开发引擎。它为我提供即时反馈并允许增量更改,这在原型设计中非常有用。在F#中,由于错误率远低于其他语言,因此TDD不太重要。我不会测试所有内容,只关注主要功能并确保高测试覆盖率。使用testdriven.net加载项或Visual Studio 2012 Premium and Ultimate可以为您提供有关测试覆盖率的有用统计信息。

使用F#REPL和TDD,我几乎不必使用调试。每当出现错误行为时,我都会停下来思考。由于您的代码没有副作用,您可以轻松地对其进行推理。在很多时候,推理和一些打印命令可以给我正确的答案。

您可以在UnquoteFsCheck的F#REPL中使用TDD。前者通过报价提供测试,这非常令人印象深刻。后者使用随机测试方法,这在处理代码的角落情况时很有吸引力。当你的程序必须满足某些属性时,我发现它非常有用。但是,学习正确使用这些框架可能需要一些时间。

答案 1 :(得分:3)

pad给出了一个非常实用且对F#新手有用的答案。我将提供一种不同的方式,以便其他人不认为F#的人只有一种方式。

注意:如果你对编程很陌生,那么坚持使用pad的答案,这对于一个新程序员来说要好得多。

Object Oriented世界中,人们会考虑使用对象和这些语言,我会先将对象写在纸上并使用各种图表,例如use-casestate transition,{{3等等,直到我觉得我已经足够开始在C#cs文件中创建对象,用方法,属性,事件等来充实对象。

在功能世界中,我通常从抽象概念开始,并在F#fs文件中将它们转换为sequence diagram(DU),跳过使用discriminated unions,即REPL,以及然后开始添加一些功能。在我有一些函数后,我使用F# InteractiveNUnit通过FsUnit设置了一个测试项目。由于DU是抽象的,测试用例通常难以编写,因此我为DU创建打印机,然后将它们插入到测试用例中,我在NUnit工具中捕获打印机的结果输出,用于剪切和粘贴回到测试用例根据需要进行更改。请参阅NuGet,了解我不能手工编写的原因。

一旦我完成抽象DU,我就可以转到代码上将人/具体形式转换为抽象DU,并将抽象DU转换为人/具体形式。在某些情况下,这些会是theseparsers

我要说的主要观点是,我不会专注于我使用的工具,而是关注问题的抽象概念,并在需要时将工具带入。

我会注意到我也在pretty printers编程,然后我从REPL开始,一旦逻辑工作就将代码移到商店。所以我并不反对使用REPL,这只是解决问题的另一种方式。

修改

根据PROLOG的请求获取示例。

请参阅:Ken并查找部分
Using Discriminated Unions Instead of Object Hierarchies

因此,如果没有具有继承类型的Circle,EquilateralTriangle,Square和Rectangle的基本类型的形状,则会创建一个区分联盟,如下所示:

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

由于你的问题会带来一个更好的独立问题,并且能得到比我能给出的更好的细节答案,我建议你问一下。

此外,如果您在此搜索信息,也会使用以下替换进行区分联合(DU)搜索: