首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何知道我的方法应该有多大的可重用性?

如何知道我的方法应该有多大的可重用性?
EN

Software Engineering用户
提问于 2018-11-27 03:18:02
回答 12查看 14.3K关注 0票数 138

我在家管自己的事,我妻子走过来对我说

宝贝..。你能在控制台上打印2018年世界各地所有的日照储蓄吗?我需要检查一下。

我非常高兴,因为这就是我用我的Java经验一直在等待的东西,并想出了:

代码语言:javascript
运行
复制
import java.time.*;
import java.util.Set;

class App {
    void dayLightSavings() {
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(
            zoneId -> {
                LocalDateTime dateTime = LocalDateTime.of(
                    LocalDate.of(2018, 1, 1), 
                    LocalTime.of(0, 0, 0)
                );
                ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
                while (2018 == now.getYear()) {
                    int hour = now.getHour();
                    now = now.plusHours(1);
                    if (now.getHour() == hour) {
                        System.out.println(now);
                    }
                }
            }
        );
    }
}

但后来她说,她只是在测试我是否是一名受过道德教育的软件工程师,并告诉我,我似乎没有(从这里)。

应该指出的是,任何受过道德训练的软件工程师都不会同意编写DestroyBaghdad过程。基本的职业道德要求他写一个DestroyCity程序,巴格达可以作为参数。

我想,好吧,好吧,你让我..。通过任何你喜欢的一年,给你:

代码语言:javascript
运行
复制
import java.time.*;
import java.util.Set;

