软件工程

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

1
为什么某些语言的文档说“等于”而不是“是”?
为什么某些语言的文档说“等于”而不是“是”? 例如,Python文档说 itertools.chain(*iterables) ... 等效于: def chain(*iterables): # chain('ABC', 'DEF') --> A B C D E F for it in iterables: for element in it: yield element 或者,这个C ++参考的find_if: 该功能模板的行为等效于: template<class InputIterator, class UnaryPredicate> InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred) { while (first!=last) { if (pred(*first)) return first; …

5
为什么构建工具使用的脚本语言不同于基础编程语言?
当我意识到大多数语言的主要构建工具/系统使用的语言与基础编程语言本身所使用的语言不同时,我最近一直在为Nodejs项目使用一些构建工具。 例如,make不使用C或C ++编写脚本,而ant(也不是Maven)不使用Java作为脚本语言。 诸如Ruby之类的较新语言的确将相同的语言用于诸如rake之类的构建工具,这对我来说很有意义。但是,为什么情况并非总是如此?拥有使用与基础语言不同的语言的构建工具的优势是什么?

3
我应该避免在C#中使用unsigned int吗?
我最近想到了在C#中使用无符号整数(并且我猜可以对其他“高级语言”说类似的论点) 当需要整数时,我通常不会遇到整数大小的难题,例如Person类的age属性(但问题不限于属性)。考虑到这一点,据我所知,使用无符号整数(“ uint”)优于有符号整数(“ int”)的唯一优势-可读性。如果我想表达年龄只能为正数的想法,可以通过将年龄类型设置为uint来实现。 另一方面,对无符号整数的计算可能会导致各种错误,并且使其难以执行诸如减去两个年龄的运算。(我读到这是Java省略无符号整数的原因之一) 在C#的情况下,我还可以认为setter上的保护子句可以提供两个世界中最好的解决方案,但是,例如当我将年龄传递给某种方法时,这将不适用。一种解决方法是定义一个名为Age的类,并将属性age作为唯一的对象,但是这种模式将让Me创建许多类,并且会造成混乱(其他开发人员将不知道什么时候对象只是包装器)以及更复杂的内容)。 关于此问题的一些最佳常规做法是什么?我应该如何处理这种情况?

