软件工程

针对在系统开发生命周期中工作的专业人士,学者和学生的问答

1
REST API响应中的null与缺少键
在我的应用程序中说,有些用户给我们他们的姓氏,有些则没有。在REST API响应中,首选哪个主体: 具有“空”值: {"firstName": "Bob", "lastName": null} 或只是缺少的钥匙: {"firstName": "Bob"}
40 rest  api-design  json 

6
为什么SQL不可重构?[关闭]
每个人都知道新开发人员会编写长函数。随着您的进步,您会更好地将代码分解成较小的部分,而经验告诉您这样做的价值。 输入SQL。是的,SQL的代码思考方式与过程的代码思考方式不同,但是该原理似乎同样适用。 假设我有一个采用以下形式的查询: select * from subQuery1 inner join subQuerry2 left join subquerry3 left join join subQuery4 使用一些ID或日期等 这些子查询本身很复杂,可能包含自己的子查询。在任何其他编程上下文中,我都认为复杂子查询1-4的逻辑与将它们全部连接在一起的父查询一致。看起来很简单,应该将那些子查询定义为视图,就像如果我在编写过程代码时将它们作为函数一样。 那么,为什么不这样做呢?人们为什么如此频繁地编写这些冗长的整体SQL查询?SQL为什么不鼓励广泛使用视图,就像过程编程鼓励广泛使用函数一样。(在许多企业环境中,创建视图甚至都不是一件容易的事。需要请求和批准。想象一下,其他类型的程序员每次创建函数时是否都必须提交请求!) 我想到了三个可能的答案: 这已经很普遍了,我正在与经验不足的人一起工作 经验丰富的程序员不会编写复杂的SQL,因为他们喜欢用过程代码解决硬数据处理问题 还有别的

8
当可以有意义地缺少值时,新的布尔字段是否比空引用更好?
例如,假设我有一个类Member,它具有一个lastChangePasswordTime: class Member{ . . . constructor(){ this.lastChangePasswordTime=null, } } 缺少其lastChangePasswordTime可能是有意义的,因为某些成员可能永远不会更改其密码。 但是根据“ 如果空值是邪恶的”,当可以有意义地缺少一个值时应该使用什么?和https://softwareengineering.stackexchange.com/a/12836/248528,我不应该使用null来表示有意义的缺失值。所以我尝试添加一个布尔标志: class Member{ . . . constructor(){ this.isPasswordChanged=false, this.lastChangePasswordTime=null, } } 但是我认为它已经过时了,因为: 当isPasswordChanged为false时,lastChangePasswordTime必须为null,并且检查lastChangePasswordTime == null与检查isPasswordChanged为false几乎相同,因此我更喜欢直接检查lastChangePasswordTime == null。 在此处更改逻辑时,我可能会忘记同时更新两个字段。 注意:当用户更改密码时,我会这样记录时间: this.lastChangePasswordTime=Date.now(); 此处的附加布尔字段是否比空引用更好?
39 null  boolean 

5
为什么继承一个类而不添加属性?
我在我们的(相当大的)代码库中发现了一个继承树,如下所示: public class NamedEntity { public int Id { get; set; } public string Name { get; set; } } public class OrderDateInfo : NamedEntity { } 据我所知,它主要用于绑定前端的东西。 对我来说,这很有意义,因为它为类提供了具体的名称,而不是依赖于generic NamedEntity。另一方面,有许多这样的类根本没有其他属性。 这种方法有什么缺点吗?

11
REST API是否应该返回500 Internal Server Error以指示查询引用了不存在的对象?
我正在使用REST API,该API驻留在为大量IoT设备处理数据的服务器上。 我的任务是使用API​​查询服务器以收集有关所述设备的特定性能信息。 在一个实例中,我获得了可用设备及其对应标识符的列表,然后稍后使用那些标识符(GUID)向服务器查询更多详细信息。 服务器正在500 Internal Server Error对这些ID之一返回a 进行查询。在我的应用程序中,引发了异常,并且我看不到有关该错误的详细信息。如果我使用Postman更仔细地检查响应,则可以看到服务器在包含以下内容的正文中返回了JSON: errorMessage: "This ID does not exist"。 忽略服务器提供ID开头的事实-这对于开发人员是一个单独的问题。 REST API是否应返回,500 Internal Server Error以报告查询引用了不存在的对象?在我看来,HTTP响应代码应严格参考REST调用的状态,而不是API的内部机制。我希望200 OK响应中包含错误和描述,这是所讨论的API专有的。 在我看来,取决于REST调用的结构,期望值可能存在差异。 考虑以下示例: http://example.com/restapi/deviceinfo?id=123 http://example.com/restapi/device/123/info 在第一种情况下,设备ID作为GET变量传递。404或500表示/restapi/deviceinfo找不到路径()或导致服务器错误。 在第二种情况下,设备ID是URL的一部分。我会更了解404 Not Found,但仍可以根据路径的哪些部分被解释为变量还是端点来争论。

