软件工程

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

4
C ++处理大型模板实现的首选方法
通常,在声明C ++类时,最佳实践是仅将声明放入头文件中,并将实现放入源文件中。但是,这种设计模型似乎不适用于模板类。 在网上查找时,对于管理模板类的最佳方法似乎有两种意见: 1.标头中的整个声明和实现。 这相当简单,但是我认为,当模板变大时,很难维护和编辑代码文件。 2.将实现写入末尾包含的模板包含文件(.tpp)中。 对我来说,这似乎是一个更好的解决方案,但似乎并未得到广泛应用。是否存在这种方法不及格的原因? 我知道很多时候,代码风格是由个人喜好或传统风格决定的。我正在开始一个新项目(将旧的C项目移植到C ++),并且我对OO设计比较陌生,并且希望从一开始就遵循最佳实践。

4
对某些用户隐藏/禁用功能
可以说我有该应用程序的免费和付费版本。付费版本是免费版本在用户可用功能方面的超集,这意味着付费版本将具有免费应用程序的所有功能以及其他功能。 是否存在根据启动时加载的标志(例如,免费/付费)来切换功能可用性的模式? 我不喜欢到处都有以下代码块的想法: if(isFreeVersion){ // ... } else { // ... } 每个版本都没有2个单独的git分支是不可行的,因为这意味着要维护2个(或更多)代码源,这在一般情况下似乎不切实际,并在此处进行了更多讨论:在Version Control中从同一代码库维护两个单独的软件版本。 有办法做到这一点,同时仍然只有一个代码库,并且不会用检查自由/已付费标志的条件语句来乱扔代码吗? 我敢肯定这已经被讨论过很多次了,并且我肯定有一些解决这个问题的模式,但是我只是找不到它。 我们使用Android / Java。

2
函数式编程语言是否会带来副作用?
根据Wikipedia 所说,声明性的函数式编程语言禁止副作用。通常,声明式编程会尝试最小化或消除副作用。 同样,根据维基百科,副作用与状态变化有关。因此,从某种意义上说,函数式编程语言实际上消除了副作用,因为它们不保存任何状态。 但是,此外,副作用还有另一个定义。副作用 除了返回值之外,还可以与其调用函数或外界进行交互。例如,特定函数可能会修改全局变量或静态变量,修改其参数之一,引发异常,将数据写入显示或文件,读取数据或调用其他副作用函数。 从这种意义上说,函数式编程语言实际上会带来副作用,因为有无数的函数实例影响它们的外部世界,调用其他函数,引发异常,写入文件等。 那么,最后,函数式编程语言是否允许副作用? 或者,我不明白什么是“副作用”,因此命令式语言允许它们,而声明式语言则不允许。根据以上内容以及所得到的内容,没有一种语言能够消除副作用,因此我可能遗漏了一些有关副作用的信息,或者Wikipedia定义的定义不正确。

1
源内构建与源外构建
在我的(主要是C ++)开发中,我一直坚持使用源代码之外的版本。也就是说,我的来源通常坐落在一个/project/src目录和建立生活在一个/project/build/bin/release,/project/build/bin/debug目录。之所以这样做,是因为它可以使我的源目录与中间文件保持干净,我的所有二进制文件都位于一个位置,打包更容易,清理更容易,版本控制也更容易。(我有什么想念吗?) 我现在正在继承一个使用源代码内部构建的(大型)项目。这种结构的动机是什么,它的优点是什么?(我最关心的是工程级别的原因与个人喜好类型的原因。) 我希望拉科斯(Lakos)的“大型C ++软件设计”能在其中发挥作用,但如果这样做,我会错过它。


2
如何使用多个应用程序实例安全地运行数据库迁移?
我们有一个应用程序,它既有快速的迁移(<1秒)又有缓慢的数据库迁移(> 30秒)。现在,我们正在将数据库迁移作为CI的一部分来运行,但是我们的CI工具必须知道我们的应用程序(在多个环境中)的所有数据库连接字符串,这并不理想。我们希望更改此过程,以便应用程序在启动时运行自己的数据库迁移。 情况如下: 我们有此应用程序的多个实例-在生产中大约有5个实例。我们称他们为node1, ..., node5。每个应用程序都连接到一个SQL Server实例,并且我们不使用滚动部署(就我所知,所有应用程序都是同时部署的) 问题:说我们的迁移时间很长。在这种情况下,先node1启动,然后开始执行迁移。现在node4开始,并且长时间运行的迁移尚未完成,因此node4也开始运行迁移->可能的数据损坏?您将如何预防该问题,或者该问题甚至足够重要而值得担心? 我当时正在考虑使用分布式锁(使用etcd或类似的方法)解决此问题。基本上,所有应用程序都尝试获取锁,只有其中一个可以获取并运行迁移,然后解锁。当其余的应用程序启动并进入关键部分时,所有迁移都已运行,因此迁移脚本将退出。 但是,我的直觉是说:“这太过分了,必须有一个更简单的解决方案。”因此,我想问一下这里是否有其他更好的主意。


3
如何设计一个C ++程序以允许在运行时导入功能?
今天,我想问您一个有关C ++实现特定软件体系结构功能的问题。 当然,我使用了搜索但是没有找到任何直接链接的答案。 基本上,我的目标是建立一个程序,使用户可以对任意组成的物理系统(例如驾驶汽车)进行建模和仿真。我假设有一个物理模型库(类中的函数)。每个函数可以具有一些输入,并根据基础的物理描述返回一些输出,例如,内燃机模型,空气阻力模型,车轮模型等。 现在,该想法是为用户提供一个框架,该框架允许他根据自己的需求来组合任何功能,即映射任何身体行为。该框架应提供功能,以连接不同功能的输出和输入。因此,该框架提供了一个容器类。我称它为COMPONENT,它可以容纳一个或多个模型对象(FUNCTION)。这些容器还可以容纳其他组件(参见复合模式)以及功能参数之间的连接(CONNECTOR)。此外,组件类提供了一些通用的数字功能,例如数学求解器等。 功能的组合应在运行时完成。在第一个实例中,用户应该能够通过导入定义合成结构的XML来建立合成。后来,人们可能会想到添加GUI。 为了使您更好地理解,这里是一个非常简化的示例: <COMPONENT name="Main"> <COMPONENT name="A"> <FUNCTION name="A1" path="lib/functionA1" /> </COMPONENT> <COMPONENT name="B"> <FUNCTION name="B1" path="lib/functionB1" /> <FUNCTION name="B2" path="lib/functionB2" /> </COMPONENT> <CONNECTIONS> <CONNECTOR source="A1" target="B1" /> <CONNECTOR source="B1" target="B2" /> </CONNECTIONS> </COMPONENT> 不必要深入研究框架的功能,因为我的问题更为普遍。编译框架代码/程序时,物理问题描述以及用户定义的功能未知。当用户选择功能(通过XML或以后通过GUI)时,框架应读取功能信息,即应获取输入和输出参数的信息,以便为用户提供互连功能的选项。 我知道反射的原理,并且我知道C ++不提供此功能。但是,我确信经常需要“在运行时构建对象”的概念。我应该如何在C ++中设置软件体系结构以实现我的目标?C ++是正确的语言吗?我忽略了什么? 提前致谢! 干杯,奥利弗

2
SOA和微服务之间的真正区别是什么
免责声明 我希望我不要踩任何人的脚趾或冒犯任何一个概念的狂热者 背景 我一直在寻找面向服务的体系结构和微服务之间的真正区别,而没有找到明确的答案。 我读到以下内容: SOA的副作用 SOA是反模式 微服务来修复SOA的故障 ESB并不是真正的ESB,而是EAI 对消息中介的过度依赖 供应商正在滥用SOA的概念并试图出售其产品 SOA不受控制地增长 但是,仍然没有明确定义面向服务的体系结构(作为一个概念)和微服务(作为一个概念)之间的体系结构差异 据我了解,它们都具有: 服务提供商,只做一件事 服务网关/ ESB将这些服务提供给消费者 服务使用者,通过ESB /服务网关访问服务 题 那么,除了将SOA重新标记为微服务之外,还有什么不同吗?限制微服务成为宏的技术约束吗? 注意:我不是在寻找观点,只是在寻找事实,希望在要点中 参考文献 软件工程问题 马丁·福勒(Martin Fowler)的网站(我认为他讨厌这段时间) 信息世界 迈克尔·富瑟斯的网站 堆栈溢出问题 更新资料 似乎在Stack溢出问题中也发生了类似的辩论,无论是否区分微服务都是变相的面向服务架构。 SO问题的结论: MS是SOA 的特例 MS支持较小规模的应用程序托管服务 MS取决于技术(使用HTTP而非开放协议选项) MS依靠技术来加强纪律(服务的自动部署) MS考虑使用ESB(邪恶),但使用API​​网关,IMHO是ESB的一种 如果满足以下条件,那么可以得出结论,MS是SOA: MS是否支持编排概念?一个或多个主流程管理工作流程 MS中是否有消息代理层?一组适配器,将消息格式从服务生产者的消息空间转换为服务使用者 微服务可以从整体企业应用程序读取数据吗?可以是单片应用程序的API吗?还是必须是能够独立运行的独立的自包含应用程序? 如果最后一个问题的答案为否,那么微服务将无法处理复杂的工作流程系统,例如信用卡管理系统或对帐系统

6
抽象类应包含哪些代码?
最近,我对抽象类的使用感到困扰。 有时,会预先创建一个抽象类,并将其作为派生类工作方式的模板。这意味着或多或少地,它们提供了一些高级功能,但是遗漏了某些细节要由派生类实现。抽象类通过放置一些抽象方法来定义对这些细节的需求。在这种情况下,抽象类的工作原理类似于蓝图,功能的高级描述或您想要的任何名称。它不能单独使用,而必须专门用于定义高层实现中遗漏的细节。 在另一些时候,碰巧抽象类是在创建一些“派生”类之后创建的(由于父/抽象类还不存在,所以还没有派生出来,但是您知道我的意思)。在这些情况下,抽象类通常用作放置当前派生类所包含的任何常见代码的地方。 做出上述观察后,我想知道这两个案例中的哪一个应该成为规则。是否应该仅由于它们当前在所有派生类中都是通用的,而将某种细节冒充到抽象类?是否应该存在不属于高级功能的通用代码? 对于抽象类本身可能没有意义的代码是否应该仅仅因为它对派生类是通用的而存在呢? 让我举个例子:抽象类A有一个方法a()和一个抽象方法aq()。在派生类AB和AC中,方法aq()都使用方法b()。b()应该移到A吗?如果是的话,那么如果有人只看着A(假装AB和AC不在那儿),那么b()的存在就没有多大意义了!这是坏事吗?有人应该能够在不访问派生类的情况下浏览抽象类并了解发生了什么吗? 老实说,在提出这个问题时,我倾向于认为编写一个有意义的抽象类而不必查看派生类是一个干净的代码和干净的体系结构的问题。我真的不喜欢抽象类的想法,它像所有代码的转储一样在所有派生类中都很常见。 您如何看待/实践?

4
登台和UAT环境之间有什么区别?
我知道在开发解决方案时,我们应该至少有3种不同的环境: 开发:程序员可以随时更改和推送更改,以便快速测试他们的代码并与其他更改集成,而不必担心破坏任何东西-它与TEST数据库和服务相关; UAT:开发人员应该尊重UAT,因为它应该包含有关硬件的生产环境的“尽可能好”的副本,不同之处在于该环境通过生产数据的可编辑副本连接到UAT数据库-问答团队和用户都使用它来验证将要投入生产的变更 生产:真实交易。 我在SoftwareEngineering上研究了这个问题,在ServerFault 上研究了这个问题,它们在暂存环境的含义上似乎有所不同。另外,有关该主题的Wikipedia页面指出: 暂存环境的主要用途是在将所有安装/配置/迁移脚本和过程应用于生产环境之前对其进行测试。这样可以确保对生产环境的所有主要和次要升级都能在最短的时间内可靠地完成而不会出错。 对我来说,登台等于UAT,您必须在UAT上测试应用程序和部署过程,然后才能进入现实世界。因此,我们将对UAT所做的更改以与推送到生产的方式相同的方式推送到软件包中,完全自动化,并在生产环境中进行所有应有的仪式。 话虽如此,UAT环境和暂存环境之间的适当区别是什么? - 编辑:为了清楚起见,我在考虑Web应用程序,无论是Internet网站还是Intranet网站。没有“表单”应用或移动应用。

3
为什么编译器通常只为安装它们的平台生成可执行文件?
我是C ++开发人员,为了更好地理解跨平台开发,我试图更好地了解编译器的一些实现细节以及它们如何精确创建OS特定的二进制文件。在研究过程中,我意识到,至少有一段时间,您为特定平台下载的大多数编译器仅针对该平台编译了二进制文件。因此,如果您下载了Windows编译器exe附带的IDE,则该编译器将只能针对x86-x64 Windows应用程序而非Linux或Mac应用程序编译程序。 现在,我了解到不同的平台需要不同的二进制格式,但是为什么说Windows上的可视C ++编译器很难生成Linux二进制可执行文件呢?只要您具有运行CPU的汇编指令以及特定于OS的库,您是否不应该能够在任何计算机上为任何平台编译可执行文件?

3
如何重构具有多个切换案例的应用程序?
我有一个应用程序,它使用整数作为输入,并基于输入调用不同类的静态方法。每次添加新数字时,我们需要添加另一种情况,并调用不同类的不同静态方法。交换机中现在有50个案例,每当我需要添加另一个案例时,我都会发抖。有一个更好的方法吗。 我做了一些思考,想到了这个主意。我使用策略模式。我没有交换条件,而是有一个策略对象映射,键为输入整数。调用方法后,它将查找对象并为该对象调用通用方法。这样,我可以避免使用switch case结构。 你怎么看?

1
OSS项目中的集成测试-如何处理带有身份验证的第三方?
我的一个开源项目是一个备份工具,该工具可从GitHub,Bitbucket等进行脱机存储库备份。 它调用托管者的API来获取存储库列表,然后使用Git / Mercurial /任何克隆/将存储库拉到本地计算机。 因此,我在集成测试中通过身份验证调用了GitHub API。 (并且当克隆/拉动功能完成时,可能会有测试从GitHub克隆存储库,并且还需要进行身份验证) 我创建了一个用户和一个组织,专门用于这些集成测试。 问题:我不能只是在源代码中的某个地方对密码进行硬编码,因为它是开源的,并且代码在GitHub上是公开的。 我现在在做什么 在测试中,我从环境变量中获取所有用户名,密码和存储库名称。 这是一个例子: config.Name = TestHelper.EnvVar("GithubApiTests_Name"); config.Password = TestHelper.EnvVar("GithubApiTests_PW"); (TestHelper.EnvVar是一个帮助程序方法,它获取环境变量的值并在不存在环境变量时引发异常) 然后,我有一个批处理文件,用于设置这些环境变量。 真正的(environment-variables.bat)在构建脚本中以及在执行测试之前被调用,但是在源代码控制中被忽略,因此它实际上不在我的存储库中。 什么是源控制environment-variables.bat.sample,它设定了相同的环境变量,而是用假密码: rem copy/rename this file to environment-variables.bat echo Setting environment variables for integration tests... set GithubApiTests_Name=scm-backup-testuser set GithubApiTests_OrgName=scm-backup-testorg set GithubApiTests_PW=not-the-real-password set GithubApiTests_Repo=scm-backup 因此,我可以将存储库克隆到我的计算机上,将此文件重命名为environment-variables.bat,用真实的密码替换假密码,所有集成测试都将起作用。 这也适用于持续集成-我正在使用AppVeyor,并且可以在Web UI中设置这些环境变量。 我对此不满意 我认为这对于OSS项目不是一个好的解决方案,尤其是对于该项目不是这样: 从理论上讲,我的项目的贡献者现在可以通过以下方式运行集成测试: …

2
只有吸气剂的接口有代码气味吗?
(我已经看到了这个问题,但是第一个答案更多的是关于自动属性而不是设计,而第二个答案则是向使用者隐藏数据存储代码,我不确定这是我想要的/我的代码做了什么,所以我想听听其他意见) 我有两个非常相似的实体,HolidayDiscount和RentalDiscount,它们表示长度折扣,即“如果至少持续numberOfDays使用percent折扣,则适用”。这些表有不同的父实体,并且在不同的地方使用,但是在使用它们的地方,有一种通用的逻辑来获取最大的适用折扣。例如,a HolidayOffer具有多个HolidayDiscounts,在计算其成本时,我们需要找出适用的折扣。租金和相同RentalDiscounts。 由于逻辑相同,因此我想将其放在一个地方。这就是以下方法,谓词和比较器的作用: Optional<LengthDiscount> getMaxApplicableLengthDiscount(List<LengthDiscount> discounts, int daysToStay) { if (discounts.isEmpty()) { return Optional.empty(); } return discounts.stream() .filter(new DiscountIsApplicablePredicate(daysToStay)) .max(new DiscountMinDaysComparator()); } public class DiscountIsApplicablePredicate implements Predicate<LengthDiscount> { private final long daysToStay; public DiscountIsApplicablePredicate(long daysToStay) { this.daysToStay = daysToStay; } @Override public boolean test(LengthDiscount discount) { return daysToStay >= …

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.