Questions tagged «design»

有关通过软件设计解决问题和计划解决方案的问题。

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

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

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

4
编译器如何从类型错误中恢复?
我已经阅读了几篇论文,文章和《编译器:原理,技巧和工具(第二版)》(第2版)(又称“龙书”)第4章第4.1.4节,它们都讨论了语法编译器错误恢复的主题。但是,在尝试了几种现代编译器之后,我发现它们还可以从语义错误以及语法错误中恢复。 我非常了解编译器从句法相关的错误中恢复的算法和技术,但是我并不完全理解编译器如何从语义错误中恢复。 我目前使用的访问者模式略有变化,以从我的抽象语法树生成代码。考虑我的编译器编译以下表达式: 1 / (2 * (3 + "4")) 编译器将生成以下抽象语法树: op(/) | ------- / \ int(1) op(*) | ------- / \ int(2) op(+) | ------- / \ int(3) str(4) 然后,代码生成阶段将使用访问者模式来递归地遍历抽象语法树并执行类型检查。将遍历抽象语法树,直到编译器到达表达式的最内层为止。(3 + "4")。然后,编译器会检查表达式的每一面,并发现它们在语义上不相等。编译器引发类型错误。这就是问题所在。编译器现在应该做什么? 为了使编译器能够从此错误中恢复并继续对表达式的外部部分进行类型检查,它必须从评估表达式的最内部部分到表达式的下一个内部部分返回某种类型(int或str)。但是它根本没有返回的类型。由于发生类型错误,因此没有推断出任何类型。 我提出的一种可能的解决方案是,如果确实发生类型错误,则应该引发错误,并且应该将一个特殊值(表示发生类型错误)返回给以前的抽象语法树遍历调用。如果先前的遍历调用遇到此值,则他们知道在抽象语法树中更深处发生类型错误,因此应避免尝试推断类型。尽管此方法确实有效,但效率似乎很低。如果表达式的最内层部分位于抽象语法树的深处,则编译器将不得不进行许多递归调用,而仅是意识到无法完成任何实际工作,而只需从每个返回即可。 我是否使用了上述方法(我对此表示怀疑)。如果是这样,效率不高吗?如果不是,那么编译器从语义错误中恢复时将使用什么方法?

6
在编码之前设计OOP系统的简单过程是什么?
每当需要构建项目时,我总是设法进行构建,而不是事先设计计划或设计,而是在首先编写了需要的类之后,从下至上充实整个项目。现在,我知道这不是创建软件的正确方法,但是对我来说,将其包裹在所谓的面向对象的分析和设计上并不容易。我可以更容易地理解自上而下的程序设计,因为它只包含将任务分解为子任务,这些子任务在代码,功能上与之相对。但是我不容易理解面向对象的分析和设计,因为我不理解人们如何知道他们将需要哪些类以及它们将如何交互,除非他们知道如何对它们进行编码。 因为一旦在设计过程中引入了类和对象的概念,就不能再自上而下进行设计,因为我们不再将问题分解为可以作为过程实现的事物。相反,根据我对该主题的了解,我们必须确定需要哪些类,并在统一建模语言中创建各种工件,然后在实现软件时就可以使用这些工件。但是这种设计过程我不明白。除非他们已经构思了整个系统,否则如何知道他们将需要哪些类以及它们将如何交互? 这就是我的问题。尽管我确实了解面向对象编程的概念,但是我不了解如何设计面向对象的系统,并且可以在我知道的任何面向对象编程语言中使用这些概念。因此,我需要有人向我解释可以使用对我来说有意义的方式设计面向对象系统的简单过程。

2
覆盖率-算法中的缺陷-如何摆脱它的使用?
介绍 许多主线矢量图形渲染引擎都存在算法缺陷。它们分别渲染每个形状,并通过计算像素覆盖率来消除锯齿,然后将它们彼此叠加在一起。是的,它很简单,但是正确的解决方案甚至更简单。 这就导致了合并问题,因为它通过透明性扩大了覆盖范围。Alpha混合遵循的规则不能准确表示情况,例如,以50%覆盖的像素与50%互补覆盖的像素相邻的像素,其覆盖率最终不会达到100%,而覆盖率最终达到75% 。它的外观取决于算法的调整方式和其他细节,但从本质上讲这是一个已知的错误。甚至有人在记录不同的引擎错误以及写一篇论文说明如何更好地解决问题方面费了很多力气。 图像1:完全不具有代表性的示例,呈现的形状是由三角形组成,在顶部显示放大的误差。SVG来源 这个问题有一个简单的天真解决方案*,只是超级样本,没有覆盖率计算,并且将图像过滤掉。作为奖励,您可以使用比框滤波更好的图像重建算法(请参阅像素不是正方形3)。甚至有些解决方案的速度可以与当前解决方案相提并论,并且这些解决方案在硬件光栅化管道中更容易实现(并且您在GPU上很少看到此错误,因为它是为避免这个问题而构建的)。 这也不是没有成本的问题。有许多从事图形设计工作的人花费大量时间来尝试手动解决此问题,方法是确保此处没有重叠,而那里没有重叠以解决计算机应为他们解决的问题。而且在很多情况下都会失败。但是他们的客户不在乎为什么必须在那里解决错误。 题 错误如何传播?由于它们都在执行相同的错误,因此可以得出结论,他们对算法使用相同的源。是什么导致设计人员选择此算法?为什么只有3D程序员会识别此错误,甚至将其错误编入其API和教学中,而2D程序员却没有呢? 如何确保此错误不再继续传播? 附录(但我不是在问这个) *显然,我声称超级采样无缺陷的工作是非凡的,并且需要非凡的证明。好的,所以超级采样工作的关键是超级采样不进行覆盖处理。本质上,超级采样器将每个样本视为点样本。由于点样本不假设基础区域,因此不会在没有发生的情况下进行alpha比较。 为了使其始终如一地工作,如答案之一所述。为了一致性,我们需要使用整数采样来处理样本。这可以确保每个点一旦转换为屏幕空间,对于相同的坐标都将获得完全相同的解决方案,并且没有任何样本被像素边界遮挡2次。要做到这一点,一个样本可能不会触发一个像素,如果它是例如左侧底部样本,则它可能不会完全打开(因此我们制定了一条规则,即在> vs <=中处理确切的边缘)。除一个控制台图形卡外,其他所有图形卡都按此方式工作。它确保不需要缓存额外的数据,也不需要进行额外的附近测试。与基于覆盖的解决方案相比,该解决方案更稳定,更通用,更一致。 该算法与原始算法完全相同,但代码更少,样本更多。因此,与基于覆盖的算法相比,它甚至是一致的。我们之所以知道这一点,是因为我们几乎在其他任何信号处理领域以及图形卡中都使用了这种方法。 那么这种方法有缺点吗?好吧,如果您只是天真的假设,那就慢了一点。从理论上讲,它比覆盖范围栅格化器具有更快的渐近行为,有点像光线跟踪器,它在典型场景中仍仅处于同等水平。同样,这可能会使基于卷积的效果的使用更加难以实现。

2
谁设计Web开发中的数据库?[关闭]
已关闭。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗?更新问题,以便通过编辑此帖子以事实和引用的形式回答。 3年前关闭。 在Web开发的背景下,谁设计数据库?尽管有大量的信息将后端Web开发人员与服务器端处理,数据建模等相关联,但方程式的数据库设计方面似乎并不存在。 我不是在说谁设置物理数据库,而是在说谁设计数据库的逻辑模型,进行用户故事采访以获取有关需要哪些字段,这些字段规范是什么等信息。 。 我已经意识到(PROPER数据库)的设计是不小的任务(我在读这 672寻呼机),并可以很容易地是整个行业。但是,在Internet上上下搜索对于预期在Web开发环境中负责此任务的人员而言,收效甚微。