6
使用全局唯一的消息ID使代码可查找
查找脚本的常见模式遵循以下脚本: 观察奇怪的地方,例如没有输出或挂起的程序。 在日志或程序输出中找到相关消息,例如“找不到Foo”。(以下内容仅在找到错误所在的路径时才有意义。如果堆栈跟踪或其他调试信息容易获得,则是另一回事了。) 找到打印消息的代码。 调试Foo输入(或应该输入)图片到消息打印的第一处之间的代码。 第三步是调试过程经常停止的地方,因为在代码中有很多地方Could not find {name}都打印了“找不到Foo”(或模板字符串)。实际上,几次拼写错误使我找到实际位置的速度比我原本要快得多-它使消息在整个系统中(通常在整个世界)都是唯一的,从而导致相关搜索引擎立即受到攻击。 由此得出的明显结论是,我们应该在代码中使用全局唯一的消息ID,将其作为消息字符串的一部分进行硬编码,并可能验证代码库中每个ID仅出现一次。在可维护性方面,该社区认为此方法最重要的利弊是什么,您将如何实施此方法或以其他方式确保永远不必实施它(假设该软件将始终存在错误)?

8
反转IF语句
因此,我已经编程了几年,最近又开始更多地使用ReSharper。ReSharper经常向我建议的一件事是“反转'if'语句以减少嵌套”。 假设我有以下代码: foreach (someObject in someObjectList) { if(someObject != null) { someOtherObject = someObject.SomeProperty; } } ReSharper建议我这样做: foreach (someObject in someObjectList) { if(someObject == null) continue; someOtherObject = someObject.SomeProperty; } 看来,无论进行多少嵌套,ReSharper都会总是建议我反转IF。这个问题是我至少在某些情况下喜欢嵌套。对我来说,似乎更容易阅读和弄清某些地方的情况。并非总是如此,但有时我感到更舒适的嵌套。 我的问题是:除了个人喜好或可读性之外,还有其他减少嵌套的理由吗?是否存在性能差异或其他我可能不知道的东西?

5
从库中的STDIN读取是否被认为是反模式?
在为我正在工作的大型项目编写库时,出现了一个问题,该问题要求将令牌发送到电子邮件地址,然后传递回代码中,以供以后使用。 我的同事说,只是从STDIN中读取(使用Python:)code = input("Enter code: "),然后让用户传递它,但是对我来说,这似乎是一种不好的做法,因为该库可能(在这种情况下肯定会)用在服务器上的后台任务中。 我想知道这是否被视为反模式。

7
将外部数据转换为您正在编程的语言
我不确定该怎么做: 我们从自己工具中的外部工具获取数据。该数据用荷兰语编写。我们正在用英语编写Java代码。然后我们应该将此荷兰语翻译为英语还是保留为荷兰语?例如,我们有两个部门:Bouw(英语建筑)和Onderhoud(英语维护)。 创建逻辑是否合理: public enum Department { BOUW, ONDERHOUD } 要么: public enum Department { CONSTRUCTION, MAINTENANCE } 甚至: public enum Afdeling { BOUW, ONDERHOUD } (在荷兰语中系部门)
39 naming  translate 

3
为什么要使用“函数操作”而不是for循环?
for (Canvas canvas : list) { } NetBeans建议我使用“功能操作”: list.stream().forEach((canvas) -> { }); 但是,这是为什么首选?如果有的话,很难阅读和理解。您正在调用stream(),然后forEach()使用带参数的lambda表达式canvas。我看不出有什么比for第一个片段中的循环更好。 显然,我只是出于美学目的。也许这里缺少我的技术优势。它是什么?为什么我应该改用第二种方法?

