软件工程

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

4
像亚马逊这样的公司如何避免访问数据库层的瓶颈?
如果您想象一家像亚马逊(或任何其他大型电子商务网站应用程序)的公司正在大规模运营一家在线商店,而其仓库中的实物数量有限,那么他们如何优化这一点,以至于没有一个瓶颈?当然,它们必须具有多个具有复制功能的数据库,以及许多独立处理负载的服务器。但是,如果多个用户由不同的服务器提供服务,并且两个用户都试图将相同的商品添加到他们的购物车中,而该商品仅剩一个,则该商品的剩余数量必须有一些“真相来源”。这是否意味着至少,所有访问单个商品的产品信息的用户都必须串行查询同一数据库? 我想了解如何使用分布式计算来经营这么大的商店,而又不会在包含库存信息的单个数据库上造成巨大的瓶颈。

2
Voyager任务的代码开发过程?
旅行者1号于2012年8月到达星际空间,是现存最遥远的人造天体。旅行者1号是在其双人航天器旅行者2号不久后发射的,旅行者1号探索了木星和土星的系统,发现了新月,活跃的火山以及有关外部太阳系的大量数据。 旅行者1号和旅行者2号的设计利用了罕见的行星对准技术,该对准技术在176年中仅发生过一次,并且仍然是历史上飞行次数最多的航天器。两架航天器都带有一个称为“黄金唱片”的时间胶囊,这是一个12英寸的镀金铜盘,上面装有声音和图像,这些图像和声音被选择用来向外星人描绘我们的世界故事。 我以为为该任务而开发软件的绝大多数人现在已经退休了,但是在过去的35年中,编程,编程语言到目前为止已经发展了。 因此,它于1977年发射升空。35年后,旅行者号到达星际空间。有几行代码,用什么语言编写?此任务(仍在执行中)背后的开发过程是什么? 那么,此任务中使用代码的更大计划是什么,代码库是用哪种语言编写的?

7
C ++程序是否应该捕获所有异常并防止异常冒泡过main()?
曾经有人告诉我,C ++程序最终应该捕获所有异常。当时给出的推理基本上是允许异常冒泡main()进入怪异的僵尸状态之外的程序。几年前有人告诉我,回想起来,我相信观察到的现象是由于有关项目中产生的异常大的堆芯产生了很长时间。 当时,这似乎很奇怪,但却令人信服。C ++应该“惩罚”程序员没有捕获所有异常完全是荒谬的,但是我面前的证据似乎支持了这一点。对于有问题的项目,引发未捕获异常的程序似乎确实进入了怪异的僵尸状态-或我怀疑是现在的原因,在意外的核心转储中的进程异常难以停止。 (对于任何想知道为什么这在当时不那么明显的人:该项目从多个进程的多个文件中生成了大量输出,这些输出有效地掩盖了任何形式的aborted (core dumped)消息,在这种情况下,对核心转储进行事后检查是没有必要的“这不是一项重要的调试技术,因此无需过多考虑核心转储。程序的问题通常不取决于寿命长的程序随时间推移从许多事件中累积的状态,而是取决于寿命短的程序的初始输入(< 1小时),因此使用来自调试版本或调试器的相同输入重新运行程序以获得更多信息更为实用。) 目前,我不确定仅出于防止异常离开的目的而捕获异常是否有任何主要的优点或缺点main()。 我可以想到的允许异常冒泡的小好处main()是,它会导致将结果std::exception::what()打印到终端上(至少使用Linux上的gcc编译程序)。另一方面,通过捕获所有派生自std::exception该异常的异常并打印结果来实现此目的很简单std::exception::what(),如果希望从非派生的异常中打印一条消息,std::exception则必须在离开之前对其进行捕获才能main()打印消息。 我可以想到的允许异常冒泡的适度缺点main()是,可能会生成不需要的核心转储。对于使用大量内存的过程而言,这可能会很麻烦,并且从程序控制核心转储行为需要特定于OS的函数调用。另一方面,如果需要核心转储和退出,则可以在任何时间通过调用来实现,而在std::abort()没有核心转储的情况下可以通过调用在任何时间实现std::exit()。 有趣的是,我认为我what(): ...在崩溃时从未见过由广泛分布的程序打印的默认消息。 支持或反对允许C ++异常冒出来的强有力的论据是什么(如果有)main()? 编辑:此站点上有很多常规异常处理问题。我的问题特别是关于无法处理的C ++异常,并使其一直存在main()-可能会显示错误消息,但这是立即显示的停止错误。
29 c++  exceptions 

