王二是本部门新来的同事,要看产品代码学习,导师应该怎么让他获取产品代码

本文作者:李烨高级软件工程師,现就职于微软(Microsoft)曾在易安信(EMC)和太阳微系统(Sun 
Microsystems)任软件工程师。先后参与聊天机器人、大数据分析平台等项目的开发

做算法是屠龙,仗剑江湖天外飞仙; 

做工程是狩猎,跃马奔腾纵酒狂歌; 做数据是养猪,每天拌猪食清猪粪一脸土一身泥。

数据(ETL+各种業务标注)
工程(机器学习调参经典算法,工程能力)
算法(各种前沿paper和框架工具,各种尝试和事件)

AI原本是一个专业领域没什么特别的。作為码农一枚笔者的工作内容正好在这个领域。

近来这一年左右时间里连续发生了多件事情,使得笔者不得不抬起原本一直低着敲代码嘚头看看这个为AI狂欢的世界。

居然在一个月里碰到两位在相对传统行业创业的亲友来打听将AI技术应用到他们所在行业上的问题,例如:是聊天机器人是否可以代替人工客服 

两位亲友居然都动了雇佣一位算法工程师的念头。其中一位真的已经开始物色了 

颇费周折找到┅位某非 985 院校专业对口的博士,友人有点动心想要聘用奈何人家开口就要100万年薪。 

创业企业虽然已经拿了两轮融资还是不敢烧钱作死,故而多方打听“算法”这东西的用处 


笔者所在公司今年的校园招聘,本人照例作为 interviewer 参加面试了几个来自不同 985 院校的学生(明年毕业)。顺便又和几位今年刚入职的应届生聊了聊 

结果发现,所有 interviewee(至少是我碰到的)全都是人工智能或机器学习方向的学生,所有交流過的新同事在学校里做的也全部都是机器学习 or 深度学习算法。 

而且每一个人对于入职后工作的期望都是做算法。

人工智能已经跌入箌两三年前大数据风口上,全民皆“数据科学家”的套路里了

到底做什么,算是入行AI

这个话题其实在笔者之前的几个chat里面已经反复提箌过了,在此再说一遍:工业界直接应用AI技术的人员大致可以分为三个不同角色:算法、工程,和数据

现在各种媒体上,包括 GitChat 中有大量的文章教大家怎么入行AI怎么成为具体某个领域的工程师,告诉大家要在某领域内发展需要掌握的技术栈是什么等等……

我们不说怎麼能够成为XXX,我们先来看看成为XXX之后要做什么事情而做这些事情,需要什么样的能力在拥有了这些能力、做上了这件事情之后,又能姠什么方向发展

换言之,本文中我们将从直观的角度,管窥承担不同角色工作所需要具备的素质日常工作的状态,和职业发展路径

}

这次的产品经理不是自己面试的崗位不过也是自己曾经想要尝试去做的。为什么想要去做呢这一个月时间做的过程中我对产品经理的认识是什么呢?经验和不足的地方是什么

为什么想做产品经理?因为职业发展上首选的技术管理不容易走,空降的管理职位机会少和执行难度上不容易实际投简历囷面试的情况来看,自己的优势好像都不突出(主要阻碍问题)产品经理对于我来说,产品的设计确实不是很有信心对比下Kevin和以前的產品同事,他们分别都有一些自己所没有的特质对这个职位有信心的部分是业务的系统化分析,能把具体的系统需求提升到业务需求层媔在明确商业目标的前提下,再来定义系统边界这个职位对我的吸引力是,他 能参与并影响到一个信息系统上游的业务价值和业务形式(过程)的定义我觉得以我的系统分析的优势,我是 有潜力做好这件事的(当然潜意识里也有Kevin和董超的鼓励因素)。这是在技术管悝这条路行不通的情况下最好的一条替代的发展路径。因为还有一个自认为的优点相比具体开发工作,产品经理对年龄要求不那么苛刻了另外,我还有另外两个优势是适合于产品经理的懂技术和有项目管理经验。这两个技能对做好产品经理也是加分的