class App {
    void dayLightSavings(int year) {
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(
            zoneId -> {
                LocalDateTime dateTime = LocalDateTime.of(
                    LocalDate.of(year, 1, 1), 
                    LocalTime.of(0, 0, 0)
                );
                ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
                while (year == now.getYear()) {
                    // rest is same..

但是,我如何知道参数化的数量(以及参数)?毕竟她可能会说..。

  • 她想传递一个自定义字符串格式化程序,也许她不喜欢我已经打印的格式:2018-10-28T02:00+01:00[Arctic/Longyearbyen]

void dayLightSavings(int year, DateTimeFormatter dtf)

  • 她只对某些月份感兴趣。

void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd)

  • 她对某些时段感兴趣。

void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd, int hourStart, int hourend)

如果你在寻找一个具体的问题:

如果destroyCity(City city)destroyBaghdad()好,takeActionOnCity(Action action, City city)更好吗?为什么/为什么不?

毕竟,我可以先用Action.DESTROY调用它,然后再调用Action.REBUILD,不是吗?

但对我来说,对城市采取行动还不够,takeActionOnGeographicArea(Action action, GeographicalArea GeographicalArea)怎么样?毕竟,我不想打电话:

代码语言:javascript
运行
复制
takeActionOnCity(Action.DESTORY, City.BAGHDAD);

然后

代码语言:javascript
运行
复制
takeActionOnCity(Action.DESTORY, City.ERBIL);

等我能做的时候:

代码语言:javascript
运行
复制
takeActionOnGeographicArea(Action.DESTORY, Country.IRAQ);

附注:我的问题只是围绕我提到的话,我没有反对任何国家,宗教,种族或世界上任何东西。我只是想说明一下。

EN

回答 12

Software Engineering用户

回答已采纳

发布于 2018-11-27 07:51:03

一直都是海龟。

或者抽象在这种情况下。

良好的代码实践是可以无限应用的,在某种程度上,您是为了抽象而进行抽象,这意味着您已经做得太过了。找出这条线并不容易,因为它很大程度上取决于你的环境。

例如,我们有一些客户首先要求简单的应用程序,然后才要求扩展。我们也有客户问他们想要什么,通常永远不会回来我们的扩张。

您的方法将因客户而异。对于第一个客户来说,先发制人地抽象代码是值得的,因为您相当肯定将来需要重新访问这段代码。对于第二个客户,如果您期望他们在任何时候都不想扩展应用程序,您可能不想投入额外的精力(注意:这并不意味着您没有遵循任何好的实践,而只是避免做超出当前需要的任何事情)。

我如何知道要实现哪些特性?

我提到上面的原因是因为你已经掉进了这个陷阱:

但是,我如何知道参数化的数量(以及参数)?毕竟,她可能会说。

她可能会说“这不是目前的商业要求。”这是对未来业务需求的猜测。一般情况下,不要以猜测为基础,只发展当前所需的内容。

然而,上下文适用于此。我不认识你妻子。也许你准确地判断了她实际上会想要这个。但是您仍然应该向客户确认这确实是他们想要的,因为否则您将花费时间开发一个永远不会使用的特性。

如何知道要实现哪种体系结构?

这更棘手。客户不关心内部代码,所以您不能问他们是否需要它。他们对这件事的看法基本上是无关紧要的。

但是,您仍然可以通过向客户询问正确的问题来确认这样做的必要性。与其询问体系结构,不如询问他们对未来开发或代码库扩展的期望。您还可以问当前的目标是否有最后期限,因为您可能无法在必要的时间框架内实现您理想的架构。

如何知道何时进一步抽象我的代码?

我不知道我在哪里读到的(如果有人知道的话,请告诉我,我会给予赞扬),但一个好的经验法则是,开发人员应该像穴居人一样计算:一,二,多。

XKCD #764

换句话说,当第三次使用某个算法/模式时,应该对其进行抽象,使其可重用(=多次可用)。

首先要说明的是,我并不是在暗示在只使用算法的两个实例时不应该编写可重用的代码。当然,您也可以抽象它,但是规则应该是,对于三个实例,您必须抽象。

同样,这也是你期望中的因素。如果您已经知道需要三个或更多实例,当然可以立即进行抽象。但是,如果您只猜测您可能希望更多地实现它,那么实现抽象的正确性完全取决于您猜测的正确性。

如果你猜对了,你节省了一些时间。如果您猜错了,您就浪费了一些时间和精力,并且可能会牺牲您的体系结构来实现您最终不需要的东西。

如果destroyCity(City city)destroyBaghdad()好,takeActionOnCity(Action action, City city)更好吗?为什么/为什么不?

这在很大程度上取决于多种因素:

  • 在任何一个城市都可以采取多种行动吗?
  • 这些动作可以互换使用吗?因为如果“破坏”和“重建”操作有完全不同的执行,那么在一个takeActionOnCity方法中合并这两个操作是没有意义的。

还要注意的是,如果您递归地抽象这个,您将得到一个非常抽象的方法,它只不过是一个容器来运行另一个方法,这意味着您已经使您的方法变得无关紧要和毫无意义了。

如果您的整个takeActionOnCity(Action action, City city)方法体最终只是action.TakeOn(city);,那么您应该想知道takeActionOnCity方法是否真的有目的,还是仅仅是一个额外的层,并没有增加任何价值。

但对我来说,对城市采取行动还不够,takeActionOnGeographicArea(Action action, GeographicalArea GeographicalArea)怎么样?

同样的问题出现在这里:

  • 你们有地理区域用例吗?
  • 在一个城市和一个地区执行一个行动是一样的吗?
  • 是否可以对任何地区/城市采取任何行动?

如果您能够确定地回答“是”这三个,那么抽象是有道理的。

票数 118
EN

Software Engineering用户

发布于 2018-11-27 04:13:32

Practice

这是软件工程SE,但是制作软件比工程更艺术。没有通用的算法可遵循,也没有衡量标准来确定可重用性有多大。和任何事情一样,你设计程序的实践越多,你就会得到更好的结果。你会对什么是“够”有更好的感觉,因为当你参数化的太多或太少时,你会看到哪里出了问题,它是如何出错的。

不过,现在这不是很有帮助,那么一些指导原则如何呢?

回头看看你的问题。有很多“她可能说”和“我可以”。很多关于未来需要的理论陈述。人类对未来的预测是愚蠢的。而你(很可能)是个人类。软件设计的主要问题是要考虑一个你不知道的未来。

准则1:你不会需要的

我是认真的。别说了。通常情况下,想象中的未来问题不会出现--当然也不会像你想象的那样出现。

准则2:成本/效益

酷,那个小程序花了你几个小时才写出来的?如果你妻子回来要这些东西怎么办?最糟糕的情况是,你还要花上几个小时的时间来完成另一个程序。在这种情况下,没有太多的时间来使这个程序更加灵活。而且它不会增加运行时的速度或内存的使用。但非平凡的程序有不同的答案。不同的场景有不同的答案。在某种程度上,即使未来的判断技巧不完善,成本也显然不值得受益。

准则3:关注常量

回头看看这个问题。在您的原始代码中,有很多常量的ints。20181.恒定的ints,恒定的字符串..。它们是最有可能需要保持不变的东西。更好的是,它们只需少量时间来参数化(或至少将其定义为实际常量)。但另一件需要警惕的事情是,行为是不变的。例如,System.out.println。这种关于使用的假设往往会在未来发生变化,而且修复成本也会很高。不仅如此,像这样的IO还会使函数变得很困难(同时还会在一定程度上获取时区)。参数化该行为可以使函数更加纯净,从而增加灵活性和可测试性。最大的好处是成本最低(特别是在默认情况下使用System.out的过载)。

票数 43
EN

Software Engineering用户

发布于 2018-11-27 04:57:51

首先:任何出于安全考虑的软件开发人员都不会因为任何原因而不通过授权令牌而编写DestroyCity方法。

我也可以把任何东西写成具有明显智慧的命令,而不需要在另一种情况下适用。为什么有必要授权字符串连接?

第二:所有代码在执行时必须完全指定。

决定是硬编码在适当的位置,还是推迟到另一层并不重要。在某种程度上,在某种语言中有一段代码,它既知道要销毁什么,也知道如何指导它。

它可能位于同一个对象文件destroyCity(xyz)中,也可能位于配置文件:destroy {"city": "XYZ"}"中,也可能是UI中的一系列单击和按键。

第三:

宝贝..。你能在控制台上打印2018年世界各地所有的日照储蓄吗?我需要检查一下。

是一组与以下非常不同的要求:

她想传递一个自定义的字符串格式化程序.只对某些月份感兴趣,. 和对某一小时周期感兴趣.

现在,第二组需求显然提供了一个更灵活的工具。它有更广泛的目标受众和更广泛的应用领域。这里的危险在于,世界上最灵活的应用程序实际上是机器代码的编译器。它实际上是一个非常通用的程序,它可以构建任何东西来使计算机成为你想要的(在它的硬件约束下)。

一般来说,需要软件的人不想要一些通用的东西,他们想要一些特定的东西。通过提供更多的选择,你实际上使他们的生活变得更加复杂。如果他们想要那样的复杂性,他们会使用编译器,而不是问你。

你妻子要求的是功能,而且她对你的要求不够明确。在这种情况下,这似乎是故意的,一般情况下,这是因为他们不知道更好。否则,他们只会自己使用编译器。所以第一个问题是你没有要求更多关于她到底想做什么的细节。她想要经营几个不同的年份吗?她想把它放在CSV文件里吗?你不知道她想自己做什么决定,她要你为她做什么决定。一旦您了解了哪些决策需要推迟,您就可以知道如何通过参数(和其他可配置的方法)来传达这些决策。

话虽如此,大多数客户都会错过交流、猜测或对某些细节一无所知(又名)。他们真的想自己做决定,或者他们真的不想做(但这听起来很棒)。这就是为什么像PDSA (计划开发-学习-行动)这样的工作方法是重要的。您已经按照需求计划了工作,然后开发了一组决策(代码)。现在是时候学习它了,无论是你自己还是和你的客户一起学习,学习新的东西,这些都会告诉你未来的想法。最后,根据你的新见解采取行动--更新需求,改进流程,获得新的工具,等等。那就重新开始计划吧。随着时间的推移,这将揭示出任何隐藏的需求,并向许多客户证明了进步。

终于来了。你的时间是重要的,它是非常真实和有限的。您所做的每一个决定都需要许多其他隐藏的决定,这就是开发软件的意义所在。将决定延迟为参数可能会使当前函数更简单,但它确实会使其他地方变得更复杂。这个决定在另一个地点有关系吗?这里更有意义吗?到底该由谁来决定呢?这是你决定的,这是编码。如果您经常重复一组决策,那么在某些抽象中对它们进行编码有一个非常实际的好处。XKCD在这里有一个有用的视角。这在一个系统的层次上是相关的,无论是功能,模块,程序等等。

最初的建议意味着,您的函数无权做出的决策应该作为一个参数传递。问题是,DestroyBaghdad函数实际上可能是具有此权限的函数。

票数 27
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/382069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档