软件工程

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

4
SIMD编程代码库的维护成本
题: 软件行业的共识是,干净,简单的代码对于代码库和拥有它的组织的长期生存至关重要。这些属性导致较低的维护成本,并增加了继续使用代码库的可能性。 但是,SIMD代码与通用应用程序代码不同,我想知道是否有专门针对SIMD代码的简洁代码的相似共识。 我的问题的背景。 我为各种图像处理和分析任务编写了大量的SIMD(单指令,多个数据)代码。最近,我还不得不将少量这些功能从一种体系结构(SSE2)移植到另一种体系结构(ARM NEON)。 该代码是为收缩包装的软件编写的,因此,如果没有不受限制的重新分配权限(例如MATLAB),就不能依赖专有语言。 典型代码结构的示例: 使用OpenCV的矩阵类型(Mat)进行所有内存,缓冲区和生命周期管理。 检查输入参数的大小(尺寸)后,将获得指向每行像素起始地址的指针。 像素计数和来自每个输入矩阵的每一行像素的起始地址都传递给一些低级C ++函数。 这些低级C ++函数使用SIMD内部函数(用于Intel Architecture和ARM NEON),从原始指针地址加载并保存到原始指针地址。 这些低级C ++函数的特征: 唯一一维的(在内存中连续) 不处理内存分配。(每个分配,包括临时性,都由外部代码使用OpenCV工具处理。) 符号的名称长度(内部名称,变量名称等)的范围大约为10-20个字符,这是非常大的。(读起来就像是技术泡沫)。 不鼓励重复使用SIMD变量,因为编译器在正确地解析不是以“单分配”编码方式编写的代码方面存在很多缺陷。(我已经提交了几个编译器错误报告。) SIMD编程的哪些方面会使讨论与一般情况有所不同?或者,为什么SIMD与众不同? 初期开发费用 众所周知,与随便编写的 C ++代码相比,具有良好性能的C ++ SIMD代码的初始开发成本约为10倍至100倍(具有较大的余量)。 正如在性能与可读/清洁代码之间进行选择的答案中所指出的那样?,大多数代码(包括随便编写的代码和SIMD代码)起初既不干净也不快速。 不鼓励对代码性能(在标量代码和SIMD代码中)进行进化改进(因为这被视为一种软件返工),并且没有跟踪成本和收益。 就倾向而言 (例如帕累托原则,又称80-20规则) 即使图像处理仅占软件系统的20%(在代码大小和功能上),图像处理也相对较慢(当以所花费的CPU时间的百分比表示),花费的时间超过80%。 这是由于数据大小的影响:典型的图像大小以兆字节为单位,而非图像数据的典型大小以千字节为单位。 在图像处理代码中,SIMD程序员受过训练,可以通过识别C ++代码中的循环结构来自动识别包含热点的20%代码。因此,从SIMD程序员的角度来看,“重要的代码” 100%是性能瓶颈。 通常在图像处理系统中,存在多个热点,并占用相当比例的时间。例如,可能有5个热点分别占总时间(20%,18%,16%,14%,12%)。为了获得高性能,需要在SIMD中重写所有热点。 这被概括为气球弹出规则:气球不能两次弹出。 假设有一些气球,说5个。抽取它们的唯一方法是将它们逐个弹出。 弹出第一个气球后,剩下的4个气球现在占总执行时间的更高百分比。 为了获得更大的收益,然后必须弹出另一个气球。(这违背了80-20的优化规则:采摘了悬挂率最低的20%的水果后,可以获得良好的经济效果。) 在可读性和维护方面 SIMD代码显然难以阅读。 即使遵循每一项软件工程最佳实践,也是如此,例如命名,封装,const正确性(并使副作用显而易见),函数分解等。 即使对于有经验的SIMD程序员也是如此。 与等效的C ++原型代码相比,最佳SIMD代码非常扭曲(请参阅备注)。 扭曲SIMD代码的方法有很多,但是10种这样的尝试中只有1种会获得可接受的快速结果。 …