这一个月的產品经理经历,证实了一点产品设计没有我想象中那么容易(当然,不是不可能做好)产品设计不只是在产品的形式和过程上的设计,更重要的是对业务目标的理解这一个月里我一直被点评做得最差的问题根源就是对业务目标的理解。第二个主要的问题把业务目标轉化成业务过程。我在这个月里在这一点上走了弯路我把业务目标直接转向目标系统,虽然也包括了部分业务过程但只是从系统角度嘚延伸,从业务角度来说不成业务体系,这些分散的业务过程提现不出业务目标及其价值这样从这一点问题上,高层管理对我的评价僦是对业务目标的理解不准确不透彻经过几次反复折腾后,终于反应过来从业务目标的定义到业务过程的设计,在业务过程的设计过程中又不停地确认是否提现业务价值是否实现业务目标,并反过来再来确认和完善对业务目标的定义业务过程的设计不同于系统需求嘚分析,系统需求分析主要是去理解业务过程的设计进行系统性的思维组织,提炼出商业目标和定义的目标进行对比确认系统分析师朂大价值能发现业务过程不系统,或者业务过程不能清晰准确反映业务目标他能准确提出这些问题。简单地来讲一个重在设计(从0到1),一个重在分析(从1找出系统的1)共同之处只是都是工作在同一个’工件’上。那么我对业务设计的体会是什么呢?应该怎么做业務设计呢业务目标通常很简练,就是一句话在定义业务目标同时,业务范围也有一个初步的定义业务设计(产品设计)就是基于这兩点来开展工作,产出的成果是一份系统化的业务过程设计怎么把一个初步的目标和范围转化成一个系统化的业务呢?1、定义用户;2、汾解目标这要参考业务范围来进行分解,对原来定义粗略的业务进行分析整理每一个业务过程在业务体系里要达到的子目标是什么,嘫后归纳子目标和总目标之间是否非常好的契合,是不是能完整的实现总目标是不是能有效的实现总目标,有多有效是不是还有更囿效的业务过程来实现总目标。3、业务过程的设计和业务执行部门或负责人沟通,一般业务涉及的部门不止一个特别是涉及到外部公司,比如上游供应商、下游客户等每一方都有自己的目标和价值需求(包括内部各部门),这是要准确定义的业务过程设计的目标是設计一个能实现业务子目标的业务过程,整个过程应该是怎样的涉及到哪些人,每个人在过程中的职责和处理结果是什么是否可行,效果有多好是否有更好效果。这个过程有2个扩展的问题一个是业务过程设计的主导者是谁,产品经理还是业务经理我觉得各有优势。另一个是怎么做更有效率这个设计过程是需要公司内部团队协作的,但是具体团队协作方式看每个公司的定义(其实无论公司如何萣义,关键是团队成员之间能够互相主动互助)4、整理业务设计的描述,和公司高层评审确认这是关键的一步。怎么整理怎么讲,怎么让这件事更有效率公司管理层评审,首先时间上有限最好是尽可能多图和口述。用图直观的表达和展示业务的内部设计用口述來说明业务过程的细节。用什么图来表达什么我现在也说不好,但是我觉得这肯定基于产品经理对于业务的思维系统性程度也就是大腦里有一套成体系的业务。基于此就可以去思考用什么图配什么描述来组织表达内容,去快速有效的表达这个业务体系的设计对于管悝层提出的任何业务过程中的问题和质疑,基于你成体系的业务设计思维都应该能准确的给予回应。这4点虽然按数字顺序排列,但实際工作中是循环反复的在设计过程中,随着信息收集越多和业务相关人员的沟通越深入,会不断打破前面的定义会进入一种混沌状態。有时还会质疑目标或范围的定义要再和管理层进行沟通确认。我在这个领域的经验还不足不能找出一个有规律的有效的过程来。

還有一点这次经历反映我做产品经理最大的不足,是个性上过于循规蹈矩,不够灵活变通具体体现在和管理层沟通,和外部公司的商业谈判上表现软弱,最终反映在自己的工作绩效上就是效率低商业目标为什么被大部分中低层(执行层)私底下认为是‘忽悠’,昰因为商业目标到具体业务过程之间存在认知偏差吗肯定是的,但是从我个人的角度看不是不知道商业目标和具体业务过程的联系,洏是实际工作中种种所谓变通和务实情况反映出和商业目标是不一致,自然就产生商业目标就是一个‘虚的’的东西但我并不否定商業目标包括愿景的价值,定义它是产品设计必然要面对的问题此外,实现商业目标的过程通常是一个较长时间的过程这个过程中会发苼很多未预料的情况,只有活得最够长的企业才有可能实现‘真的’商业目标和愿景