1
社交网络通知系统
背景 我正在为包含一些社交网络功能的客户端开发应用程序。我原本是在开发移动前端,但当时的情况也让我负责开发后端。 作为一般背景,我们的系统允许用户关注其他用户,并收到有关他们关注的人的通知,这是您期望从社交网络获得的。需要注意的是,只有一小部分用户(最多几百个)是可追踪的,并期望大多数用户群将关注这些个人中的至少一个。 在用户界面侧,我们将有一个带有数字的通知按钮,单击该按钮将带您进入通知屏幕。 问题 我一直在研究实现通知的策略,发现的大多数资源都指向在数据库中创建一个或多个通知表。(我喜欢的一个示例是此处接受的答案:https : //stackoverflow.com/questions/9735578/building-a-notification-system)。 让我烦恼的是,大多数数据库驱动的通知策略都要求为每个关注者的每个通知插入一行。因此,如果有一千人在关注​​Sally,我们将在相应表中插入一千行。那可扩展吗?如果我们到了成千上万的用户关注Sally并且她每天发表数十条帖子的情况,会发生什么? 我最初的想法是处理查询的所有问题:通知按钮上的数字将通过请求比上次访问通知屏幕最近发布的内容的行计数来获得,而单个通知将通过更详细的查询生成当您访问通知屏幕时。这种方法不需要写入或额外的存储空间,但是不灵活,可能会严重影响服务器。 设定 后端(由先前的开发人员建立)使用CodeIgniter和MySQL数据库。它目前在糟糕的GoDaddy共享托管帐户上运行,但我认为(希望吗?)在我们投入生产之前,将对其进行升级,并且托管软件包将随着用户的增长而扩展。 目前,我们唯一的前端是移动应用程序,但我们计划稍后再建立一个网站。我现在不关心从服务器获取有关通知的实时推送更新。 附录 我不专门研究后端,而我在那个部门负责。客户知道这一点,并且我已尽力解释这种性质的项目的范围,但是他们已经明确表示,在这一点上,他们将不信任任何其他人来从事该项目。在开始添加测试人员之前,我们可能还要再做一个月的工作,我才能获得任何类型的性能指标。我真的无法估计未来5年我们将拥有多少用户,或者我们将使用什么硬件,但是我认为客户希望有成千上万的用户或更多。 我希望这个问题足够具体,可以在此处发布。如果需要,我可以对其进行优化。请询问您是否有任何疑问,或者我省略了重要的详细信息。 tl; dr 当所有用户都只跟随数百人时,数据库驱动的通知系统是否会对长期可扩展性产生负面影响? 有没有一种方法可以使通知由数据库驱动,而无需为每个关注者的每个通知单独的通知行? 完全由查询驱动的通知系统是否具有可伸缩性,或者除了不向数据库写入任何数据以外,还具有其他优点? 我想得太早了吗?我是否应该仅构建一个目前可以使用的产品,并且由于客户预算有限并且我们不知道最终产品是否会流行,如果问题出现,我们可以担心对其进行优化吗?

2
HTTP请求/响应对象应该是不可变的吗?
我认为可以肯定地说,大多数Web应用程序都基于请求/响应范例。PHP从未对这些对象进行正式的抽象。一个小组正在尝试改变这一点:https : //github.com/php-fig/fig-standards/blob/master/proposed/http-message.md 但是,他们在不变性问题上有些偏颇。一方面,请求/响应对象通常在其生命周期内几乎不需要更改。另一方面,响应对象尤其经常需要添加HTTP标头。 此外,不变性从未真正在PHP领域流行。 人们在使用不可变的请求/响应对象时会看到哪些优势? 假设您要返回一个json对象。 $response = new JsonResponse($item); 漂亮又简单。但是事实证明,该请求是跨域资源共享(CORS)请求。生成响应的代码无关紧要,但是下游的某个过程将添加必要的Access-Control标头。保留原始响应并使用其他标题创建新响应有什么好处?还是严格来说是编程风格的问题。 请求对象更加有趣。它从相同的地方开始: $request = new Request('incoming request information including uri and headers'); 初始信息不需要更改。但是,随着请求的传递,通常需要添加其他处理信息。例如,您可能有一个URL匹配器,该匹配器决定应为给定请求执行什么操作。 $request->setAttribute('action',function() {}); 实际执行操作是下游流程的责任。您可能有一个可变的RequestAttributesCollection,它包装了不可变的请求,但在实践中往往有些尴尬。除了属性集合之外,您还可能有一个不变的请求。异常也往往很尴尬。处理此类要求有经验吗?

4
为什么python生成器和函数共享“ def”关键字?
考虑以下: def some_function(): return 1 def some_generator(): yield 1 在上面的代码中,some_function是一个函数,some_generator而是一个生成器。他们看起来很相似。 我在阅读代码时遇到的问题是,我需要在“函数”的每一行中进行扫描以寻找yield关键字,然后才能确定它实际上是函数还是生成器! 在我看来,为生成器使用其他关键字会更有意义,例如: gen some_generator(): yield 1 def对生成器和函数使用关键字有什么好处?为什么未将新关键字引入单独的函数和生成器?

1
如何避免健谈的界面
背景: 我正在设计一个服务器应用程序,并为不同的子系统创建单独的dll。为简化起见,假设我有两个子系统:1)Users2)Projects 用户的公共界面具有如下方法: IEnumerable<User> GetUser(int id); 而且Projects的公共接口具有如下方法: IEnumerable<User> GetProjectUsers(int projectId); 因此,例如,当我们需要显示某个项目的用户时,我们可以调用GetProjectUsers,这将为对象提供足够的信息以显示在数据网格或类似物中。 问题: 理想情况下,Projects子系统不应同时存储用户信息,而应仅存储参与项目的用户的ID。为了服务的GetProjectUsers,它需要调用GetUser的的Users系统存储在自己的数据库中的每个用户ID。但是,这需要大量单独的GetUser调用,从而在User子系统内部引起大量单独的sql查询。我还没有真正测试过,但是具有这种健谈的设计会影响系统的可伸缩性。 如果不考虑子系统的分离,我可以将所有信息存储在两个系统Projects都可以访问的单个模式中,并且可以简单地执行a操作,JOIN以在单个查询中获取所有项目用户。Projects还需要知道如何User从查询结果中生成对象。但这打破了具有许多优点的分离。 问题: 有人可以建议一种在避免所有这些单独GetUser通话的同时保持分隔的方法GetProjectUsers吗? 例如,我曾想过让用户为外部系统提供使用标签值对“标记”用户并请求具有特定值的用户的能力,例如: void AddUserTag(int userId, string tag, string value); IEnumerable<User> GetUsersByTag(string tag, string value); 然后,Projects系统可以在将每个用户添加到项目中时对其进行标记: AddUserTag(userId,"project id", myProjectId.ToString()); 在GetProjectUsers期间,它可以在一次调用中请求所有项目用户: var projectUsers = usersService.GetUsersByTag("project id", myProjectId.ToString()); 我对此不确定的部分是:是的,用户与项目无关,但实际上有关项目成员资格的信息存储在用户系统中,而不是项目中。我只是感觉不自然,所以我试图确定我是否缺少一个很大的劣势。

