最佳实践 - 编码前设计

时间:2008-12-17 08:34:33

标签: architecture

我很好奇你们怎么想? (我的意思是一种思考方式)关于你的图书馆,系统,框架等的设计架构,然后再开始编码。

我最近发现自己在做的事情上感到很痛苦,实际上每次我都想从头开始做任何事情。

我之前做过设计,在纸上绘制一些方案并想象它是如何工作的,但也许我是以错误的方式做到的?

例如,您如何确定所需的接口,以及如何以最佳方式连接所有接口?

(前一天我遇到了一个问题,我的朋友问我一个库,我前段时间做了什么,而不是只给他一个文件,我不得不给他约3-4个文件,那是因为他们以某种方式连接......但我认为不是正确的:)所以这是我在设计上的错误..)

11 个答案:

答案 0 :(得分:29)

我通常对纸张/白板上的问题域进行足够的分析,以便对问题域有足够的了解,开始编写代码。我很少在纸上绘制实现或类图。我发现实现更好设计的关键技术是不要太依赖你编写的代码。如果我不喜欢它,我会删除,重命名,移动和随机播放它,直到它表达了我正在尝试解决的问题的足够好的解决方案。听起来很容易?一点也不!但是使用良好的“编码”工具,实际编写代码并不是主要的努力。写一些,重构,删除,再写一次......

好的设计几乎从未开始好。 它发展得很好。接受这一点可以让您更轻松地在小步骤中工作而不会感到沮丧为什么设计不“完美”。为了使这个过程发挥作用,你必须拥有良好的设计技能。重点是,即使优秀的设计师也不会在第一时间做到正确。

很多时候,当我开始时,我以为我理解了问题域,但我没有。然后我回到白板,与某人交谈或阅读问题域,如果我发现我不太了解它。然后我回到代码。

这是一个非常迭代的过程。

在处理程序员如何思考时,一个有趣的问题是他们如何发展他们的思维方式。就个人而言,我的思维方式多年来不断发展,但是一些事件对我开发软件的方式产生了深远的影响。其中最重要的是与专家设计人员一起设计软件。没有什么比对伟大的设计师进行迭代更能影响我了。另一个事件已经并且仍然会影响我的思考方式,看看我写回来的软件。

答案 1 :(得分:6)

对于面向对象的方法,我发现离开用户界面一般是一个好主意,并关注系统中将存在哪些实体(对象),以及适当的属性和操作。

在白板或大纸上绘图,使用不同的颜色来识别各种特征也是一个好主意。便利贴也是一种可视化模型的好方法。

即使我花了很多时间仔细考虑设计,我也总是随着时间的推移改变它。因此,请记住,在您决定如何记录设计时,您的设计会发生变化。

答案 2 :(得分:5)

我主要从一盒卡开始,写下我想要建模的域的概念。有时我会使用思维导图。

了解利益相关者以及他们想要实现的目标。从那里开始是很重要的,因为它允许您正确地确定优先级(即不是在最有趣的技术部分,而是在具有最大商业价值的部分)

关于设计的思考大多写在测试中。写在代码之前实现它。从利益相关者的最终目标开始,从那里开始向后工作(时间倒置)。这可以确保您专注于什么,而不是如何。对象之间的交互比对象属性更重要。

另一部分主要是在白板上。如今,紧凑型数码相机是标准配置。

在有三个需要它的实现之前做一个框架是一种不好的做法。如果必须,请为重要的界面(和实现)更改做好准备。

见:

答案 3 :(得分:4)

我通常花大约2-4个小时来设计我的应用程序,然后将其写在笔记本中。

然后我开始编码,每次事情变得复杂(因为某些东西不在正确的地方)我重构。将一个类移动到另一个包,或提取方法等。当“设计”感觉正确时,我可以继续前进。

通过这种方式,我可以避免“分析瘫痪”,这种情况很常见。很多时候,当我超前设计时,我最终没有使用一些工件。

因此我采用了这种更“敏捷”的方法。

快速绘制设计并在运行中“细化”(通过重构)。

当然,这适用于小型应用程序(2至4周)

我建议你读一下这篇文章:来自Martin Fowler的Is design dead。它有点冗长但值得一读。

修改

Joshua Bloch的附加链接(略微偏离主题) How to design a good API and why it matters。当您拥有API的受众时,请讨论设计的相关性。总结,尽可能私密,并从那里成长。

答案 4 :(得分:4)

必须保持平衡。

如果你试图在白板上预先设计好大量的图片,那么当它实际编写时,你可能会错过一些细节。

如果你开始攻击系统的某个小部分,你可能会忽视“大局”并最终导致设计不佳。

当您查看库时,您希望它们尽可能地重复使用。因此,对于初始设计,请考虑一下您可以在您已经了解的库的预期用途中的最常见情况 - 在此阶段不要过于担心假设的未来用途可能很好永远不会发生在您了解更多信息并发现设计问题时,使用单元测试和重构对设计进行编码。

尽量将关于图书馆用户的具体知识放入图书馆本身。然后,运气好的话,你最终会得到一些可重复使用的东西,而且下次不会自动想要从头开始。