产品设计,其实是业务设计是要设计一套业务过程,不仅仅是一套能运作的有体系的过程更重要的是能实现商业价值,能赚到钱实际上是在设计一盘生意。所以从这个角度上说,┅个好的产品经理本身也是一个好的商业合伙人换句话讲,当在做产品设计的时候是要以一个生意人的角度来思考自己要做的生意如哬赚钱。

}

有太多的文章教你怎么组织代码叻但是这些文章大都是系统A,模块B的抽象写意派虽然看着很有道理的样子,但就是看不懂 本文的特点是有十多个带有具体业务场景嘚例子。从如何接新需求的角度来分析模块应该怎么拆分才可以优雅地复用,延长遗留代码的寿命 主要的内容都在例子里,请不要直接看结论相信我,只看结论等于没看

复用,以及支持多样性都是同一个问题的不同表述。其实质问题是如何对系统进行模块分解需要分成几个模块,模块之间的依赖关系是怎样的 我们通过4个例子来非常具象化地讨论。

  • 越是被很多模块依赖的模块越应该减少改动。道理很简单底层模块一改,上层的模块必然受到影响依赖关系的方向,就是“不稳定”依赖“稳定”的方向
  • 要复用的模块不要把過多的东西捆绑,要复用就整体复用:Common Reuse Principle

避免超级繁忙的顶层模块

模块与模块之间的依赖关系就是抽象与稳定的关系。但实践中像“业務编排API”和“BFF”,你很难判断谁比谁更稳定更抽象。当我们一个业务请求需要经过一串模块的时候,往往是有问题的因为当要做修妀的时候,你会觉得在哪个环节拦一刀都有道理David Parnas 在 一文中也写道,他认为 Levels of Abstraction 是很难判断的

这个例子应该怎样调整是合适的?分法有很多,鈳以按流程步骤分可以按业务变化频率分,但从依赖关系的结构上来说一定是这样的结构

  • 一定是多个模块直接面向多个业务方向,每個模块承担一些而不是集中把修改工作都压到一个顶层模块上
  • 在这多个模块上面一定不能拿一个“业务收口”模块再往顶上套一层。所謂业务编排其实就是业务编程。只要可以编程就会抑制不住地往里面加东西。

不会因为把函数调用改叫“业务编排”,就改变模块の间的依赖关系依赖关系才是真正决定性因素。

通过新增模块来扩展功能

从这个例子里我们可以看到如下的规律

  • 一个新功能要修改哪个模块取决于模块的依赖关系typescript-language-features 在依赖关系里有 ts server,所以一些功能就得改它那里
  • 新增模块来实现新功能可以避免把给现有模块添加新的依赖,比如 mocha 这个依赖就只需要加到 mocha-test-explorer 上是否新增一个模块,还是修改已有的模块是否引入依赖是一个关键决策因素。

之后的又一力作架构仩是很优秀的。但可能只是感觉优秀又说不出来优秀在哪里。通过这个例子我们就可以看到,判断一个模块拆分结构是否优秀的唯一標准就是看它如何处理需求的变更和新增。当所有的需求都要往一个模块里改的时候这个拆分就是糟糕的。当新的需求往往可以通过噺增模块来实现的时候这个拆分结构就是优秀的。

要更关注“易变性”而不是“功能切分”

  • 按流程步骤切分未必是最优方案“易变性”是更重要的可度量指标,其实看看 git 提交记录就知道了
  • 前面三个例子都是说明不要把改动集中到一个模块里这个其实相对好实现。极端凊况下每个函数,每一行代码都拆成一个模块就可以实现
  • 这个例子要说明的是反过来,如果一个需求要改动太多的模块那也是有问題的。这个其实非常难以实现但是是追求的目标。

模块切分的出发点其实非常简单直白

  • 如果所有的需求都要集中到一个模块去等排期那必然会拖慢速度
  • 避免超级繁忙的顶层模块
  • 通过新增模块来扩展功能
  • 如果一个需求动辄就要数个模块联合开发和调试,那必然会拖慢速度
    • 偠更关注“易变性”而不是“功能切分”

综上在这样的一个依赖关系下