10
从同一类构造的对象可以具有唯一的方法定义吗?
我知道这似乎是一个奇怪的问题,因为两个或更多共享同一类的对象的要点是它们的行为是相同的,即它们的方法是相同的。 但是,我很好奇是否有任何OOP语言可以让您以可以为对象的字段分配不同值的相同方式重新定义对象的方法。结果将是从同一类构造的对象不再表现出完全相同的行为。 如果我没记错的话,您可以使用此JavaScript吗?我问这个问题,为什么有人要这样做呢?

4
正确的Model-View -_____设计
我一直在阅读有关Model View Controller,Model View Presenter,Model View ViewModel等的内容,通常,基本概念似乎很容易理解:将漂亮的视觉效果和科学胆量保持彼此独立和无知,例如可能。设计巧克力中没有添加逻辑花生酱;酷,我喜欢。 问题是我对于第三部分还是有点模糊,不是模型或视图。每个人似乎都有自己的主意,如何称呼它,应该做什么,什么是正确的,什么是明显的错误……而且我很想弄清楚什么时候Presenter成为ViewModel,什么时候应该让View成为现实。不要这样做,因为那是主持人的工作,并且- 我在乱逛 而不是请别人解释它们之间的区别-因为已经一次又一次地做到了(我知道;我读了不计其数的文章)-我很好奇听到我自己拼凑的模型很少有程序员。 就是说,您会将此设计归类为什么?也许更重要的是,您是否对此有明显的印象?当然,如果这确实是可靠的设计,我很想听到我做的很好,但是我宁愿得到可靠的建议而不是赞美。 注意:我将使用“桥梁”作为Model-View-?的神秘第三部分。避免对其“应该”有任何潜意识的建议。 模型 是对数据的授权。 从网桥接收有关请求的更改的信息。 包含并执行关于数据如何与其他数据相关的所有逻辑。 数据更改时通知网桥(对于网桥表示感兴趣的数据)。文字编辑:允许外部订户(对其一无所知)监视其状态或计算结果。 对视图的知识为零。 视图 与为用户提供查看和操纵数据的方式有关。 从网桥接收有关数据更新的信息。 包含并执行有关如何向用户呈现数据和控件的所有逻辑。 当用户执行了(可能)影响模型的操作时,通知Bridge。 通知Bridge感兴趣的信息。 对模型的知识为零。 桥 是模型和视图之间的协调者和翻译者。 对在模型和视图之间传递的信息进行适当的格式更改。 保留有关“谁需要知道什么”的信息。 具有模型和视图的知识。 补充说明 在更复杂的程序中,通常会有多个模型。在这种情况下,网桥通常承担在多个模型之间进行协调/转换的工作,因此成为应将原型/ API /设计模型构建到哪个模型的权限。(例如,如果构建纸牌游戏程序,并且您要构建备用的甲板改组模型,则应使用Bridge来确定与Bridge正确通信所需的功能。) 在只有一个视图和模型的小型简单程序中,网桥通常会“假定”任一侧都有哪些功能。但是,随着程序变得越来越复杂,建议视图和模型向Bridge报告其功能,这样可以避免效率低下和错误的假设。 我认为这几乎涵盖了它。无论如何,我欢迎您对我倾向于使用的设计有任何疑问,并且我也鼓励您提出任何建议。 和往常一样,感谢您的宝贵时间。

4
允许使用显式接口实现在C#中隐藏成员吗?
我知道如何在C#中使用接口和显式接口实现,但是我想知道隐藏某些不经常使用的成员是否被认为是不好的形式。例如: public interface IMyInterface { int SomeValue { get; set; } int AnotherValue { get; set; } bool SomeFlag { get; set; } event EventHandler SomeValueChanged; event EventHandler AnotherValueChanged; event EventHandler SomeFlagChanged; } 我事先知道这些事件虽然有用,但很少使用。因此,我认为通过显式实现将它们隐藏在实现类之外以避免IntelliSense混乱是有意义的。