答案 5 :(得分:4)

我遵循一个非常宽松的Rational Unified Process版本。

首先开始使用一个愿景文档,该文档清楚地说明了您正在尝试做什么,您正在做什么以及可能关于所提议的方法/算法的一些关键细节。它不需要花哨,甚至可以成为简单系统的单线程“根据霍格沃茨学校的最新研究,仅用于个人用途的预测中奖号码的系统。”,对于更复杂的系统,它可以大约五页,但不多了。这不是设计,而是更像愿望清单。

然后做一些用例/故事。这些应该是与外部世界的所有交互的简单自然语言文本描述。极简主义是关键;用例的目的是识别所有必需的功能,并仅识别所需的功能。我也发现这是大多数创造力发生的地方。

用例可能以:

开头
  User presses the "magic" button.
  System displays next weeks winning number.
  User writes down number.
  User buys lottery ticket.
  Lottery draws winning number.
  User claims money
  lottery pays up.

经过多次努力,它最终成为: -

  User presses "magic" button
  System selects next weeks numbers.
  System logs on to lottery system.
  System enters winning numbers.
  Lottery selects winning numbers.
  Lottery transfers winnings to users account.
  User spends money.

完成用例后,您可以启动开发环境,各种类和交互都将落实到位。

答案 6 :(得分:3)

虽然不是对你的问题的完整答案,但我有时会找到最容易进入项目的方法,因为它是找到一小部分孤立的功能来开始并继续工作,同时也考虑到更大的图片。

通过这种方式,您不会对每一个细节都过于痴迷,并且正在提高工作效率并为自己提供喘息的空间,以便了解您需要做什么才能保持清晰。

就像我说的,不是答案。

答案 7 :(得分:2)

问题是当你开始一个新项目时,它往往是新的(现在不是那么明显)。一般来说,一个人不会理解新的东西,除非你是一个非常专业的顾问一遍又一遍地做同样的事情,这听起来有点奇怪......

因为你不可避免地对你制作的系统不熟悉,所以你的设计和代码在第一次出现时并不完美,所以你重申设计和设计。重构代码,直到准备好。

答案 8 :(得分:1)

我更喜欢自下而上的设计。如果没有适用的应用程序框架,我倾向于先组装或构建它。一个好的应用程序框架是可移植的,与应用程序无关,主要解决跨领域问题。它通常包含诸如日志记录,异常处理,验证助手,扩展方法等内容。

从那时起,我喜欢采用大量DDD(领域驱动设计)方法。如果需要,与业务用户面谈以构建域模型。一旦域模型和后续的DAL(数据访问层)得到处理,我就转移到业务逻辑层(BLL)。

我个人试图尽可能地从前端实施中删除,因为它绝对不是我的强项。我喜欢单元测试的一个原因当然是我可以专注于核心功能,并且能够测试该功能而不会过早地进行接口决策。

答案 9 :(得分:0)

打开问题。答案几乎和海报一样多。 1)看看很多软件工程书。一些人认为设计良好,其余部分则很快。这是一个直言不讳的谎言 2)看看多样化的框架是多么的干扰,你最好以预期的方式使用它们,否则你最好再次实现你的需求 3)任何写作都需要不断改变设计。你看到句子,但你觉得它们不完全适合。所以你重写它。因此,每个设计都必须考虑到事情的不同,就像你编写设计一样。

此致 弗里德里希

答案 10 :(得分:0)

在进行游戏开发等重大项目时,我倾向于尝试从一开始就仔细构建我的代码并制作非功能性的虚拟函数和类。从主代码文件中,如果需要,我将所有内容分成其他模块和子模块中的类。例如;我的主要代码页只包含include和调用我的主模块的类初始值设定项。这是我正在用Python制作的游戏的init.py示例;

来自commonheaders import *

if arguements.debug:
    debug.init()

try:
    graphics.init()
    sound.init()
    physics.init()
    input.init()
    loop.start("scene1")
except Exception, e:
    print "Error!"
    print e

它非常简单易懂,但我最喜欢它的是它在各种主要代码方面之间提供了非常明确的分离。如果我对图形课中的某些东西感到沮丧,我可以去声音课或其他东西工作以完成其他工作并将图形遗留一段时间,直到云通过。在所有类init()调用中都有可选的参数,例如图形的widht / height,但我通常将它们放在那里,并将它们设置在commonheaders.py文件中或通过命令行开关。

在考虑我可以剪切并放入其自己的模块之前,我尽量不让任何模块大于100行。它使一切变得更加清洁,当它像这样分裂时,更容易找到你正在寻找的东西。我以前曾经使用过各种开源项目,之前看过几万行中的单个模块......有太多的冗余代码可以很容易地卸载到辅助函数中。我会在必要时使用注释,但我会尽量保持我的代码结构,使您甚至不需要阅读注释。

我真的很喜欢从一开始就构建非功能性框架,因为它很容易看出仍然需要做什么以及在结构方面可以改进什么。最好不要急于写几千行代码,只是为了弄清楚有一种更优雅,更实用的方法,需要对代码进行全面重组。