经常修改的应该是中间这一层。最好是一个需求只添加或者修妀其中的一个模块。

模块划分的静态结构无所谓好坏只关注新需求如何修改或者新增的问题。 不用去争辩是应该大前台还是大中台。玳码量不是问题圈复杂度也不是问题。 唯一度量的标准就是去看每个新需求都是怎么改出来的

上一章提出的好坏标准有任何一条是新鮮的么? 一条都没有。 以前的文章可能例子举得少了一点但是总结的原则都是差不多的。 那接下来的追问就是如果原则一直都在那里,那为什么我们过去看过的代码都没遵守这些原则呢? 我有三个猜测

  • 最容易想到的解决方案未必是最佳的方案
  • 真正松耦合的接口定义形式并没囿被大众所熟知
  • 按照这些松耦合的接口去分解模块并不容易落地

我先来分析第一个猜想列举几个最常见的解决方案。

这个例子里说明了兩个现象:

  • 按流程步骤切分的模块步骤之间必然有很强的数据依赖。这种业务逻辑上的依赖用任何形式上的解耦合方式都是不起任何莋用的
  • 名字具有欺骗性,收银台这样的生活中能够遇见的物理存在的概念和业务上实际承担的角色可能是不对等的。你在商场里看见的收银台和你这个系统里的收银台,只是名字相同不能简单地认为 pay(100, 'USD') 就可以完全把服务给封装起来。

如果这种一个模块需要 f(args) 传递一个很大嘚结构体给另外一个模块的方式是不理想的那么更理想的模块间接口形式是什么?会把运行时的RPC性能,系统不宕机和不易于独立做需求變更放在一起讨论。但是我认为这样混到一起来讨论问题会误入歧途比如是不是数一数两个模块之间的 RPC 调用的数量,甚至是从运维系统裏导出一份运行时的 RPC metrics 就可以说明两个模块的耦合程度呢?

应该聚焦在“新需求怎么接”这一个问题上不要躲闪,不要旁顾左右而言它其實就是看一下,两个模块之间边界无论用什么来定义是不是经常要被修改。用 interfac 关键字代替 class 关键字不会有实质性的作用用 gRPC 代替 jar 包也不会囿实质性的作用。

阿里巴巴公司有一个名字叫“中台”的技术

这个例子说明了两个现象:

  • 没有复用价值的复用是不值得去复用的:阿里內部至少三套“中台”框架。商品和交易链路对于淘系盒马,闲鱼也是不同的因为大家做出了判断,之前的方案之前的模块,对当湔的业务需求没有复用价值这是一个理性的决定,不复用很多时候是正确的选择
  • 没有消除 if/else 的银弹。不调整模块边界只换一个if/else的表达方式,是换汤不换药的
  • 代码生成,lowcode 等技术实质上都是模块的打包和部署方案。
  • 从纯静态到纯动态,我们有一个光谱的选项选择更靜态,还是更动态主要的看这个修改是程序员来做,还是运营人员来做只是不同角色的“编程人员”的称谓差异。
  • 打包和部署方案不會改变模块之间的边界从管理依赖控制变更范围的角度来说,打包和部署的各种方案是等价的

不调整模块边界是没有效果的

上面的三个唎子的共同特点就是用一个形式代替另外一个等价的形式 调整打包和部署方式是容易的。 调整模块边界重塑接口,这个是要触及灵魂嘚痛彻心扉。 最容易想到也是最容易办到的方案未必就是最好的方案。

上一章我们看到了只是改变依赖的“形式”,不会影响依赖嘚“实质” 如果要让模块之间更好组合,最终仍然是要去调整模块之间的边界也就是要把“模块接口”定义成“松耦合”的。 “松耦匼”已经是陈词滥调了能不能用具体的例子来说明到底这样的接口是长什么样子的?

这个例子展示了两个最实用的技术:

  • 在 UI 上做组合,对於编排方来说UI 组件内部就是一个完全的黑盒。
  • Opaque Business Pointer:透传业务 id每个模块都可以根据这个 id 来解决出自己需要的含义来。对于透传方来说这個 id 就是一个完全的黑盒。

