理解编程的世界

今年3月份开始,我开始做一个强技术导向性的产品工作。这个产品更强调技术的能力满足了用户的需求,因此,在产品的开发过程中,需要让产品的使用流程适配技术的需求,同时兼顾一些用户的体验。

做这种产品工作,比较大的挑战在于理解技术的原理。只有在了解后端的技术实现逻辑后,前端的产品设计才能进行。

我技术背景不强(近乎于无),刚接手时还挺懵。但还好,过了几月后,通过最有效地学习方式——边干活边学习,盲人摸象式地由点及面摸索,现在也算是上手了。

同时,由于这个产品是一个偏向基础能力层的应用,因此横向与各个业务线同学对接的需求也非常多。

所以在过去的几个月里,密集地接触了各个部门的许多研发同学,他们在工作角色的定义上,是将产品的需求用代码予以实现。

一开始,我其实感觉和研发同学有沟通上的一些障碍,感觉他们说的话,我听不懂。

但很神奇,有一天我突然感觉自己开窍了。起因是一位搜索的研发同学,给我解释为什么搜索的技术无法实现某一个产品需求。

这位研发老师非常资深,他直接给我共享了一个文档,带着我看了一遍代码的实现逻辑,非常清晰,我很快理解了原先的问题。同时,也开始有了一点点对程序员mindset的领悟。

以下是我的实践与思考,欢迎交流。

黑客与画家的共同之处,在于他们都是创作者。与作曲家、建筑师和作家一样,黑客和画家都试图创作出优秀的作品。

——Paul Graham《黑客与画家》

1 产品语言和研发语言

我对于编程语言的理解主要来自于半吊子的自学,和之前的一点点工作经验。

But the gift for a beginner is fresh eyes.

在实际的工作场域中,产品的语言和研发的语言在逻辑上有着很大的差异。产品倾向于用场景化的语言来描述需求,而研发常常使用的是条件式的语言来实现需求。

举个例子:现在一个页面上有两个卡片,这两个卡片有各自展示的逻辑。

产品的场景化表述需求为:

在产品的表述中,穷尽了所有用户的可能的行为,并对所有的行为下不同的产品表现做出了描述。

而到了研发同学开发的时候,他们会用另一套条件式、命令式的代码语言来实现这个需求。

该页面共有以下4种展示的形式,分别的判断标准是:

这正如,Paul Graham 在《黑客与画家》中写的:

“所有机器都有一张操作命令清单,让你可以控制它。有时这个清单非常简短。电水壶就只允许两种操作:打开和关闭。CD播放器稍微复杂点,除了打开和关闭以外,还能调节音量、播放、暂停、快进、快退和随机播放等。

计算机和其他机器一样,也有一张操作命令清单。比如,可以命令计算机把两个数相加。这种操作命令的总和就是计算机的机器语言。”

在感知到了这种思维逻辑上的差异后,我在产品的设计和沟通过程中,有了一些思维上的些许变化。

一方面,是在写PRD(产品需求文档)的时候。当我穷尽罗列了所有某一场景的case后,我会自动代入研发的视角,思考一下他们在实现的时候,判断的条件是什么样的。

我通常在写完具体的场景化需求后,会用另一套代码式的语言,用条件判断式的语言体系再转换一下表述。这样做的好处在于,研发同学在看需求文档的时候,可以对判断的逻辑更清晰,同时这样做也可以对研发的开发工作量和难度能有轻微的判断。

其次,在与研发同学沟通的时候,尝试着用他们的语言体系来沟通,也更加顺畅了。在很多次与研发同学的需求评审会上,我都感受到他们在看需求文档的时候,脑子里其实都在转译——把文字转换为代码。

他们会提出的很多基于需求实现逻辑上的询问:判断条件是什么?传参是什么?库里有没有某种状态?…..

这个时候,其实如果我能跟着他们的思维和技术的逻辑来与他们沟通,甚至帮助他们来思考判断的逻辑,彼此的沟通就会更加有效率。

2 如果将代码视为一种媒介?

在传播学的理论中,麦克卢汉的「媒介即讯息」广为人知。其核心观点为:相较于内容而言,媒介本身才是最有价值的讯息。

抽象地来看,代码也可以作为内容表达的一种实现方式、一种媒介。它自有框架体系,有不同的语言,有传达的方式,它被世界上成千上万地程序员们使用来创造出互联网上形形色色的应用。

那么如果我们将其视作一种媒介,这种媒介的形式在传达什么样的讯息?这种媒介本身有着什么样的特点?那些每天都用使用这种媒介的人,他们被这种媒介塑造了什么样的mindset呢?

从一个局外人的角度,我能感受到的是,代码塑造的信息和mindset是这样的:

(1)强调精确

Paul Graham 在《黑客与画家》中写道:

“任何一种编程语言都可以分成两大组成部分:基本运算符的集合(扮演公理的角色)以及除运算符以外的其他部分(原则上,这个部分可以用基本运算符表达出来)。”

感觉写代码,就像解数学题,只不过使用代码的形式在解题。数学是强调精确的,代码也一样。程序员们使用指令性语言来解决问题,代码中的输入和输出一定要准确无误,就算错了一个符号都会使整个程序出现bug。

(2)整体思维更加线性

代码是清晰的指令性语言和判断式语言,而我接触的很多程序员同学身上,也能很直观地感受到这种更加线性思维。

最直接的例子是,前两天我和我的前端工程师和后端工程师讨论一个很小的产品的逻辑:

界面上一个名称框,支持编辑名称,有重名校验的逻辑。编辑名称后,有「取消」和「保存」两个按钮。当用户点击名称编辑框后,但并未修改名称,此时点击「保存」,是否需要使用重名校验逻辑报错。

我的想法是,用户如果没有修改名称,点击「保存」,此时不应该出现重名校验逻辑。因为,事实上,它并没有和其他名称重名,只是和自己重名了。

但是我的前端和后端研发工程师都认为,如果用户没有修改名称,用户就不该点击「保存」,而应该点击「取消」,因此不存在点击「保存」却没有修改的场景。

我当时其实很敏感地发现了,我们思维上的不同。代码的思维是非常线性且直接的,修改了名字点击保存,不修改名字点击取消。但实际上,用户在编辑名称的时候,很可能会出现不修改但保存的场景,此时如果出现重名校验的报错,是不符合产品逻辑的。

我感觉这是一个很典型的思维比较线性的例子,产品在其中的角色会更加用户视角一些,会考虑到这个用户的操作可能性是什么样的。

线性的思维符合代码的书写逻辑,但是在产品的视角上,太过线性,却容易忽视用户多样操作可能性的场景。

(3)强调Problem-solving:从定义问题到解决问题中间,有详细地问题拆解和解决方案的拆解

每一个产品需求,都可以看作是一个问题,有小问题和大问题。解决小问题,用少量的步骤,少量的代码。解决大问题,则需要拆分更多步骤,每一个步骤成为新的小问题,仍然用一连串的指令代码来解决。

在实际的产品研发过程中,当产品与研发同学开完产品需求评审会后,研发同学就会开始写技术文档,Product Technology Documents(PTD)。

在PTD中,技术同学会把一个整体的产品需求,拆分为许多技术实现的模块。这个过程,技术负责人就像一个工程师,把要建造的一个建筑拆解为不同模块的工程,有的人负责打地基,有的人负责凿窗户,有的人负责装空调。

这其实和许多项目管理的思维也有一致性,把一个大的项目,拆解为一步一步可实现的小项目,安排到人去实现每一个小项目。

3 对代码思维的感知途径,从自身经验谈谈

我记得,在几年前,一个长久被讨论和询问的问题是:产品经理是否需要懂技术?甚至,我自己刚做PM时,都挺疑惑。

这个问题,让现在做强技术属性的产品经理的我来回答的话,可能答案是这样:有技术的背景当然是最好的,没有也没啥关系。因为,一旦开始做了,就会慢慢懂一点技术了。

不懂技术上手确实会难一些,主要是代码的世界有一套自成体系的框架,如果对这套框架毫不知晓,确实会言不知所以。但是只要对这套框架形成感性的认知,技术局限便是有限的,更重要的是如何将技术为产品所用,用产品满足用户的需求。

如果让我来复盘,两年前对计算机技术一无所知的我,是盲人摸象式慢慢建立起来一点认知的,我觉得可能有以下几点:

首先是工作一直在与技术频繁地打交道。感觉在工作中学习确实是学习最快的途径,比如,学习用SQL去数仓里查数据,知道了数据库的基本形态(学习材料是《深入浅出SQL》);学会用Json来实现前端界面的显示配置,知道了前端界面大概是怎么用代码实现的。

我现在的工作技术属性也蛮强的。我感觉得到我终于入门明白这产品到底是咋回事的时候,是我的leader让我写完我负责的产品的All in one文档的时候。把产品的每一个技术环节都问清楚研发同学,同时用文字表达清楚后,我终于感觉到上手了==。

其次是,读了一些书,当然读的都是入门书哈,比如《给产品经理讲技术》《云计算通俗讲义》这种,能比较快地以框架性的方式懂一些基本知识。

同时,自己也学习了一点点怎么写代码。此处,我觉得很多我的人文社科的朋友们都几乎人手一本《Python编程:从入门到实践》,我也有一本==。但我觉得如果没有很强的应用目的,很厚一本真的很难学下去。

我感觉对我来说,最好玩最有用的使用苹果的Playgrounds来学习Swift语言。因为,我不需要真的去做程序员的工作,我所需要的只是理解代码的实现方式。这个教程做得很好,循序渐进,有框架,直接动手,也很有趣味性。