软件工程

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

6
依赖注入的最佳定义是什么?
每次有人联系我,并要求我以概念性方式定义“依赖项注入”,并解释在软件设计中使用DI的真正利弊。我承认我很难解释DI的概念。每次我需要告诉他们有关单一责任原则,组成而不是继承的历史时。 任何人都可以帮助我解释为开发人员描述DI的最佳方法吗?

5
我是否真的需要关系数据库的触发器,例如PostgreSQL?
我知道触发器可以用来验证存储的数据以保持数据库的一致性。但是,为什么不先在应用程序端对数据进行验证,然后再将其存储到数据库中呢? 例如,我们存储客户,并且我们想要执行一些在DDL级别上不容易完成的验证。 https://severalnines.com/blog/postgresql-triggers-and-stored-function-basics 另一个例子是审计。 更新资料 触发器和数据库事务如何一起工作。例如,如果我想对插入的数据进行验证。它是在事务内部完成的。之前发生了什么:事务已提交或触发器已执行?


4
什么是“过早抽象”?
我听过这个短语被扔掉了,对我来说,论点听起来完全是疯了(对不起,如果我在这里是稻草人,那不是我的意图),通常它遵循以下原则: 您不希望在知道一般情况之前先创建一个抽象,否则(1)您可能会将不属于您的东西放在抽象中,或者(2)忽略了重要的事情。 (1)对我来说,这听起来像程序员不够务实,他们已经假设事情会出现在最终程序中,而事实并非如此,因此他们使用的抽象程度很低,问题不是过早的抽象,它是过早的凝结。 (2)忽略重要的事情是一回事,完全有可能在规范中省略了某些事情,后来证明这很重要,解决这个问题的方法不是在发现自己时就浪费自己的资源和浪费资源。猜错了,这是从客户端获取更多信息。 我们应该始终从抽象到具体工作,因为这是最实用的做事方式,而不是相反。 如果我们不这样做,那么我们可能会误解客户,并创造需要更改的东西,但是如果我们仅构建客户以其自己的语言定义的抽象,那么我们就永远不会遇到这种风险(至少远不及承担风险)是在黑暗中带着某种凝结的镜头),是的,客户可能会改变对细节的想法,但是他们最初用来传达他们想要的内容的抽象往往仍然有效。 这是一个示例,假设客户希望您创建一个物品装箱机器人: public abstract class BaggingRobot() { private Collection<Item> items; public abstract void bag(Item item); } 我们正在从客户端使用的抽象中构建一些东西,而没有涉及我们不知道的事情的更多细节。这是非常灵活的,我已经看到这被称为“过早抽象”,而实际上假设套袋是如何实施还为时过早,可以说与客户讨论后,他们希望一次将多个袋装成袋。为了更新班级,我只需要更改签名,但是对于自下而上的人可能需要进行大范围的系统检修。 没有过早的抽象,只有过早的凝结。这句话有什么问题?我的推理的缺陷在哪里?谢谢。

1
API网关后面的微服务是否需要验证访问令牌?
我有一堆只能通过API网关从外部访问的微服务。 我的API网关设置为OAuth资源,并在将请求下游传递给一个或多个微服务之前验证令牌(检查签名等)。 虽然我的微服务需要令牌才能验证范围和声明,但现在是否还需要该服务来验证令牌? 似乎有些矫kill过正,但我​​无法在线找到有关此情况的任何建议。 在API网关上验证令牌是否足够好?还是最好的做法是稍后再进行验证?

4
如果微服务架构需要每个微服务单独的数据库,那么它的成本太高且难以管理。为什么我们甚至需要它?
我读到有关微服务的信息,对于每个服务创建一个单独的DB来实现隔离似乎不合逻辑。我可以仅使用Web服务和单个数据库来实现相同的目的。为什么我们甚至需要它?分开数据库的东西是无聊的。还是我明明是错?你能指导我吗?