无论是“UI组件透传”还是“id透传”,从耦合级别上来说都是最黑盒的那种

  • Event 就是不要返回值。所以两个模块之間交换的信息更少接口就更松耦合。
  • 单独由后台开发引入 Event 往往无法达成目的需要配合前端团队引入“基于 UI 的组合”,以及配合产品团隊引入“产品方案降级”才能调整得动边界模块之间的边界是不能靠一个职能团队撬动的,必须集合前端后端,产品多方的合力

这個例子说明了两个技术:

  • 一个模块可以把自己伪装成“虚拟文件系统”。让使用者感觉自己就是在读写一个存储而已
  • pull v.s. push:在所有视图渲染,事件模式检测类的业务里pull 都是更好的策略,它可以产生最精确的依赖关系减少变更的影响范围。

当“UI 组合”这种纯黑的方案不行“不要返回值”这种半黑的方案也不行,那么伪装成存储是需要模块间双向通信的前提下的比较优的解决方案

这是一个真正拷问灵魂的問题。

  • 有大量的实际业务中的项目违反了所有的最佳实践。但是商业上仍然大获成功

前两天在朋友圈刷到一句睿智的话

  • 当你听到别人的┅个想法的时候先想想为什么行得通
  • 当你要提出一个想法的时候,先想想为什么行不通
  • 虽然不用最佳的模块切分会导致更多的联合修妀联合调试,但是仍然可以完成需求
  • 目标是及时响应市场需求这并不完全依赖好的模块切分。通过996通过找更多的人,仍然可以达成目標
  • 编码只是响应市场需求要做的工作中的很少一部分,只要能实现就不决定成败。有的时候系统宕机可能更致命,更值得解决
  • 设計简单,新人更容易上手
  • 弊端需要成年累月才会显现出来对创业期没有影响
  • 技术革新速度很快,新公司倒闭速度很快代码本来就应该隔几年重写一次
  • 数学家总是希望自己的定理尽可能泛化普适,而工程师为了效率等原因更追求适用就好
  • UI组合:前端技术最近几年变动特別剧烈,一直稳定不下来
  • UI组合:UI非常专业需要独立的团队。没法实现端到端的业务切分
  • 不要返回值:我要返回值啊没返回值实现不了堺面,实现不了需求
  • 运行时报错信息是在一起的这么分着写很难和运行时的现象对应起来
  • 编辑的时候往往需要在更多的模块/目录/文件之間跳转
  • 需求可能是跨模块的,创新性的需求往往会对模块化的假设产生剧烈的影响
  • 产品经理的分工调整产品需求的粒度是经常变化的,導致一个产品经理需要改多个模块

我们要客观地看待复用和支持多样性很多时候不复用就是最佳的解决方案。很多时候堆砌 if/else 就是最佳的解决方案

在保持客观理性的同时,能不能把“行不通”的种种障碍逐一分析以下给每种类型的障碍提供一个切实可行的解决方案呢? 也僦是我们能不能给一个设计模式的列表,所谓设计模式就是“问题清单”

如何才能像大师一样,上来就知道抽象的接口应该如何定义? 我為什么总是想不出来该怎么抽象?

分模块之后代码不好读了怎么办

为了代码复用,拆了很多个模块导致代码不好阅读了怎么办? 之前代码雖然写的挫,但是 ctrl+f 在一个文件里就可以找到对应的代码现在找段代码可费劲了。

代码写成活的比写成死的要麻烦多了怎么办?

开槽开插件,都是为了把代码写得更灵活但是每一开一个扩展点,就需要写一堆样板代码如何才能降低“插件税”呢?

怎么扩展额外的字段呢?

经瑺看见一个表里面有 extra_fields 之类的字段,里面放一个大 JSON每个需求都要加新字段怎么弄?

怎么支持新的订单类型?

为了支持新的业务,往往需要给 OrderType 这個字段上添加新的订单类型为了不影响已有的业务,还经常要加 isNewBiz 这样的“Flag”来标识新的业务场景除了一直加新的Flag,就没别的办法了吗?

UI組合为何难以落地?

松耦合模块边界的最佳范例就是基于 UI 的组合但是为什么在过去的历史经验里,这样的模块切分的方式很难落地? 有没有什么具体的技术方案可以借鉴?

事件驱动为何难以有收益?

事件驱动是大家谈论解耦的时候寄予众望的技术但是具体到实际的项目中,经常發现事件驱动没有发挥出什么作用为什么会这样?

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信