正确的编程姿势

近年六个星期,我利用 plantuml (贝尔(Bell)实验室出品了一个最佳绘图工具
graphviz,
这是一个包装版)把自家的绘图项目做了一次周全的接口和类的可视化。使用了诸多设计格局,包括:桥接、装饰器、生成器、抽象工厂。绘制完后,图像是很美的,接口之间的相互和参数定义清晰优雅。很美观!

然并卵!

那个项目在支付之处已经违背了自我的一对感觉到,对于程序设计的感到。从我对数据库和服务器的多年经历,使用基于数据表和数码表达的空洞结构,你总能拿到最简单易行易用可扩充的软件结构。

可是,这几个绘图项目确实很复杂,涉及了重重的多态和关系。比如,在一个长的列表中储存系列不一的图样,那多少个图片存储的绘图数据和血脉相通信息都不比,我急需把这多少个数据视做同一序列型,然后迭代它们,选出需要的一个而且利用它的有关音信。所以,我尝试运用学术界的设计情势来缓解之中的问题。

当项目变得很巨大的时候,我意识到设计形式屁都不是。诸如桥接、装饰器以及其他,都是起家在一种如果,若是你的父组件和子组件总是可以忽略对方的底细,而得以统一的拍卖它们。比如,面包有奶油味、抹茶味、水果味,面包又有起码材料、高档材料,那么您可以把味道和素材分为两个不同的接口,然后分别抽象,并且结合这六个接口生成更增长的面包,比如低档材料的抹茶味面包。不过,真实的编程世界中,那样的美观图景分外少。在实际的编程世界中,面包还想要更多的东西,比如奶油味的有糖,抹茶味的没有糖,有糖的面包放在左侧柜台上,没有糖的面包放在左边柜台上。看到了啊,复杂度升级了,柜台跟面包有没有糖是绑定的。这表示,倘若您想像前面那么抽象六个接口—味道和素材,这您现在必须考虑柜台。因为低档材料的抹茶味面包是未曾糖的,放在右侧柜台。现在,你不得不抽象出味道和柜台的涉及。在地点的接口之上再追加一层。每当你的要求复杂一点,这种层就会提高。比如,红糖面包和白糖面包。

总的说来,固然设计情势避免了类继承的爆裂,可是也防止不了抽象层级的繁杂。

于是,我认为自家又不会编程了。于是,我尽可能的重新思考这多少个规划,并且重新在网络上寻找曾经协理自己的规划论调:面向数据结构编程而不是目的。假使不是为着这些绘图项目,我相对不会铤而走险再两次使用设计情势和面向对象。

自身当然搜到了一大堆 Linus 排斥面向对象和 C++ Java
的话语,从感觉上,这么些就是自个儿面临设计困难时候的感到。我已经无数次这样解决自己的主次设计。

git的计划性其实特另外简短,它的数据结构很平稳,并且有抬高的文档描述。事实上,我充分的同情应该围绕我们的数据结构来统筹代码,而不是按照此外的,我觉着那也是git之所以成功的原故之一。[…]
依我的见识,好程序员和烂程序员之间的差别就在于他们以为是代码更首要如故数据结构更要紧。

在高大的品类中,人们对不是友善开发的模块并不精通,能很快了解其他模块中函数的适当含义才能增高支付功效。而C++引入的各个抽象则使代码相当依赖上下文,想清楚一段代码,需要看多得多的上下文。

面向对象语言以目的为大旨,加一些相关联的措施,简直是呓语。首要的事物应该是数据结构,对象自我有什么首要?真正有意思的,是在不同序列的例外目的交互而且有锁规则的时候。但是,即便是此时,封装什么“对象接口”也相对大错特错,因为不再是单纯对象的问题了。

有意思的是,这里有一篇此外一位长辈的很早的文字,推在 Google+ 上,来自 Unix
核心创立者之一 Rob 派克(Pike):

原稿链接
A few years ago I saw this page:
http://www.csis.pace.edu/~bergin/patterns/ppoop.html

Local discussion focused on figuring out whether this was a joke or
not. For a while, we felt it had to be even though we knew it wasn’t.
Today I’m willing to admit the authors believe what is written there.
They are sincere.

But… I’d call myself a hacker, at least in their terminology, yet my
solution isn’t there. Just search a small table! No objects required.
Trivial design, easy to extend, and cleaner than anything they
present. Their “hacker solution” is clumsy and verbose. Everything
else on this page seems either crazy or willfully obtuse. The lesson
drawn at the end feels like misguided epistemology, not technological
insight.

It has become clear that OO zealots are afraid of data. They prefer
statements or constructors to initialized tables. They won’t write
table-driven tests. Why is this? What mindset makes a multilevel type
hierarchy with layered abstractions better than searching a three-line
table? I once heard someone say he felt his job was to remove all
while loops from everyone’s code, replacing them with object stuff.
Wat?

But there’s good news. The era of hierarchy-driven, keyword-heavy,
colored-ribbons-in-your-textook orthodoxy seems past its peak. More
people are talking about composition being a better design principle
than inheritance. And there are even some willing to point at the
naked emperor; see
http://prog21.dadgum.com/156.html
for example. There are others. Or perhaps it’s just that the old guard
is reasserting itself.

Object-oriented programming, whose essence is nothing more than
programming using data with associated behaviors, is a powerful idea.
It truly is. But it’s not always the best idea. And it is not well
served by the epistemology heaped upon it.

Sometimes data is just data and functions are just functions.

— Rob Pike (One of the Unix creators (Ken Thompson, Dennis M.
Ritche, and Rob Pike))

几年前自己来看了这多少个网页:
http://www.csis.pace.edu/~bergin/patterns/ppoop.html

本身的确不了解这篇作品到底是不是在搞笑。读了一晃,我尽管很想说这不是一篇搞笑的篇章,但是,拜托,它根本就是。让自身来跟你们讲讲他们在搞笑什么吗。

e…依照他们的言语,我应该称自己为 hacker
(黑客),不管我不珍贵那个。Hello! 你只需要一个小的不能够再小的 table

根本不需要哪些目的。朴素平凡,容易扩充,容易清除,(比起他们的这种设计)多
TM 简单。他们的 “hacker solution”
真的是又蠢又笨。他们写出来的这堆东西到处透漏着疯狂和愚昧。他们不够技术认知。

很醒目,OO 的狂热者们提心吊胆数据。他们欣赏用言语或者协会器来起初化 tables
。他们根本不写 table-driven 的测试。Why is this?
得有多大的心才会采纳用一类别并且多层的类华而不实,而不去用一个纤维三行
table ? 我已经听说有人用各类 OO 的事物替换掉 while 循环。

而是好新闻是,hierarchy-driven, keyword-heavy,
colored-ribbons-in-your-textook orthodoxy
这个东东快绝望了。更多的人摘取组合而不是继承。有些人早就重复起始认识
OO。

面向对象编程语言,其本意是使用数据和有关的表现举行编程,那是一个很好的想法。事实当真如此。可是,这么些想法并不连续最好的
idea。 这些想法并不曾完全的咀嚼编程的世界。

Sometimes data is just data and functions are just functions.

— Rob Pike (Unix 创立者之一的 (Ken 汤普森(Thompson), Dennis M. Ritche, and
Rob Pike))

毋庸置疑,大家需要的就是数额的空洞和多少的解释器。用表来存储你需要的逐一数据,对于多态,C
语言中简易间接干净:union。使用这样一个概括的协会,你能储存各类不同的连串,而且你只需要仓储他们的指针,这意味着你不会浪费多少内存,同时你能博得一致内存段可是多少不同的肤浅。

接下来,使用一个链表或者数组,把那么些 union
装进去,遍历,cast,然后利用你需要的一定数据。

重重言语都有 union 的变体,现代语言中的泛型就是 union
的一种语法糖,不过你往往忘记了那种布局的确实价值和企图。仔细回味下这多少个全新的统筹:

enum ShapeKind {
  skLINE, skPORT, skBOARD
}

class Shape {
  kind: ShapeKind   
  value: Line | Port | Board
  contains(x: number, y: number): boolean
}

class ShapeContainer {
  shapes: Array<Shape>
  search(x: number, y: number): [ShapeKind, Shape]
}

type
  ShapeKind = enum
    skLINE, skPORT, skBOARD

  Shape = ref object
    case kind: ShapeKind
    of skLINE:
      line: Line
    of skPORT:
      port: Port
    of skBOARD:
      board: Board
    contains: (x: number, y: number): bool

  ShapeContainer = object
    shapes: seq[Shape]

proc search(c: ShapeContainer, x: number, y: number): tuple[kind: ShapeKind, shape: Shape]