2
为什么C字符串文字是只读的?
字符串文字为只读的优点是(-ies / -ied): 另一种射击自己的方式 char *foo = "bar"; foo[0] = 'd'; /* SEGFAULT */ 无法优雅地初始化一行中的可读写单词数组: char *foo[] = { "bar", "baz", "running out of traditional placeholder names" }; foo[1][2] = 'n'; /* SEGFAULT */ 使语言本身复杂化。 char *foo = "bar"; char var[] = "baz"; some_func(foo); /* VERY DANGEROUS! */ some_func(var); /* …
29 c  memory  strings 

11
多少个设计模式和抽象级别是必需的?[关闭]
我怎样才能知道我的软件有太多的抽象和太多的设计模式,或者反过来,我怎么知道它是否应该有更多的抽象呢? 与我合作的开发人员在这些方面的编程方式有所不同。 有些人确实提取每个小功能,尽可能使用设计模式,并不惜一切代价避免冗余。 其他人,包括我在内,都试图更加务实,并编写出并非完全适合每种设计模式的代码,但由于应用了较少的抽象,因此其理解速度更快。 我知道这是一个权衡。我如何知道何时将足够的抽象放入项目中,又如何知道需要更多抽象呢? 例如,当使用Memcache编写通用缓存层时。难道我们真的需要Memcache,MemcacheAdapter,MemcacheInterface,AbstractCache,CacheFactory,CacheConnector,...,或者这是更易于维护和使用仍然只有一半时,好的代码这些类的? 在Twitter中找到了这个: (https://twitter.com/rawkode/status/875318003306565633)

1
立即调用的匿名JavaScript函数的术语是什么?
我正在为团队编写JavaScript样式指南,以便我们可以更轻松地组织和贡献文档。但是我遇到了一个小障碍,这就是我的问题所在... 我应该如何调用立即调用的匿名JavaScript函数。我知道我可以简单地将其称为“匿名函数”,但我想强调一下它被立即调用的事实。 这是一个例子: var MyVariable = (function(data){ return "another value" })("some value"); console.log(MyVariable); // "another value"

3
为什么大多数免费软件(例如Linux)上不使用UML?
我试图了解为什么大多数免费软件项目中未使用UML。例如,我的Debian / Linux系统可能有超过一万个免费软件包,我什至不能说出使用显式 UML框架和方法开发的软件包。例如,Qt的,GCC,Linux内核,庆典,GNU 化妆,ocaml的,侏儒,齐奏,lighttpd的,libonion,码头工人都是免费的软件项目,其中(据我所知)完全不提UML。 (我的猜测是UML非常适合开发任务的正式分包,而这不是自由软件的开发方式) 请注意,尽管我确实阅读了一些有关UML的材料,但并没有声称对它有很好的理解。 实际上,我不能轻易地命名使用UML的自由软件(也许某些以自由软件实现的UML工具除外)。也许openstack是一个例外(其中提到了UML)。 (即使是旧的免费软件项目在启动后也可能采用了UML,但没有这样做) 一些从事Papyrus研究的同事提到,大多数自由软件项目在开始时就没有任何明确(且足够深入)的形式化模型。而且,UML看起来与Java的关系要比它声称的要多得多(我不完全确定对于Ocaml或Common Lisp或Haskell或Java脚本是否有意义,甚至对于C ++ 11也不可能。)。也许敏捷软件开发不是很友好的UML。 又见这个答案的一个主题相关的问题。M.Fowler的博客设计死了吗?有见地。 PS。我认为这主要不是意见问题;自由软件应该有一些客观原因和一些基本特征,这可以解释原因。我倾向于猜测UML仅对形式化转包有用,并且仅在隐藏了一部分已开发软件时才有用,例如在专有项目中。如果这是真的,那么UML将与自由软件开发不兼容。 注意:我自己不是UML迷。我不仅将UML定义为书面文档,还定义为软件工具的[元]数据格式

8
复制并粘贴长而直接的代码而不是将它们包装到类或函数中是否可以接受?
假设我有一段代码可以连接到互联网并显示类似的连接结果: HttpRequest* httpRequest=new HttpRequest(); httpRequest->setUrl("(some domain .com)"); httpRequest->setRequestType(HttpRequest::Type::POST); httpRequest->setRequestData("(something like name=?&age=30&...)"); httpRequest->setResponseCallback([=](HttpClient* client, HttpResponse* response){ string responseString=response->getResponseDataString(); if(response->getErrorCode()!=200){ if(response->getErrorCode()==404){ Alert* alert=new Alert(); alert->setFontSize(30); alert->setFontColor(255,255,255); alert->setPosition(Screen.MIDDLE); alert->show("Connection Error","Not Found"); }else if((some other different cases)){ (some other alert) }else Alert* alert=new Alert(); alert->setFontSize(30); alert->setPosition(Screen.MIDDLE); alert->setFontColor(255,255,255); alert->show("Connection Error","unknown error"); } }else{ (other handle …

4
C#6.0的新空条件运算符是否违反Demeter定律?
该德米特法律规定如下: 每个单元对其他单元的知识应该有限:只有与当前单元“紧密”相关的单元。 每个单位只能与朋友交谈;不要和陌生人说话。 只与您的直系朋友交谈。 C#6.0引入了一个称为空条件运算符的新运算符。恕我直言,它使编码更容易并提高了可读性。但这也使编写更多耦合的代码变得更容易,因为更容易在已经检查了无效性的类字段中导航(类似var x = A?.B?.C?.D?.E?.F?)。 陈述这名新操作员违反Demeter法则是否正确?

2
为什么制作一个64位版本的程序会很困难?
在我的短时间编程中,只要我有程序的完整源代码,就可以为32位或64位计算机编译我的任何C ++,Java等都是很简单的。 但是很多软件没有发布64bit。最令人讨厌的是,还没有64位版本的Unity引擎。 是什么使得很难为64位计算机编译某些程序?

6
您可以在没有class关键字的情况下实现“面向对象”编程吗?
假设我们要提供银行“帐户”的抽象。这是function在Python中使用对象的一种方法: def account(): """Return a dispatch dictionary representing a bank account. >>> a = account() >>> a['deposit'](100) 100 >>> a['withdraw'](90) 10 >>> a['withdraw'](90) 'Insufficient funds' >>> a['balance'] 10 """ def withdraw(amount): if amount > dispatch['balance']: return 'Insufficient funds' dispatch['balance'] -= amount return dispatch['balance'] def deposit(amount): dispatch['balance'] += amount return dispatch['balance'] …

3
重写的版本控制实践
我们用语言X开发了产品(原型)P_OLD,现在我们正从头开始用语言Y将其重写为P_NEW。 由于P_NEW和P_OLD是同一产品: P_NEW应该只是旧的P_OLD分支还是应该是它自己的存储库? 从版本控制角度来看,处理如此大的更改的通常方法是什么?

6
类型推断的权衡是什么?
似乎所有新的编程语言,或者至少是流行的编程语言都使用类型推断。即使是Javascript,也可以通过各种实现(Acscript,Typescript等)获得类型和类型推断。对我来说看起来很棒,但我想知道是否需要权衡取舍,或者为什么要说Java或旧的好语言没有类型推断 在Go中声明变量而不指定其类型时(使用不带类型的var或:=语法)时,将从右侧的值推断出变量的类型。 D允许编写大型代码片段,而无需像动态语言那样重复指定类型。另一方面,静态推断可推导类型和其他代码属性,从而充分利用静态和动态环境。 Rust中的类型推断引擎非常聪明。它所做的不只是在初始化过程中查看r值的类型。它还看起来如何在以后使用变量来推断其类型。 Swift使用类型推断来得出适当的类型。通过类型推断,编译器只需检查您提供的值,即可在编译代码时自动推断出特定表达式的类型。

3
一个好的通用类型系统
人们普遍认为Java泛型在某些重要方面失败了。通配符和范围的组合导致了一些严重无法读取的代码。 但是,当我看其他语言时,似乎真的找不到程序员满意的通用类型系统。 如果我们将以下作为此类类型系统的设计目标: 总是产生易于阅读的类型声明 易于学习(无需复数协方差,逆方差等) 最大化编译时错误的数量 有没有正确的语言?如果我使用google,我唯一看到的就是对类型系统如何吸收X语言的抱怨。这种类型的复杂性是通用类型固有的吗?我们应该放弃在编译时尝试100%验证类型安全性的想法吗? 我的主要问题是,就这三个目标而言,哪种语言“做到最好”是最好的。我意识到这是主观的,但到目前为止,我什至找不到一种语言,并非所有程序员都同意通用类型系统是一团糟。 附录:如前所述,子类型/继承和泛型的结合才是造成复杂性的原因,所以我真的在寻找一种将两者结合起来并避免复杂性激增的语言。

9
TDD仅在理论上
一年多以前,我很幸运能够休息9个月。我决定在那段时间里磨练自己的C#技能。我开始从事许多项目,并强迫自己遵循TDD。 这是一个相当启发的过程。 刚开始时很难,但是随着时间的流逝,我学会了如何编写更多可测试的代码(事实证明,这往往是更多的SOLID代码),并且在此过程中,我还提高了OO设计技巧。 现在,我回到了工作岗位,并且注意到了一些奇怪的事情。 我宁愿不遵循TDD。 我发现TDD会使我慢下来,实际上使设计干净的应用程序更加困难。 相反,我采用了一种(完全)不同的方法: 挑选垂直的作品 开发功能正常的原型 重构直到一切都变得整洁 请欣赏一下我编写的精美的SOLID和可测试的代码。 您可能已经注意到,第1步不是“定义我的测试目标的公开表面”,而第2步不是“在所述公开表面上测试耶稣”。您可能还注意到,所有步骤都不涉及测试。我正在编写可测试的代码,但是我尚未对其进行测试。 现在,我想说明一下,我实际上并没有进行任何类型的测试。我正在编写的代码有效。它有效,因为我正在手动测试它。 我还想明确指出,我也没有提到所有自动化测试。这是我的过程与众不同的地方。这就是为什么我问这个问题。 TDD理论上。不在实践中。 我的过程有所发展,我在TDD和没有发现我认为非常有效且也相当安全的测试之间取得了平衡。内容如下: 在考虑到测试的情况下实现工作的垂直工作,但是不要编写任何测试。 如果在路上(例如,一个月后),该切片需要修改 编写单元测试,集成测试,行为测试等,以确保工作片段正确无误 修改代码 如果该切片不需要修改, 没做什么 通过简单地将编写测试的负担从编写代码之前转移到修改代码之前,我已经能够生产出更多的工作代码。而且,当我确实着手编写测试时,我编写的测试数量要少得多,但是覆盖的范围却差不多(投资回报率更高)。 我喜欢这个过程,但是我担心它可能无法很好地扩展。它的成功取决于开发人员在更改测试之前勤于编写测试。这似乎是一个很大的风险。但是,TDD具有相同的风险。 那么,我该死[BT] DD,还是这是一种实用的编码和测试的常见形式? 我想继续这样工作。从长远来看,我该怎么做才能使该过程正常运行? 注意: 我是项目的唯一开发人员,我负责所有工作:需求收集,设计,架构,测试,部署等。我怀疑这就是我的流程正常运行的原因。

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.