繁体   English   中英

避免或接受破坏编辑和继续的C#构造?

[英]Avoid or embrace C# constructs which break edit-and-continue?

我开发并维护一个用C#2.0编写的大型(500k + LOC)WinForms应用程序。 它是多用户,目前部署在大约15台机器上。 系统的开发正在进行中(可以被认为是一个永久的测试版),并且很少有人能够保护用户免受可能在每周构建中引入的潜在新错误的影响。

出于这个原因,我发现自己变得非常依赖于调试器中的编辑和继续。 它不仅有助于寻找漏洞和修复漏洞,而且在某些情况下还可以进行持续开发。 我发现能够在正在运行的应用程序的上下文中执行新编写的代码非常有价值 - 不需要重新编译并为新代码添加特定的入口点(必须添加虚拟菜单选项,按钮等等)应用程序并记住在下一个生产构建之前删除它们 - 所有内容都可以在不停止进程的情况下实时进行测试和测试。

我坚持编辑并继续这么高的考虑,我积极地编写代码以完全兼容它。 例如,我避免:

  • 匿名方法和内联委托(除非完全不可能重写)
  • 通用方法(稳定,不变的实用程序代码除外)
  • 以'任何CPU'为目标的项目(即永远不会以64位执行)
  • 在声明点初始化字段(初始化移动到构造函数)
  • 编写使用yield枚举器块(实用程序代码除外)

现在,我完全清楚C#3和4中的新语言功能在很大程度上与编辑和继续(lambda表达式,LINQ等)不兼容。 这是我拒绝将项目迁移到更新版本的框架的原因之一。

我的问题是,避免使用这些更高级的结构来支持非常非常容易调试的代码是否是一种好的做法? 这种发展是否合法,还是浪费? 另外,重要的是,这些构造中的任何一个(lambda表达式,匿名方法等)是否会产生性能/内存开销,这些代码可以避免编写良好,编辑和继续兼容的代码? ...或者C#编译器的内部工作方式是否使这些高级构造比手动编写的“扩展”代码运行得更快?

不想听起来陈旧 - 编写单元/集成测试而不是依赖Edit-Continue是一种好习惯。

这样,你花了一次力,每隔一段时间都是'免费的'......

现在我不建议你回顾性地编写所有代码的单位; 相反,每次你必须修复一个错误,首先要编写一个测试(或更常见的多个测试)来证明修复。

正如@Dave Swersky在评论中提到的那样,Mchael Feathers的书“有效地使用遗留代码”是一个很好的资源(它是你写的5分钟之后的遗产,对吧?)

所以是的,我认为避免新的C#结构有利于允许编辑和继续是错误的; 但我也认为仅仅为了它而接受新结构是错误的,特别是如果它们导致更难理解代码。

我喜欢'编辑并继续'。 我发现它是交互式开发/调试的一个巨大推动因素,当它不起作用时我也觉得很烦人。

如果“编辑并继续”有助于您的开发方法,那么请务必做出选​​择以促进它,同时牢记您放弃的价值。

我的一个烦恼是,使用lambda表达式编辑函数中的任何内容都会破坏“编辑并继续”。 如果我绊倒它,我可能会写出lambda表达式。 我正在使用lambda表达式。 我可以用它们更快地完成一些事情,但是如果我最后把它们写出来,它们就不会节省我的时间。

在我的情况下,我不想使用lambda表达式。 如果它们妨碍我将它们包装在一个函数中,以便我可以“编辑并继续”使用它们的代码。 如果他们是无偿的,我可以写出来。

你的方法不需要是黑白的。

想要澄清一下这些事情

最好避免使用这些更高级的结构来支持非常非常容易调试的代码?

编辑和继续不是真正的调试,它正在开发。 我之所以这样区别,是因为新的C#功能非常可调试。 该语言的每个版本都增加了对新语言功能的调试支持,以使它们尽可能简单地进行调试。

一切都可以在不停止过程的情况下实时测试和测试。

这种说法具有误导性。 “编辑”和“继续”可以验证更改是否修复了一个非常具体的问题。 验证更改是否正确并且不会破坏许多其他问题要困难得多。 即因为编辑和继续不修改磁盘上的二进制文件,因此不允许单元测试等项目。

总的来说,虽然是的,我认为避免新的C#结构有利于允许编辑和继续是错误的。 编辑和继续是一个很棒的功能(当我第一次在C ++时代遇到它时真的很喜欢它)。 但它作为生产服务器助手的价值并不能弥补新的C#功能恕我直言的生产收益。

我的问题是,避免使用这些更高级的结构来支持非常非常容易调试的代码是否是一种好的做法

我认为,只要你强迫自己编写以下代码:

  1. 表现力较差
  2. 更长
  3. 重复(避免通用方法)
  4. 非便携式(从不调试和测试64位??!?!?)

您正在增加总体维护成本,远远超过调试器中“编辑并继续”功能的丢失。

我会尽可能编写最好的代码,而不是使IDE的功能工作的代码。

虽然您的方法没有任何本质上的错误,但它确实限制了IDE理解的表达量。 您的代码反映了它的功能,而不是语言的功能,因此您在开发世界中的整体价值会降低,因为您将不再学习其他提高生产力的技术。 避免使用编辑并继续使用LINQ对我个人来说感觉就像是一个巨大的机会成本,但矛盾的是你必须先获得一些使用它的经验才能有这种感觉。

此外,正如其他答案中所提到的,对代码进行单元测试无需一直运行整个应用程序,从而以不同的方式解决您的困境。 如果您无法在IDE中右键单击并仅测试您关心的3行代码,那么您在开发过程中就已经做了太多工作。

您应该真正介绍继续集成,它可以帮助您在部署软件之前查找和消除错误。 特别是大项目(我认为500k相当大)需要某种验证。

http://www.codinghorror.com/blog/2006/02/revisiting-edit-and-continue.html

关于具体问题:不要避免使用这些结构,也不要依赖于你疯狂的调试技巧 - 尽量避免错误(在已部署的软件中)。 改为编写单元测试。

我还参与过非常大的永久性测试项目。

我使用匿名方法和内联委托来保留一些相对简单的使用 - 一个逻辑接近他们唯一的使用地点。

我已经使用泛型方法和类来重用和可靠。

我已经在构造函数中初始化了尽可能完整的类,以维护类不变量并消除由无效状态中的对象引起的错误的可能性。

我已经使用枚举器块来减少创建枚举器类到几行所需的代码量。

所有这些都有助于在可靠的状态下维持一个快速变化的大型项目。

如果我无法编辑并继续,我会编辑并重新开始。 这大部分时间花费我几秒钟,在讨厌的情况下花费几分钟。 值得一提的是,通过重用提高代码和提高可靠性的能力使我更加节省了时间。

我会做很多事情来让它更容易找到错误,但是如果它也能让它更容易出错。

您可以尝试测试驱动开发 我发现完全避免使用调试器非常有用。 您从一个新测试(例如单元测试)开始,然后您只运行此单元测试来检查您的开发 - 您不需要整个应用程序一直运行。 这意味着您不需要编辑并继续!

我知道TDD是当前的流行词,但它确实适合我。 如果我需要使用调试器,我将其视为个人故障:)

依靠编辑和续。 听起来好像花在设计新功能上的时间很少,更不用说单元测试了。 我觉得这很糟糕,因为你最终可能会进行大量的调试和修复bug,有时你的错误修复会导致更多错误,对吧?

但是,很难判断您是否应该使用语言功能,因为这还取决于许多其他因素:项目需求,发布截止日期,团队技能,重构后的代码可管理性成本,仅举几例。

希望这可以帮助!

你似乎遇到的问题是:

重建你的应用程序需要很长时间,再次启动它并获得你正在处理的UI。

正如大家所说的,单元测试将有助于减少运行应用程序以查找/修复无UI代码上的错误的次数; 但是他们没有帮助解决UI的布局等问题。

在过去,我编写了一个测试应用程序,它将快速加载我正在处理的UI并用虚拟数据填充它,以减少周期时间。

将任何UI代码分离到可以使用单元测试进行测试的其他类中,将允许您在这些类中使用所有C#构造。 然后你可以在UI代码中限制自己使用的构造。

当我开始编写大量单元测试时,我对“编辑并继续”的使用失败了,除了UI代码之外我几乎不能使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM