Go 的编程思想是什么?

2019-03-07 11:08:13 +08:00
 index90

一直 OOP,换到 Go 也是用 OOP 思想,但总感觉很别扭啊。 有没有什么指引?

13004 次点击
所在节点    Go 编程语言
94 条回复
ChristopherWu
2019-03-08 10:27:53 +08:00
go 的编程思想是 : `if va, err = Myfunc(); err != nil ` 对所有的错误进行检查,那么你的程序就是无懈可击的对啦,try catch 就是垃圾 🐶🐶 /doge
specita
2019-03-08 10:37:18 +08:00
之前看过一篇博客说到了 java 和 go 在编程思想上的差别会导致两者代码在处理相同问题上的不同思路,记得主要就是说并发处理方面基于通信和基于内存差别?写了一年 go 又滚回来写 java 了,orz~~
index90
2019-03-08 10:38:05 +08:00
@abcbuzhiming 茅塞顿开,感谢。看来需要回归本源,重新学习编程
index90
2019-03-08 10:40:28 +08:00
@specita 是哪篇文章,烦请分享一下链接
Linxing
2019-03-08 10:57:23 +08:00
如果还是 OOP 的思想 写起来很难受的 毕业之后除了 Java 就基本没写过 OOP 的东西了 都是面向接口
gxm44
2019-03-08 11:08:26 +08:00
@wweir 说的很中肯,包管理一直是 go 的痛点。
abcbuzhiming
2019-03-08 11:15:45 +08:00
@gowk

程序设计有一个范式( paradigm )问题。所谓范式,就是组织程序的基本思想,而这个基本思想,反映了程序设计者对程序的一个基本的哲学观,也就是说,他认为程序的本质是什么,他认为一个大的程序是由什么组成的。这和他对于现实世界的看法有关。显然,这样的看法不可能有很多种。编程作为一门行业,独立存在快 60 年了,但是所出现的范式不过三种——过程范式、函数范式、对象范式。其中函数范式与现实世界差距比较大——真的纯函数范式在目前的编程实践中其实很少有,绝大部分语言只是取了函数范式的一个子集,即可以把函数作为参数传递,不过这并不是函数范式的核心,在这里不多讨论,只谈一个历史趣闻,有兴趣的可以自行去进一步查资料:当年的大牛们认为,Haskell 是“美丽的,聪明的”设计,C 语言是“丑陋的,简陋的”设计,然而最后占据了世界主流的却是“丑陋的,简陋的”的设计。

而过程范式和对象范式可以视为对程序本质的两种根本不同的看法,而且能够分别在现实世界中找到相应的映射。

过程范式认为,程序是由一个又一个过程经过顺序、选择和循环的结构组合而成。反映在现实世界,过程范式体现了劳动分工之前“全能人”的工作特点——所有的事情都能干,所有的资源都是我的,只不过得具体的事情得一步步地来做。

对象范式则反映了劳动分工之后的团队协作的工作特点——每个人各有所长,各司其职,有各自的私有资源,工件和信息在人们之间彼此传递,最后完成工作。因此,对象范式也就形成了自己对程序的看法——程序是由一组对象组成,这些对象各有所能,通过消息传递实现协作。

对象范式与过程范式相比,有三个突出的优势,第一,由于实现了逻辑上的分工,降低了大规模程序的开发难度。第二,灵活性更好——若干对象在一起,可以灵活组合,可以以不同的方式协作,完成不同的任务,也可以灵活的替换和升级。第三,对象范式更加适应图形化、网络化、消息驱动的现代计算环境。

重复一遍对象范式的两个基本观念:

程序是由对象组成的;
对象之间互相发送消息,协作完成任务;

这就是对象范式的核心,并没有规定对象的标准,这里的对象只是一个抽象的概念,人为划定的,包含一定职责和功能的组件。对象之间互相“发消息”其实也只是一个抽象的概念,并没有规定“发消息”这一行为究竟该是什么样的,核心问题就在这里,这里埋下了一个大坑,为后来面向对象变成被扭曲成面向类编程留下了一个悬念。

历史没有假设,把 OOP 应用于编程语言实践并第一个“获得广泛成功”的语言是 C++,而上面说了,C++是基于 Simula 的思想,Simula 认为“发消息”是什么样的操作呢?向一个 Simula 对象中发送消息,就是调用这个对象的一个方法,或者称成员函数。那么你怎么知道能够在这个对象上调用这个成员函数呢?或者说,你怎么知道能够向这个对象发送某个消息呢?这就要求你必须确保这个对象具有合适的类型(方法),也就是说,你得先知道,哦这个对象是什么(类),才能向它发消息。而消息的实现方式被直接处理为成员函数调用,或虚函数调用。

而另外一边的 Smalltalk 在这一点上做了一个历史性的跨越,它实现了一个与目标对象无关的消息发送机制,不管那个对象是谁,也不管它是不是能正确的处理一个消息,作为发送消息的对象来说,可以毫无顾忌地抓住一个对象就发消息过去。接到消息的对象,要尝试理解这个消息,并最后调用自己的过程来处理消息。如果这个消息能被处理,那个对象自然会处理好,如果不能被处理,Smalltalk 系统会向消息的发送者回传一个 doesNotUnderstand 消息,予以通知。对象不用关心消息是如何传递给另一个对象的,传递过程被分离出来(而不是像 Simula 那样明确地被以成员函数调用的方式实现),可以是在内存中复制,也可以是进程间通讯。到了 Smalltalk-80 时,消息传递甚至可以跨越网络。所以各位,其实和消息队列类似的功能当年就已经存在了,消息队列 1 是为了解耦,2 是为了削峰错流,某种程度上消息队列不是实时的,然而 Smalltalk 的消息机制,某种程度上可以视为实时的。这也是它的先进性所在,我们希望解耦,但是我们不需要延迟。

很可惜,历史没有假设,Smalltalk 的直系继承者 Object-C 被 Steve Jobs 收入苹果公司,很长一段时间没有和公众见面。后来有一个也利用了该思想的专门为电信级通讯设计的语言 erlang,Actor 模式由它定义,其实就是那套消息机制,然而 erlang 是少见的纯函数式编程的语言,接受的人不多,也没流行开来。

后来就和大家知道的那样,因为 C++的流行,导致“类”这个概念变的无比重要,毕竟你要先知道对象的“类”,你才能确定,我能不能发消息给这个对象。于是类的概念变成了第一要素,OOP 至此被扭曲为 COP ( Class Oriented Programming,面向类程序设计)。

客观地说,“面向类的设计”并不是没有意义。来源于实践又高于实践的抽象和概念,往往能更有力地把握住现实世界的本质,比如 MVC 架构,就是这样的有力的抽象。但是这种抽象,应该是来源于长期最佳实践的总结和提高,而不是面对问题时主要的解决思路。过于强调这种抽象,无异于假定程序员各个都是哲学家,具有对现实世界准确而深刻的抽象能力,当然是不符合实际情况的。结果呢,刚学习面向对象没几天的程序员,对眼前鲜活的对象世界视而不见,一个个都煞有介事地去搞哲学冥想,企图越过现实世界,去抽象出其背后本质,当然败得很惨。

但是学术界一向高傲,传统上学术界一直都是理论定义的先驱,负有“指导众生”的义务,所以学术界仍然坚持这套基于类的 OOP 概念,但是工程界自从发现基于类的抽象其实对程序员的心智负担过高后,组合优于继承的思想就开始深入人心了。对象才是第一要素,对象并不依赖于类,对象的组合方式是彼此发消息,彼此发消息的方式也可以不依赖类,就算是传承自 C++的 Java 也搞出了接口这种方式——其实这种方式距离抛弃类就只有一步之遥了,我要知道对象有没有方法让我发消息,我检查接口定义就行了,我为啥需要类,Java 需要类来制造对象是历史惯性,不是必须。

历史让 C++走上了舞台,历史也终将让 COP 重新回到 OOP 的本来面目
gowk
2019-03-08 12:39:44 +08:00
@abcbuzhiming 茅塞顿开,感谢回复。如果能有这方面的书推荐一下就更好了。
abcbuzhiming
2019-03-08 13:01:49 +08:00
@gowk 没有书可以推荐,因为绝大部分技术书籍基本不讲技术历史,其实我是个对技术历史脉络比技术本身还感兴趣的人,年轻时精力好,在那个博客发达的时代到处翻人家写的点滴记录,有了这么点积累而已。其实我也万分的想让别人给我推荐讲技术历史脉络的书籍,然而这类书真心罕见
passerbytiny
2019-03-08 13:03:36 +08:00
@abcbuzhiming #36 虽然你说的绝大部分都是对的,但你这一棍子打死类、继承的态度,跟你所批判的“面向类变成的态度”,有什么区别。

再看你接下来的描述,感觉你有这么一种思路:直接去做东西,不做或者后做模子,先做模子再按照模子做东西的都是 S13。
passerbytiny
2019-03-08 13:09:08 +08:00
@wweir #10 你这个“二十万行”的规格太离谱了。举个例子,一万行代码、没有设计模式的项目,1.0 版本你准备花多长时间评审和单元测试,1.0-1.1 版本准备花多长时间,1.21-2.0 版本又准备花多长时间。
shayuvpn0001
2019-03-08 13:28:57 +08:00
@abcbuzhiming 这几个长回复真心不错,解决了长久以来我对各种语言的来龙去脉的困惑。介绍硬件发展和软件公司发展的文章很多,语言这一块很少,而且大多都是围绕大家耳熟能详的几个语言的来龙去脉介绍,小众一点的几乎没看到过完整的介绍,今天算是看到了 the big picture。
zwpaper
2019-03-08 13:39:31 +08:00
@abcbuzhiming 最后一段,组合比继承更重要,有参考的资料或者文章吗?想多了解一下

谢谢
dengtongcai
2019-03-08 13:59:43 +08:00
说下我的经验+愚见:设计->按设计编码->微调设计
abcbuzhiming
2019-03-08 14:01:55 +08:00
@passerbytiny 我没有一棍子打死类和继承,我只是强调类和继承不是 OOP 必须的而已。另外,基于哲学的抽象领域,类有很高的价值,这也是为啥类和继承这套体系在学术界仍然相当有地位的原因,但是绝大部分程序员,只是凡人,程序的本来目的,其实也是为了让大部分凡人能够利用计算机编程这一工具而已。曲太高,和就寡。我里面提到设计的更好的 Haskell 并没有被广而接受,而被设计的并不优秀的 C 语言成了历史的选择,就是例子
abcbuzhiming
2019-03-08 14:02:37 +08:00
@zwpaper 1995 年出版的经典作品《 Design Patterns 》中,建议优先考虑组合而不是继承
wweir
2019-03-08 14:34:05 +08:00
@passerbytiny 是离谱的,对 go 而言,10 万行就已经是巨型的项目了,为了避免到处是杠精,才说的 20w 行。
就我自身而言,3、4 万行的代码还能 hold 住,再多的话,没优秀的封装、模块化,根本进行不下去。
bsg1992
2019-03-08 14:46:39 +08:00
@blless 你说的那些除了 代码规范 go 是自带的,其他的.NET 都有 也不比你差啊。
wind3110991
2019-03-08 14:54:22 +08:00
@wweir loraserver 感觉算是比较大的项目了,不过我一直觉得行数多少不是问题,主要是结构和思想够不够清晰和简洁
https://github.com/brocaar/loraserver
est
2019-03-08 14:55:38 +08:00
golang 的思想就是 interface 一把梭。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/542022

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX