软件工程

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

3
什么时候可以使用并行阵列?
我一直在尝试使用所谓的“并行数组”或列表的代码(新代码)。意味着有2个数组包含相关数据,并通过它们在数组中的位置(索引)进行链接。 我认为这很容易混淆,并且容易出现各种错误。我通常建议的解决方案是创建一个名为CompanyCompanyId和CompanyName 的对象。 一个非常真实的例子: List<string> companyNames; List<int> companyIds; //...They get populated somewhere and we then process for(var i=0; i<companyNames.Count; i++) { UpdateCompanyName(companyIds[i],companyNames[i]); } 这些并行数组是否被认为是不好的做法?

2
为什么要使用具有类型约束的泛型方法而不是类型本身?
在另一个StackExchange问​​题中,我注意到有人在使用此原型: void DoSomething<T>(T arg) where T: SomeSpecificReferenceType { //Code.... } 请记住,只有一个类型约束(SomeSpecificReferenceType),这样写而不是简单地有什么区别和好处? void DoSomething(SomeSpecificReferenceType arg) { //Code.... } 在这两种情况下,arg都将进行编译时类型检查。在这两种情况下,方法的主体都可以安全地依赖arg编译时已知的特定类型的知识(或作为其后代)。 这是开发人员在学习普通继承之前热衷于泛型的一种情况吗?还是有一个合理的理由解释为什么这样写方法签名?
14 c#  .net  generics 

3
大量构建一种实现。DI无望吗?使用服务定位器?
假设我们有1001个客户端,它们直接构造其依赖关系,而不接受注入。根据我们的老板,重构1001不是一个选择。实际上,甚至不允许我们访问其源代码,而只能访问类文件。 我们应该做的是“现代化”这1001个客户所经历的系统。我们可以重构自己喜欢的一切。依赖关系是该系统的一部分。还有一些依赖关系我们应该更改为具有新的实现。 我们想要做的是能够配置依赖关系的不同实现,以满足众多客户的需求。可悲的是,DI似乎不是一个选择,因为客户端不接受构造函数或setter的注入。 选项: 1)重构客户端使用的服务的实现,以使其执行客户端现在需要的功能。砰,我们完成了。不灵活。不复杂。 2)重构实现,以便将其工作委托给它通过工厂获取的另一个依赖项。现在,我们可以通过重构工厂来控制它们都使用哪种实现。 3)重构实现,以便将其工作委托给它通过服务定位器获取的另一个依赖项。现在,我们可以通过配置服务定位器来控制它们都使用哪种实现,该服务定位器可能只是hashmap对象的字符串,并且需要进行一些强制转换。 4)我什至没有想到的东西。 目标: 在不增加毫无意义的复杂性的情况下,将因设计欠佳的旧客户端代码拖到将来而导致的设计损失最小化。 客户不应该了解或控制其依赖项的实现,但是他们坚持使用来构建它们new。我们无法控制,new但可以控制他们正在构建的类。 我的问题: 我没有考虑什么? Doc Brown的问题 您是否真的需要在不同的实现之间进行配置?出于什么目的? 敏捷。很多未知数。管理层希望变革的潜力。只失去对外界的依赖。还测试。 您是否需要运行时机制或只是编译时机制来在不同的实现之间进行切换?为什么? 编译时间机制可能就足够了。除测试外。 您需要在实现之间切换哪种粒度?一次全部?每个模块(每个模块包含一组类)?每堂课? 在1001中,任何一次都只能运行一次。一次更改所有客户端使用的内容可能很好。但是,对依赖项的单独控制可能很重要。 谁需要控制开关?只有您/您的开发人员团队?管理员?每个客户自己吗?还是客户的代码的维护开发人员?那么,机械师需要多么容易/稳健/万无一失? 开发测试。管理员随着外部硬件依赖性的变化而变化。它需要易于测试和配置。 我们的目标是证明该系统可以快速重建和现代化。 实施开关的实际用例? 一种是,在硬件解决方案准备就绪之前,一些数据将由软件提供。

1
如何防止同事引入极端的复杂性和抽象性?
我的工作很困难,因为我的同事似乎在展览 过早/不必要的优化工作 具有可疑抽象的过早重复数据删除 例如,我们使用了经过修改的VIPER体系结构。他实现了路由器组件的基类(使用泛型),作为实现第一个毒蛇堆栈的一部分,而实际上并不知道在其他路由器中将确切复制什么。现在我们不得不提供一种UseCase包含用例的类型,但是大多数路由器没有多个用例,只有一个。 为潜在的未来功能发明通用解决方案 例如,当我们在应用程序中只有两个这样的屏幕时,他写了一个用于填充静态单元格表​​格视图的管理器,他不知道设计将从无聊的垂直形式转变为更多的自定义形式UI,因此管理器无用。 选择偶然的复杂性 当他还表现出英语差的语言障碍时,我该如何应对?