4
以适当的方式将条件替换为多态吗?
考虑两个类Dog并且Cat都符合Animal协议(就Swift编程语言而言。这将是Java / C#中的接口)。 我们有一个屏幕,显示猫和狗的混合列表。有一个Interactor类处理幕后逻辑。 现在,我们要向用户显示删除猫的确认警报。但是,需要立即删除狗而不发出任何警报。有条件的方法如下所示: func tryToDeleteModel(model: Animal) { if let model = model as? Cat { tellSceneToShowConfirmationAlert() } else if let model = model as? Dog { deleteModel(model: model) } } 该代码如何重构?闻起来很香

2
为什么Forth的灵活性使语法不适合它?
我最近承担了编写基于堆栈的编程语言的任务。但是,在开始设计语言之前,我认为阅读和尝试现有的基于堆栈的语言是一个好主意。 这把我带到了这篇文章的主题。我正在阅读有关Forth的Wikipedia文章,Forth是一种使用后缀样式表达式的基于堆栈的语言。在文章中,我看到了以下语句: Forth的灵活性使静态BNF语法不合适,并且它没有整体编译器。扩展编译器只需要写一个新词,而不需要修改语法和更改基础实现。 据我了解,在Forth术语中,“单词”一词基本上与“子例程”同义。鉴于此,上述说法似乎很奇怪。为什么在Forth中创建新功能的能力会导致Forth的正式语法不合适?为什么需要为定义的每个新子例程重新编写语法?在环境中写一个新单词如何构成扩展编译器?上面的陈述似乎类似于说正式语法不适合Python,因为您可以定义新函数。 实际上,我决定尝试为下面的Forth的一个简单子集编写BNF样式语法: program ::= stmt+ stmt ::= func | expr func ::= ':' expr+ ';' expr ::= INTEGER | word word ::= ('+' | '-' | '*' | '/' ) 上面的语法似乎涵盖了Forth语句的有效子集,并且似乎很难扩展到涵盖Forth语言中的所有有效语句。此外,如果编译器的解析器实现了上述语法,我将看不到如何扩展该编译器。编译器只会在其环境中添加任何新词。仅环境被更改。似乎以上来自Wikipedia的摘录似乎正在将构成编译器(不会更改)的下划线代码与编译器的环境(确实会更改)进行混合。 总而言之,为什么福斯(Forth)定义新词(子例程)的敏捷性不适合书面语法?

2
警报系统架构
我想创建一个系统,处理来自各种程序的警报消息,并可以通过电子邮件将这些警报处理给顺风顺水的消费者。所有这些都将包含在一个内部网络中。 我想我希望基本架构看起来像这样: 我目前主要关心的是“消息处理程序”位,这就是我的“ API排序”。我希望该系统的所有组件将数据发送到API,该API处理所有对数据库的写入。我认为这种方法比较容易,因为它简化了安全性,并允许我将许多更复杂的数据库查询包含在一个程序中。 令人担心的是,我希望这与语言无关,这意味着任何代码都应能够将消息发送到我的处理程序,由它来解释它们。我希望通过JSON平面文件-或通过对该程序的REST调用(为下游应用程序提供灵活性)来做到这一点。 我的问题是 我应该烦恼消息处理程序吗?或者它会增加简单性,使其仅允许直接数据库访问下游应用程序以及其他两个组件(管理控制台和警报管理器)? 这样,他们就可以插入想要的任何警报-只要将INSERT插入数据库表中即可。 我不是专业的软件设计师,所以请原谅-我只想在业余时间做一个项目。

4
好的代码风格可在任何地方引入数据检查?
我有一个足够大的项目,我再也无法保持每个方面的头脑。我正在处理其中的许多类和函数,并且正在传递数据。 随着时间的流逝,我注意到我一直在出错,因为我忘记了将数据传递给不同的函数时数据必须具有的精确格式(例如,一个函数接受并输出一个字符串数组,另一个函数是我后来写的,接受保留在字典等中的字符串,因此我必须将正在使用的字符串从数组中的字符串转换为字典中的字符串)。 为了避免总是要弄清楚什么地方断了,我开始将每个函数和类都视为“孤立实体”,因为它不能依赖外部代码为其提供正确的输入,而必须自己执行输入检查(或,在某些情况下,如果数据格式错误,请重铸数据。 这大大减少了我花费在确保传递的数据“适合”每个函数上的时间,因为当某些输入不正确(有时甚至纠正)时,类和函数本身会警告我,而我不会必须与调试器一起遍历整个代码,以找出问题的根源。 另一方面,这也增加了整体代码。 我的问题是,此代码样式是否适合解决此问题? 当然,最好的解决方案是完全重构项目,并确保数据具有所有功能的统一结构-但是由于该项目不断增长,因此我最终将花费更多的时间并担心干净的代码,而不是实际添加新内容。 (仅供参考:我仍然是一个初学者,因此,如果这个问题太天真,请原谅;我的项目是使用Python。)

5
敏捷方法论:快速又肮脏还是先计划?
敏捷问题:敏捷是否相信以“快速而肮脏的方式”启动并运行事物?还是敏捷更喜欢从头开始进行牢固构建?还是这不是方法论问题,而是您逐案评估的问题? 从技术上说,我是在“重造”系统的基础之后,我已经构建了很多结构本身……这不是一项艰巨的工作……会敏捷地希望我首先确定整个流程,对其进行分析,进行调整,然后构建?我觉得从某种意义上说这是更好的方法……一旦建立了一个凌乱的系统,我就会更好地了解它是如何完成的……另一方面,它并没有那么有条理……只是好奇什么才是最好的发展实践就是在这方面。 我认为这个问题与敏捷和原型设计有些不同,因为我不是在问原型设计和一次性代码。我对敏捷的生产级代码感兴趣。
10 agile 


6
如何避免在次优设计中无休止地迭代?
因此,可能像许多人一样,我经常发现自己对设计问题感到头疼,例如,有些设计模式/方法似乎可以直观地解决问题并具有预期的好处。通常会有一些警告,如果没有某种工作就很难实施模式/方法,而这周围的工作否定了模式/方法的好处。我可以很轻松地结束许多模式/方法的迭代,因为可以预见的是,几乎所有的模式/方法在现实世界中都存在一些非常重要的警告,在这些情况下,根本没有一个简单的解决方案。 例: 我将给您一个假设的示例,大致基于我最近遇到的一个真实示例。假设我想在继承上使用合成,因为过去继承层次结构阻碍了代码的可伸缩性。我可能会重构代码,但随后发现在某些上下文中,超类/基类只是需要在子类上调用功能,尽管尝试避免这样做。 下一个最好的方法似乎是实现一半委托/观察者模式和一半组合模式,以便超类可以委托行为,或者子类可以观察超类事件。然后,该类的可伸缩性和可维护性较差,因为它不清楚应如何扩展,而且扩展现有的侦听器/代理也很棘手。同样,信息也隐藏得不好,因为人们开始需要了解实现以了解如何扩展超类(除非您非常广泛地使用注释)。 因此,在此之后,我可能会选择完全使用观察者或委托人来避免因混淆大量方法而带来的弊端。但是,这有其自身的问题。例如,我可能会发现我最终需要观察者或代表来应对越来越多的行为,直到我几乎需要针对每种行为的观察者/代表。一种选择可能是只为所有行为提供一个大的侦听器/代理,但是实现类最终会带有许多空方法等。 然后,我可以尝试另一种方法,但是与此同时存在很多问题。然后是下一个,然后是下一个,依此类推。 当每种方法似乎都存在其他问题时,这种迭代过程将非常困难,并导致某种设计决策瘫痪。无论使用哪种设计模式或方法,都很难接受代码最终同样会带来问题。如果我最终陷入这种情况,是否意味着问题本身需要重新考虑?别人遇到这种情况时会做什么? 编辑: 似乎有一些我想清除的问题的解释: 我将OOP完全排除在问题之外,因为事实证明它实际上并不是特定于OOP的,而且很容易误解我在传递OOP时所做的一些评论。 有些人声称我应该采取迭代的方法并尝试不同的模式,或者当它停止工作时我应该放弃一个模式。这是我首先要参考的过程。我认为这个例子很清楚,但是我可以更清楚一点,所以我编辑了问题。

6
将大多数类划分为仅数据字段类和仅方法类(如果可能的话)是好的还是反模式的?
例如,一个类通常具有类成员和方法,例如: public class Cat{ private String name; private int weight; private Image image; public void printInfo(){ System.out.println("Name:"+this.name+",weight:"+this.weight); } public void draw(){ //some draw code which uses this.image } } 但是在阅读了有关“单一职责原则”和“开放封闭原则”之后,我更喜欢仅使用静态方法将类分为DTO和辅助类,例如: public class CatData{ public String name; public int weight; public Image image; } public class CatMethods{ public static void printInfo(Cat …

3
将一组相关的属性包装到其自己的struct / class中是一种好习惯吗?
用Swift编写User对象,尽管我的问题与任何强类型语言有关。用户可以拥有一堆链接(FacebookProfile,InstagramProfile等)。有关此问题。 将链接包装在其自己的对象中是一种好习惯吗? struct用户{ var firstName:字符串 var lastName:字符串 var email:string var链接:链接 } 结构链接{ var facebook:字符串 var instagram:字串 var twitter:字符串 } 还是应该松散?从技术上讲,我知道这两种方法都很好,但是总体上想知道是否有推荐的方法,尤其是为了提高可读性。 struct User { var firstName: string var lastName: string var email: string var facebookLink: string var twitterLink: string var instagramLink: string } 在这种情况下,链接应该是集合/列表吗?我认为它不应该是一个列表,因为有固定数量的链接选项可用,并且数量不会增加。我的想法对吗? 将我的网络方法放置在User对象(例如getUsers,getUser,updateUser)内是否是一种好习惯? 我知道这些可能是主观的,但是我试图了解在类似情况下的最佳实践是什么。将不胜感激任何指针。

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.