6
设计与数据库相关的方法,最好返回:true / false或受影响的行?
我有一些方法可以在数据库中执行某些数据更改(插入,更新和删除)。在ORM我使用这些类型的方法返回行INT影响值。我应该为“我的方法”返回什么,以指示操作的成功/失败状态? 考虑返回一个代码int: A.1 public int myLowerLevelMethod(int id) { ... int affectedRows = myOrm.deleteById(id) ... return affectedRows; } 然后用法: A2 public void myOtherMethod() { ... int affectedRows = myLowerLevelMethod(id) if(affectedRows > 0) { // Success } else { // Fail } } 与使用boolean相比: B.1 public boolean myLowerLevelMethod(int id) { ... int …

2
使用包(宝石,鸡蛋等)创建解耦的架构
主要问题 眼看着良好的支持最先进的编程平台有包管理(想想gem,npm,pip,等),它是有意义的设计应用程序或系统由内部开发的软件包,从而促进并创建一个松散耦合的架构? 例 这样的一个示例是创建用于数据库访问以及用于身份验证和系统其他组件的软件包。当然,这些也使用外部程序包。然后,您的系统导入并使用这些软件包-而不是将其代码包含在自己的代码库中。 注意事项 对我来说,这似乎可以促进代码去耦并提高可维护性,几乎是一种基于Web的桌面应用程序方式(更新几乎是自动应用的,单一功能的单一代码库,等等)。 这看起来像是一个合理而理智的设计概念吗?如今,这实际上已用作构建应用程序的标准方法吗?

1
面向单个开发人员的极限编程[关闭]
已关闭。这个问题需要更加集中。它当前不接受答案。 想改善这个问题吗?更新问题,使其仅通过编辑此帖子来关注一个问题。 4年前关闭。 在过去的两周中,我一直在研究一些基本的极限编程概念,用于小型,营利,多人,街机游戏。我花了一个星期来开发用户故事并确定创建发布计划的要求。我还花了一周的时间编码并应用我想出的第一个迭代计划。我已经确定了一些对于单个开发人员有用的概念。 持续集成 永远不要尽早添加功能 测试驱动开发 选择一个系统隐喻 使用单个集成点 测试所有错误 不断重构 设定可持续的步伐 简单 频繁发布 我很好奇我是否缺少特别适合与单个开发人员项目一起工作的任何东西? 同样,鉴于这种简单性和测试驱动开发的思想,使用建立的,功能丰富的,现成的平台更好吗? 还是应该在可行的情况下从头开始工作,以避免遇到规则不断提出的问题,例如不断进行重构并且永远不要尽早添加功能?

2
当我们将计算与副作用分开时,我们将“询问世界”的代码放在哪里?
根据命令查询分离原则,以及使用Clojure演示的“ 数据中的思考”和“ DDD”,应将副作用(修改世界)与计算和决策分开,以便更容易理解和测试这两个部分。 这就留下了一个悬而未决的问题:我们应该把“问世界”放在边界的哪个位置?一方面,从外部系统(例如数据库,扩展服务的API等)请求数据不是参照透明的,因此不应与纯计算和决策代码放在一起。另一方面,将它们从计算部分中分离出来并作为参数传递是有问题的,甚至是不可能的,因为因为我们可能事先不知道可能需要请求哪些数据。

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.