13
使用布尔参数确定值是否错误?
根据使用布尔参数确定行为是否错误?,我知道避免使用布尔参数来确定行为的重要性,例如: 原始版本 public void setState(boolean flag){ if(flag){ a(); }else{ b(); } c(); } 新版本: public void setStateTrue(){ a(); c(); } public void setStateFalse(){ b(); c(); } 但是,使用boolean参数来确定值而不是行为的情况如何呢?例如: public void setHint(boolean isHintOn){ this.layer1.visible=isHintOn; this.layer2.visible=!isHintOn; this.layer3.visible=isHintOn; } 我试图消除isHintOn标志并创建2个单独的函数: public void setHintOn(){ this.layer1.visible=true; this.layer2.visible=false; this.layer3.visible=true; } public void setHintOff(){ this.layer1.visible=false; this.layer2.visible=true; this.layer3.visible=false; } …

6
硬编码永远不变的字符串
因此,在我为法语编写一个用于共轭动词的程序(通过算法,而不是通过数据集)的过程中,我遇到了一个小问题。 对于动词的大约17种情况,使动词共轭的算法实际上非常简单,并且针对每种情况在特定模式下运行;因此,这17个类的共轭后缀是静态的,并且(很可能)不会很快改变。例如: // Verbs #1 : (model: "chanter") terminations = { ind_imp: ["ais", "ais", "ait", "ions", "iez", "aient"], ind_pre: ["e", "es", "e", "ons", "ez", "ent"], ind_fut: ["erai", "eras", "era", "erons", "erez", "eront"], participle: ["é", "ant"] }; 这些是法语中最常见的动词类的屈折后缀。 还有其他动词类别(不规则动词),其动词变位也很可能在下一两个世纪保持不变。由于它们是不规则的,因此它们的完整共轭必须静态地包含在内,因为它们不能从某个模式中可靠地进行共轭(据我的统计,也只有32个不规则)。例如: // "être": forms = { ind_imp: ["étais", "étais", "était", "étions", "étiez", "étaient"], …
39 design  strings 

3
为什么Python没有列表的“扁平化”功能?
Erlang和Ruby都具有用于平坦化数组的功能。似乎是一种添加到语言的简单实用的工具。一个可以做到这一点: >>> mess = [[1, [2]], 3, [[[4, 5]], 6]] >>> mess.flatten() [1, 2, 3, 4, 5, 6] 甚至: >>> import itertools >>> mess = [[1, [2]], 3, [[[4, 5]], 6]] >>> list(itertools.flatten(mess)) [1, 2, 3, 4, 5, 6] 取而代之的是,在Python中,必须经历编写从头开始使数组变平的函数的麻烦。对我来说这似乎很愚蠢,将数组展平是一件很平常的事情。这就像必须编写一个自定义函数来连接两个数组。 我已经无能为力地搜索了Google,所以我在这里问。为什么有一个特定的原因,为什么像Python 3这样的成熟语言(附带十万种不同的电池)无法提供简化数组的简单方法?是否曾经讨论过并拒绝包含这种功能的想法?

12
为什么大多数编程语言都具有用于声明函数的特殊关键字或语法?[关闭]
大多数编程语言(动态和静态类型的语言)都具有特殊的关键字和/或语法,这些关键字和/或语法与用于函数声明的变量大不相同。我认为函数就像声明另一个命名实体一样: 例如在Python中: x = 2 y = addOne(x) def addOne(number): return number + 1 为什么不: x = 2 y = addOne(x) addOne = (number) => return number + 1 同样,使用Java之类的语言: int x = 2; int y = addOne(x); int addOne(int x) { return x + 1; } 为什么不: int x …

12
OOP中的文档应避免指定“ getter”是否执行任何计算?
我学校的CS程序避免了任何有关面向对象编程的问题,所以我一直在自己做一些阅读来补充它-特别是Bertrand Meyer的面向对象软件构造。 Meyer反复指出,类应隐藏尽可能多的有关其实现的信息,这是有道理的。特别是,他反复指出,属性(即类的静态,非计算属性)和例程(与函数/过程调用相对应的类的属性)应该是无法区分的。 例如,如果一个类Person具有属性age,他断言,它应该是不可能告诉,从符号,是否Person.age相当于国内喜欢的东西return current_year - self.birth_date或干脆return self.age,其中self.age已被定义为一个常量属性。这对我来说很有意义。但是,他继续声称以下内容: 将设计类的标准客户端文档(称为类的简称),以免透露给定功能是属性还是函数(在可能的情况下)。 即,他声称即使是该类的文档也应避免指定“ getter”是否执行任何计算。 这,我不明白。难道文档不是将这种区别告知用户的重要场所吗?如果我要设计一个包含Person对象的数据库,那么知道是否Person.age是一个昂贵的调用就不重要了,那么我可以决定是否为其实现某种缓存?我是否误解了他的意思,还是他只是OOP设计哲学的一个极端例子?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.