3
创建对象时,是将新的内存分配给实例字段和方法,还是仅分配给实例字段
我有一个下课 class Student{ int rollNumber; int marks; public void setResult(int rollNumber, int marks){ this.rollNumber=rollNumber; this.marks=marks; } public void displayResult(){ System.out.println("Roll Number= "+this.rollNumber+" Marks= "+this.marks); } } 现在,我创建两个类型为Student的对象,如下所示 Student s1=new Student(); Student s2=new Student(); 现在,为实例字段分配了两组不同的内存。现在我的问题是为方法(setResult和displayResult)分配内存两次还是一次? 请参见下图,您能帮我说一下哪个图提供了正确的信息。


4
微服务和数据复制
我正在构建一个新的应用程序,并且正在阅读有关微服务架构的信息。从开发,部署和生命周期管理的角度来看,体系结构本身很有意义。但是出现的一个问题是关于如何处理主数据。 例如,我有2个应用程序-例如销售应用程序和票务应用程序。假设这两个应用都是作为自己的微服务构建的。但是,这两个应用程序在部署时(假设分别部署,例如Sales使用MongoDB,Ticketing使用MariaDB),则需要访问相同的主数据实例,例如Accounts,Products。这意味着将有一个给定主数据实体的所有者应用程序(例如,对于帐户,可能是销售应用程序)和一个有兴趣的一方(例如,票务应用程序将需要有关帐户的信息)。 有多种方法可以实现:-从主方到感兴趣方的数据复制-从感兴趣方到主方的同步读取(微服务体系结构范例不建议同步依赖性)-自己的集中式存储库 即使在客户中,也可能有一个核心部分,对于销售和票务都是通用的(例如,帐户名,地址等)。但是,帐户的某些方面可能仅与销售相关,而其他方面仅与票务相关。 关于上述任何选项有什么想法/最佳实践/意见吗?
14 soa  services 

2
为什么C#比Java具有更多的功能?[关闭]
已关闭。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗?更新问题,以便通过编辑此帖子以事实和引用的形式回答。 5年前关闭。 请注意,这并不意味着是Java vs. C#参数。我是一位没有C#经验的Java程序员,出于好奇而问。 我在C#上做了一些阅读,似乎它比Java具有更多的功能。一些例子: 类型推断。 dynamic 关键词。 代表们 可选参数。 Lambda和LINQ (我实际上不知道它们是什么)。 属性。 但是,Java实际上没有C#所没有的任何功能。 我的问题是:为什么C#比Java具有更多的本机功能?为何Java多年来一直没有添加其中的某些内容,例如Properties或type Inference?Java语言设计人员是否采用更简单的方法?这是什么原因呢?
14 java  c#  languages 

4
从长远来看,需求管理在敏捷项目中如何工作?
在短期内,敏捷项目的需求管理对我来说似乎是一个已解决的问题。 从Scrum角度,新需求或对现有需求的更改是通过用户故事交付的。并且,按Epic或Feature分组的User Stories有助于交付更大,更复杂的需求。 当然,从技术上讲,用户故事不是要求文档。这是一个可管理的工作分组,映射到通常称为功能的垂直切片的内容。这些故事的范围可以通过使用接受标准(AC)来明确定义。 因此,尽管用户故事不是正式的要求,但浏览它们可以使您对他们的基本要求有一个清晰的认识。在短期内。 我之所以说是短期的,是因为随着项目的进展,用户故事的数量会增加。因此,随着时间的流逝,浏览不断增加的故事列表以找到需求的效率越来越低。 当您考虑扩展,取代甚至否定先前故事的用户故事时,此问题会更加复杂。 现在,假设一个项目的开发迭代(生产稳定)之间存在2年的差距。最初的团队消失了,他们所有的知识也消失了。 如果原始团队知道这将要发生(例如,这是企业的性质),那么他们可以采取哪些措施来帮助后续团队? 当然,待办事项将提供一些信息,但是它几乎不容易浏览。 那么,可以做些什么来帮助后续团队了解项目的状态,包括为什么以及如何到达那里? 以我的经验,以下几项无效: 积压整理以删除或更新以前的用户故事,以便可以将积压阅读为需求文档。 文档冲刺团队成员的任务是记录系统的当前状态。 通过行为测试的文件。这种方法是我所见过的唯一接近可行的方法。不幸的是,编码行为测试是命名问题的受害者。尽管这些测试可能正确记录了该系统,但要使变动的开发人员团队按照相同的Domain术语,措辞和样式编写测试几乎是不可能的。 因此,重申一下: 长期如何管理敏捷项目需求?

3
GPL许可使用什么许可?
实际的GPL许可(即包含“设计大多数软件和其他实际作品的许可...”字样的文本)是文档;因此,我认为它受某种版权保护吗? 该许可使用什么许可? 也就是说,如果我要在自己的项目中包括GPL许可证的正文(并可能创建衍生作品),我受到什么限制?
14 gpl  copyright 

3
在实践中如何遵守开闭原则
我了解开放原则的意图。这是通过告诉您尝试在不进行修改的情况下进行扩展,以降低破坏已在修改过程中起作用的内容的风险。 但是,我在理解此原理在实践中的应用时遇到了一些麻烦。据我了解,有两种方法可以应用它。在可能的更改之前和之后: 之前:编程抽象并尽可能“预测未来”。例如,drive(Car car)如果将来将Motorcycles添加到系统中,则必须更改 方法,因此它可能违反了OCP。但是该方法drive(MotorVehicle vehicle)将来不太可能需要更改,因此它遵循OCP。 但是,很难预测未来并提前知道将对系统进行哪些更改。 之后:需要更改时,扩展类而不是修改其当前代码。 练习1并不难理解。但是,在实践2中,我很难理解如何申请。 例如(我从YouTube视频中获取了它):假设我们在类中有一个接受CreditCard对象的方法:makePayment(CraditCard card)。将一天Voucher添加到系统中。此方法不支持它们,因此必须对其进行修改。 首先实现该方法时,我们无法预测未来,无法以更抽象的术语进行编程(例如makePayment(Payment pay),因此现在我们必须更改现有代码。 练习2说,我们应该通过扩展而不是修改来添加功能。这意味着什么?我应该继承现有的类而不是简单地更改现有的代码吗?我是否应该围绕它进行某种包装,以避免重写代码? 还是该原则甚至不涉及“如何正确修改/添加功能”,而是涉及“如何避免必须首先进行更改(即从程序到抽象)”?

8
编码前的概念和设计:这是多少?[关闭]
已关闭。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗?更新问题,以便通过编辑此帖子以事实和引用的形式回答。 5年前关闭。 我在学校和其他地方都学到,良好的开发方法在正确编码之前需要概念和设计。 即使对于初学者,这也不是一个新信息。但是,我想知道这是否是一个好的建议,因为自从我开始使用多种编程语言进行开发以来,自从开始以来就从未成功设计和构思过所有东西。 我的意思是,我总是融合设计,概念和编程。我是世界上最糟糕的开发人员,还是我们在学校学到的想法只是一种古老而毫无意义的宗教教条? 我们如何甚至可以构思和设计以前从未经历和编程的东西?是不是很荒谬?编程不是主导概念和设计吗?

6
嵌套try-catches的替代方案,用于后备
我遇到试图检索对象的情况。如果查找失败,则我有多个后备,每一个都可能失败。因此,代码如下所示: try { return repository.getElement(x); } catch (NotFoundException e) { try { return repository.getSimilarElement(x); } catch (NotFoundException e1) { try { return repository.getParentElement(x); } catch (NotFoundException e2) { //can't recover throw new IllegalArgumentException(e); } } } 这看起来很难看。我讨厌返回null,但是在这种情况下会更好吗? Element e = return repository.getElement(x); if (e == null) { e = repository.getSimilarElement(x); …

1
使默认构造函数不可用就可以了吗?
具体询问默认构造函数 考虑到构造函数会初始化一个对象的所有数据,如果我创建了一个未经适当初始化就无法使用的类,那么默认构造函数是否就没有用?考虑: // A class for handling lines in a CSV file class CSV_Entry { private: unsigned num_entries; std::string string_version; std::vector<std::string> vector_version; ...etc public: CSV_Entry(); CSV_Entry(const std::string& src_line); // returns a vector copy of the original entry std::vector<std::string> get_vector_snapshot(); } int main( void ) { ...etc CSV_Entry example = CSV_Entry(); …


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.