2
现实世界-Liskov替代原理
背景:我正在开发一个消息传递框架。该框架将允许: 通过服务总线发送消息 订阅消息总线上的队列 订阅消息总线上的主题 我们目前正在使用RabbitMQ,但我知道我们将在不久的将来迁移到Microsoft Service Bus(在Premise上)。 我计划创建一组接口和实现,以便当我们转向ServiceBus时,我只需要提供一个新的实现而无需修改任何客户端代码(即发布者或订阅者)。 这里的问题是RabbitMQ和ServiceBus不能直接翻译。例如,RabbitMQ依赖于交换和主题名称,而ServiceBus全部与命名空间和队列有关。同样,在ServiceBus客户端和RabbitMQ客户端之间没有公共接口(例如,两者都可以具有IConnection,但是接口是不同的-不同于公共名称空间)。 因此,就我而言,我可以创建如下界面: public interface IMessageReceiver{ void AddSubscription(ISubscription subscriptionDetails) } 由于这两种技术的不可翻译特性,上述接口的ServiceBus和RabbitMQ实现具有不同的要求。因此,我的IMessageReceiver的RabbitMq实现可能如下所示: public void AddSubscription(ISubscription subscriptionDetails){ if(!subscriptionDetails is RabbitMqSubscriptionDetails){ // I have a problem! } } 对我来说,上面的线打破了李斯科夫的可替代性规则。 我考虑过将其翻转,以便订阅可以接受IMessageConnection,但是RabbitMq订阅再次需要RabbitMQMessageConnection的特定属性。 因此,我的问题是: 我是否认为这会破坏LSP? 我们是否同意在某些情况下这是不可避免的,还是我错过了一些东西? 希望这很清楚,而且是话题!

5
OOP编码风格:初始化构造函数上的所有内容吗?
我仍然认为自己是一个学徒程序员,所以我一直在寻找学习典型编程的“更好”方法。今天,我的同事认为我的编码风格做了一些不必要的工作,我想听听别人的意见。通常,当我使用OOP语言(通常是C ++或Python)设计类时,会将初始化分为两个不同的部分: class MyClass1 { public: Myclass1(type1 arg1, type2 arg2, type3 arg3); initMyClass1(); private: type1 param1; type2 param2; type3 param3; type4 anotherParam1; }; // Only the direct assignments from the input arguments are done in the constructor MyClass1::myClass1(type1 arg1, type2 arg2, type3 arg3) : param1(arg1) , param2(arg2) , param3(arg3) {} …

3
我无法跟踪我的PHP Web应用程序的流程,因此变得越来越难以使用
我已经编程了几年,并且随着时间的流逝对C#和JavaScript变得非常熟悉。我有一些较大的C#和JavaScript项目,可以轻松浏览。我最近开始了一个PHP&AngularJS项目,该项目以前没有使用PHP的经验。 PHP方面的流程变得越来越难以跟踪(JavaScript方面更大,但很容易实现),当我尝试通过它进行思考时,我想象一个纠结的线程。一开始我犯的主要设计错误就开始堆积起来,影响着我的设计。实施任何新技术都将花费越来越长的时间。 我的工作期限很紧,发现编写好的DRY SOLID代码变得越来越困难。随着设计时间的增加,复制/粘贴代码块以使其行为略有变化变得越来越具有吸引力。每当我必须进行上下文切换(从一个项目然后回到这个项目)时,也需要很长时间才能回到代码库,每当我回到该项目上工作时,我都会感到恐惧。 我可以采取什么步骤来解决这个问题?另外,还可能需要花费额外的时间来证明其合理性,因为我的老板不是开发人员,也不熟悉开发或软件的生命周期,因此解释起来可能比平时更为困难。


2
如何在事件源中实施流程管理器
我正在研究一个小示例应用程序,以学习CQRS和事件源的概念。我有一个Basket汇总和一个Product应该独立工作的汇总。 这是一些伪代码来展示实现 Basket { BasketId; OrderLines; Address; } // basket events BasketCreated { BasketId; } ItemAdded { BasketId; ProductId; Quantity } AddItemSucceeded { BasketId; ProductId; Quantity } AddItemRevoked { BasketId; ProductId; Quantity } ItemRemoved { BasketId; ProductId; Quantity } CheckedOut { BasketId; Address } Product { ProductId; Name; Price; } …

2
现在,并不是Java接口中的所有方法声明都是公共抽象的,是否应该使用这些修饰符来声明方法?
从Java 8开始,default方法被引入接口。有效地,这意味着并非in中的所有方法interface都是abstract。 从Java 9(也许)开始,private将允许使用方法。这意味着并非in中的所有方法interface都是public abstract。 问题“在Java接口中的方法是否应使用publicaccess修饰符声明?” 在/programming/161633/should-methods-in-a-java-interface-be-declared-with-or-without-a-public-access-m的堆栈溢出中被询问 那里,大多数答案都认为public abstract不应使用,因为中的任何方法都interface不能是public abstract。这已不再是这种情况。 因此,鉴于接口的这些新功能,是否应该public abstract在Java接口方法声明中使用关键字? 在我的特定环境中,我们将有一些经验丰富的软件工程师,但没有Java经验的人会不时读取Java代码。我觉得,public abstract对于那些不熟悉接口如何具有使用这些关键字的不同规则的历史的人来说,现在将关键字排除在外会造成更多的困惑。

5
如何组织本地化字符串资源?
我们正在开发一个包含许多小程序包的大型应用程序。每个软件包都有自己的一组资源文件以进行本地化。 组织和命名本地化字符串的最佳方法是什么? 到目前为止,这是我的想法: 处理重复项 同一文本(例如“邮政编码”)在给定的程序包中可能多次出现。编程本能(DRY)告诉我创建一个由所有实例共享的单个字符串资源。 再者,翻译者可能希望在某些地方选择长译本(“ Postleitzahl”),在空间较小的地方选择短译本(“ PLZ”)。或者,我们可能决定在某些情况下添加冒号(“邮政编码:”),而在其他情况下则不添加。或者我们可能在某些地方要求使用不同的大写字母(“邮政编码”)。所有这些参数都指向每种用法创建一个资源,即使它们的内容相同。 命名 如果我们希望消除重复,则可以按内容命名资源,也许可以通过前缀提示使用的种类。因此,我们可能有labelOK= “ OK”,messageFileTooLarge= “文件超出了最大文件大小。” 和labelZipCode= “邮政编码”。 按内容命名具有自然处理格式参数的优势:资源messageFileHas_0_MBWhileMaximumIs_1_MB显然采用两个格式参数,即实际文件大小和最大文件大小。 但是,如果我们允许重复,则仅按内容命名是没有意义的。为了获得唯一的资源名称,我们必须以某种方式在资源名称中包括使用位置。这适用于图形控件,尽管标识符往往有点长:fileSelectionConfirmationButtonText= “ OK”,customerDetailsTableColumnZipCode= “邮政编码”。但是,对于非可视代码文件,它会变得更加困难。如果您不知道字符串的最终显示位置,该如何命名字符串的特定用法?通过代码文件和函数名称?对我来说似乎很笨拙。 总而言之,我倾向于允许重复,但是我一直在努力寻找一个支持此目的的一致命名方案。 编辑:这个问题有两个方面:如何组织资源(DRY与重复项)以及如何命名它们。到目前为止,答案集中在第一方面。非常感谢您提供有关命名约定的反馈!

7
如何从客户端应用程序构建用户身份验证?
我一直在开发将支持许多用户的应用程序。问题是我不知道如何验证客户端/用户。 我正在构建一个http://quickblox.com/之类的应用程序,在该应用程序中我将向用户提供凭据,他们将使用这些凭据来构建N个应用程序,在这些应用程序中,他们无法输入用户名和密码来进行身份验证。 让我们假设它如下。(就像QuickBlox一样) 1.用户在我的网站上创建帐户。 2.用户可以创建N个API密钥和保密凭证。(对于多个应用程序) 3.用户将在其应用程序(Android,iOS,Javascript等)中使用这些凭据与我的REST API进行通信。(REST API具有读写访问权限。) 我的顾虑? 用户会将其凭据(API密钥和秘密密钥)放入他们构建的应用程序中,如果有人获得了这些密钥并尝试模仿用户该怎么办?(通过反编译APK或直接查看JavaScript代码。 我在某处错了吗?我对构建这种三级用户机制感到困惑。

2
快速无损压缩视频流
我有一个来自固定相机的视频。分辨率和FPS都很高。我得到的数据为拜耳格式,每个像素使用10位。由于我的平台上没有10位数据类型,因此原始数据使用16位字存储在内存中。我想在通过网络传输数据之前对数据进行某种无损压缩。 摄像头不会移动,因此连续帧的大部分几乎是相同的-但由于不可避免的噪声,仍不能完全消除(降噪不是一种选择,因为降噪是无损的,即使噪声也不应“丢失” )。 由于FPS高,即使变化的部分在任何两个连续的帧之间也变化不大。 但是,看起来相机也有些晃动。在图像空间中,即使很小,但即使静止的物体也并非完全如此。 压缩必须实时进行,因此我不能收集很多帧并将它们全部压缩在一起,但是我可以向后看一帧并将其用作参考。 基于以上所述,我的第一个想法是对数据进行位打包,以使这6个冗余位不会浪费在每个字上。但是,我认为如果使用某种熵编码(例如Huffman等),则会自动考虑冗余,因此不需要额外的包装。所以我做了以下工作: 取得两个连续帧之间的二进制差异。原始数据范围为0〜1023(例如,无符号10位)。差异数据变为有符号,范围增加到-1023〜1023,但数据变化(或正确的数学术语)变得比原始数据少得多,实际上,大多数值不足为零就不足为奇了。 将Rice编码应用于差异。据我了解,对于大多数数值较小的数据集,这似乎是一个不错的选择。 对于1280x720帧,这使我的尺寸减少了60%,并且我的测试系统(单核上的VirtualBox中的Linux)每秒可以进行约40次此类压缩(无需太多优化)。我猜不是那么好,但是很合理(或者是吗?)。 有更好的方法吗?我有任何常见的错误吗?我错过了任何常规步骤吗?以后可能会使用更高分辨率的帧-对于更大的帧大小,我应该期望更好的压缩率吗? UPD: 我使用此库进行Rice编码。该库非常慢(作者本人将其描述为学习而不是实际使用),例如,它在循环中一对一地读写位,这会降低性能。最初它只给我约20 FPS,经过一些非常基本的优化后,它变成了40 FPS(如上所述),后来我对其进行了更多优化,变成了80 FPS。这是在没有向量化的单个i7内核上。 至于向量化,不幸的是,我无法想到一种对Rice代码进行向量化的方法(甚至根本不知道它是否可能-在Rice代码上找不到任何数据,我对霍夫曼代码的发现表明:它是顺序的,无法有效地向量化,这可能适用于Rice代码以及其他可变长度代码)。 我还尝试了一种完全不同的方法:将数据分成小块(例如,每个像素为64像素)并使用简单的零抑制。我们找到一个块中最大的数字,将表示它所需的位数写到该块的开头(在我的情况下,这需要再增加4位),然后将该块中的所有数字减少到相同的位数。位。我预计压缩率会很差,但是如果片段很小,那么它们中的许多都不会产生噪声尖峰,因此它们的二进制差异可以减小到每个值4〜6位,实际上只有比Rice代码差5%左右,但速度大约是Rice代码的两倍(例如我的情况下为160 FPS)。我曾尝试对其进行矢量化处理,但对矢量化处理还是有点不满,所以也许正因为如此,我只能实现约1.8倍的进一步加速。 由于负数没有前导零,因此我在二进制差之后和莱斯/零抑制之前应用了之字形编码。

1
Free monad和Reactive Extensions如何关联?
我来自C#背景,其中LINQ演变为Rx.NET,但始终对FP感兴趣。在对Monad和F#中的一些辅助项目进行了一些介绍之后,我准备尝试进入下一个级别。 现在,经过来自Scala的人们关于免费monad的几次讨论,以及在Haskell或F#中的多次写作之后,我发现带有用于理解的口译员的语法与IObservable锁链非常相似。 在FRP中,您将根据较小的领域特定块(包括链中的副作用和失败)组成操作定义,并将应用程序建模为一组操作和副作用。在免费monad中,如果我理解正确,您可以通过将操作设为函子,然后使用coyoneda来进行操作。 将针头朝任何一种方法倾斜的两者之间有什么区别?定义服务或程序时的根本区别是什么?

3
支持旧操作系统的开发
我维护着大部分用C编写的遗留代码。此代码最初被编写为针对Windows 3 for Workgroups进行编译,后来创建了NT版本。这个旧版应用程序至今仍在使用,自90年代初开始在3.11和NT工作站上愉快地运行。它可以正常工作,并且可以完成预期的工作,而它们仍然存在的原因是,属于该解决方案的某些自定义硬件的驱动程序与以后的Windows不兼容。 我维护了另一个应用程序,出于相同的原因,该应用程序仅在Win2k上有效。 但是,随着事情的发展,运行这些旧环境变得越来越困难。现在,我保留安装了开发软件的物理机,因此可以在本机硬件上工作。但是这些可能会随时死亡(毕竟他们已经25岁了)。 所以我的问题是,从2016年开始,我有什么选择可以更稳定地维护这一古老环境?您可以将3.11迁移到云托管吗? 我尝试了虚拟化,但是由于设置的特殊性,我无法使其与设备驱动程序一起使用,因此我认为可能需要按原样制作完整的操作系统映像,然后在一个操作系统中运行该映像。 VM开发软件?这样的事情可能对来宾操作系统版本一样古老WIN3和NT? 是否有任何经验可以使类似的旧平台存活下来进行开发,但是我可以借鉴更现代,更安全的方式? 我的目标是摆脱旧的物理机,然后转向虚拟化。
14 c  windows  legacy 

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.