2
什么时候在Groovy中使用def?
我现在在Groovy中开发了一段时间,我想知道应该多久使用一次动态投射def?我的一位同事认为我们应该一直使用它,因为它以某种我不了解的方式对Groovy有所帮助。 当前,当声明方法的返回类型和参数时,我想刻意指出应该放入和吐出哪些对象(出于代码可读性,我来自Java背景对我来说很有意义)示例: String doSomething(String something){ //code } // vs def doSomething(def somthing){ //code } // vs def doSomething(somthing){ // code } 所以我想我的问题是,仅是何时使用的偏好,def还是一直使用它的真正优势?(我添加了最后一个示例,因为我认为它适合作为Groovy的可行选项的问题)


2
将循环(while / for)转换为递归或从递归转换为循环的一般方法?
这个问题主要集中在算法上,也许是抽象的并且更学术化。 这个例子提供了一个想法,我想用一种通用的方式,所以例子仅用于使我们更清楚地了解您的想法。 一般来说,循环可以转换为递归的。 例如: for(int i=1;i<=100;++i){sum+=i;} 其相关的递归为: int GetTotal(int number) { if (number==1) return 1; //The end number return number+GetTotal(number-1); //The inner recursive } 最后,为了简化此过程,需要执行尾递归: int GetTotal (int number, int sum) { if(number==1) return sum; return GetTotal(number-1,sum+number); } 但是,大多数情况下都不容易回答和分析。我想知道的是: 1)我们能否获得一种“通用方式”将循环(for / while……)转换为递归?在进行转换时,我们应该注意哪些事情?最好写一些示例的详细信息以及您的persudo理论以及转换过程。 2)“递归”具有两种形式:线性递归和尾递归。那么哪个转换更好呢?我们应该掌握什么“规则”? 3)有时我们需要保留递归的“历史”,这很容易在循环语句中完成: 例如: List<string> history = new List<string>(); …

5
转到git时,如何处理大型svn历史记录?
编辑:与某些类似的问题不同,例如将多GB SVN存储库移至Git 或 /programming/540535/managing-large-binary-files-with-git 我的方案不涉及几个子项目可以很容易地转换为git子模块,也不能转换为一些非常适合git-annex的非常大的二进制文件。它是一个单一的存储库,其中的二进制文件是测试套件,与相同修订版的主要源代码紧密耦合,就像它们是编译时资产(例如图形)一样。 我正在研究从svn切换旧的中型/大型(50个用户,60k修订,80Gb历史记录,2Gb工作副本)代码存储库。随着用户数量的增加,主干中流失很多,并且功能通常分散在多个提交上,这使得代码审查变得困难。同样,如果没有分支,就无法“排除”不良代码,只有在提交到主干后才能进行检查。我正在研究替代方案。我希望我们可以转到git,但遇到一些问题。 就git而言,当前仓库的问题是大小。那里有很多旧文件,转换为git时用--filter-branch清理它可以将文件大小减小一个数量级,大约为5-10GB。这仍然太大。大型存储库的最大原因是,有很多二进制文档正在输入到测试中。这些文件的大小在.5mb到30mb之间,有数百个。他们也有很多变化。我看过子模块,git-annex等,但是在子模块中进行测试感觉很不对劲,对许多想要完整历史记录的文件都有附件也是如此。 因此,git的分布式特性实际上是阻止我采用它的原因。我并不真正在乎分布式,我只想要便宜的分支和强大的合并功能。就像我假设99.9%的git用户那样,我们将使用一个有福的,裸露的中央存储库。 我不确定我是否理解为什么每个用户在使用git时都要拥有完整的本地历史记录?如果工作流不是分散的,那么该数据在用户磁盘上做什么?我知道在git的最新版本中,您可以使用仅具有最新历史记录的浅表克隆。我的问题是:将其作为整个团队的标准运作模式是否可行?可以将git配置为始终很浅,以便您只能在中央拥有完整的历史记录,但是默认情况下,用户只有1000转的历史记录?当然,可以选择仅将1000 revs转换为git,并保留svn repo用于考古。但是,在这种情况下,在对测试文档进行了数千次修订之后,我们将再次遇到相同的问题。 什么是使用Git含有许多二进制文件,你大回购了良好的最佳实践也希望历史?大多数最佳实践和教程似乎都避免了这种情况。他们解决了几个巨大的二进制文件的问题,或建议完全删除二进制文件。 浅克隆是否可作为正常操作模式使用?还是“骇客”? 子模块是否可以用于在主源版本和子模块版本之间具有严格依赖性的代码(例如,在编译时二进制依赖性或单元测试套件中)? git存储库(在内部)的“太大”是多少?如果可以将其降低到4GB,我们应该避免切换吗?2GB?
23 git  svn 

2
命名约定:最终字段(非静态)
今天,我与一位同事讨论了finalJava类中字段的命名。 在他的观点中,final字段也应视为常量,因为其值在创建实例后不会更改。 这将导致以下final字段命名约定: public class Foo { private static final String BLA_BLA = "bla"; private final String BAR_BATZ; ... } 在我看来,只有static final字段应被视为常量,而仅字段应final遵循通常的camelCase命名约定。 public class Foo { private static final String BLA = "bla"; private final String barBatz; ... } 现在我有点不确定,因为他是比我经验丰富的程序员,我通常同意他的观点,并认为他是一个非常好的开发人员。 有什么意见吗?
23 java  naming  final 

2
将现有项目添加到REST API中的集合的最佳模式是什么?
我正在设计一个实用的REST API,并且对如何最好地将现有实体添加到集合中有些困惑。我的域模型包括一个具有站点集合的项目。这是一个严格的多对多关系,我无需创建一个显式建模该关系的实体(即ProjectSite)。 我的API将允许使用者将现有站点添加到项目中。我挂断电话的地方是,我真正需要的唯一数据是ProjectId和SiteId。我最初的想法是: 1. POST myapi/projects/{projectId}/sites/{siteId} 但是我也想过 2. POST myapi/projects/{projectId}/sites 与作为JSON内容发送的Site实体。 选项1简单易用,但感觉不太正确,而且我还有其他关系无法遵循此模式,因此它增加了我的API的不一致性。 选项2感觉更好,但引起两个问题: 如果发布了新网站(SiteId = 0),我应该创建一个网站还是引发异常? 因为我只需要ProjectId和SiteId来创建关系,所以该站点可能发布的其他属性数据有误或缺失。 第三种选择是提供一个仅用于创建和删除关系的简单端点。该端点将期望仅包含ProjectId和SiteId的JSON有效负载。 你怎么看?
23 rest  api-design 

5
另一种流行的语言如何在管理与Java / Java EE类似的复杂性时避免使用工厂模式?
工厂模式(或至少使用FactoryFactory..)是许多笑话的对接,例如此处。 除了具有冗长和“创造性”的名称(如RequestProcessorFactoryFactory.RequestProcessorFactory)之外,如果您必须使用Java / C ++进行编程并且有Abstract_factory_pattern的用例,那么工厂模式是否有根本上的错误? 另一种流行的语言(例如Ruby或Scala)如何在管理相似的复杂性时避免使用它呢? 我要问的原因是,在Java / Java EE生态系统的背景下,我看到的大多数批评都是工厂,但它们从未解释其他语言/框架如何解决它们。

7
在C和C ++中使用无符号整数
我有一个很简单的问题,困扰了我很长时间。我正在处理网络和数据库,因此要处理的许多数据是32位和64位计数器(无符号),32位和64位标识ID(也没有用于符号的有意义的映射)。我几乎从不处理任何可以表示为负数的实际单词问题。 我和我的同事经常使用无符号的类型,如uint32_t和uint64_t对这些问题,并因为它发生如此频繁,我们也将它们用于数组索引和其他常见的整数用途。 同时,我正在阅读的各种编码指南(例如Google)都不鼓励使用无符号整数类型,据我所知,Java和Scala都没有无符号整数类型。 因此,我想不出正确的做法:在我们的环境中使用带符号的值将非常不便,同时编码指南要求严格执行此操作。
23 c  coding-style 

3
为什么复制指令通常命名为MOV?
在许多汇编器中,值复制指令通常称为“ MOV”,其说明中通常也包含“ move”(但是,可以使用其他词,如“ load”,“ store”,“ extract”等。 )找到不遵循此约定的ISA并不常见。 另一方面,在其他情况下,“ move”与“ copy”在破坏源的意义上有所不同(例如,Unix中的“ mv”与“ cp”,Norton Commander中的 Move [F6] 和克隆等)。 )汇编程序的“移动”确实具有语义上的“复制”,从而保持了源值的完整性。 我发现这至少是从IBM 1401(1959)开始的,但是IBM 360仅将此词用于存储内复制,而不用于寄存器和存储(使用“ load”和“ store”)之间的操作。 。但是,为什么它仍然被广泛使用,而不是被“复制”或“存储”取代?
23 history  assembly 

5
什么时候应该增加版本号?
我不是在学校学习编程的,也不以(专业)开发人员的身份工作,因此很多基本知识对我来说还不太清楚。这个问题试图澄清其中之一。 现在,假设我有问题#1,#2并且#3在我的“问题跟踪器”中已设置要针对版本进行更正/增强,1.0.0并且最后一个(稳定)版本是0.9.0。 我1.0.0什么时候应该增加版本?当a)仅关闭了上面列出的问题之一,或b)当与版本相关的所有问题1.0都结束了? 哪一种是正确的方法?通过正确的方式,我指的是当前行业中使用的东西。

5
纯功能语言如何处理模块化?
我来自于面向对象的背景知识,在该背景知识中我了解到,类已经或至少可以用于构成一层抽象,以便于代码的轻松回收,然后可以将其用于创建对象或用于继承。 例如,我可以拥有一个动物类别,然后从中继承猫和狗,使它们都继承许多相同的特征,然后从那些子类别中,我可以创建可以指定动物品种甚至名称的对象它的。 或者,我可以使用类来指定同一代码的多个实例,这些实例处理或包含略有不同的事物。例如搜索树中的节点或多个不同的数据库连接,而没有。 我最近进入函数式编程领域,因此我开始怀疑: 纯函数式语言如何处理此类问题?也就是说,语言没有任何类和对象的概念。

5
重新格式化和版本控制
代码格式很重要。甚至缩进也很重要。一致性比微小的改进更为重要。但是,项目通常从第一天起就没有清晰,完整,可验证和强制的样式指南,并且重大改进可能会在任何一天出现。也许你发现 SELECT id, name, address FROM persons JOIN addresses ON persons.id = addresses.person_id; 可以更好地写成/比 SELECT persons.id, persons.name, addresses.address FROM persons JOIN addresses ON persons.id = addresses.person_id; 同时在查询中添加更多列。也许这是代码中所有四个查询中最复杂的查询,或者成千上万个简单查询。无论过渡有多困难,您都认为值得。但是,如何跟踪主要格式更改中的代码更改?您可以放弃并说“这是我们再次开始的地方”,也可以重新格式化整个存储库历史记录中的所有查询。 如果您正在使用像Git这样的分布式版本控制系统,则可以还原到有史以来的第一次提交,然后从那里重新格式化为当前状态。但这是一项艰巨的工作,其他所有人都必须在工作进行期间暂停工作(或为所有合并的母亲做好准备)。有没有更好的方法可以更改历史记录,从而获得最好的结果: 所有提交中的样式相同 最少的合并工作 ? 需要澄清的是,这与启动项目时的最佳实践无关,而是在大型重构被视为Good Thing™却又想获得可追溯的历史时应该怎么做?如果这是确保您的版本始终保持相同工作的唯一方法,则永远不要重写历史记录,这是伟大的,但是对于开发人员而言,全新重写的好处是什么?特别是如果您有方法(测试,语法定义或编译后的相同二进制文件)可以确保重写后的版本与原始版本完全一样?

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.