高阶的编程模型

发布于 2022-04-27 13:11:21 字数 4216 浏览 1060 评论 0

通过一系列「优雅的 Mac」的讨论,我提到这些快捷的本质是为你更快地处理尽可能多的「背景事务」,以使你能够专注在「更重要的事情」上。更重要的事情是什么呢?产出价值。产出代码。这里,我们暂且假定 代码=价值,那么有两个推论:

  1. 如果「价值」本身有问题,那么整个所谓效率体系,都没意义,因为没有产出有用的价值。这个问题,我会在效率集里讨论
  2. 如果你不产出代码,那么你没必要节约其他部分的时间,因为你就没要完成的东西啊

更遑论,产出的代码本身不一定就100%达到了你要的价值。在业务代码的上下文下,你产出了代码,解决了问题,就是为公司产出了价值。在自己做产品时,写的代码有没有价值,就难说了。因此,更快的产出,才能支持更快的验证、反馈,甚至抛弃,才能作为整个敏捷体系的支撑。代码产出越慢,价值反馈越慢,你能试错的机会越少,机会成本越高。

骨架代码

这个 issue 要谈的是「产出代码」这个事情本身。我发现,即便是在产出代码,你在写的很大一部分代码也不一定是产生了直接价值的代码,比如框架代码,比如基本的控制结构。我把你要写的代码想像成一篇文章,这篇文章应该是有它更高层次的结构的。并且,这个结构与你所写文章的类型——理解为你所用的框架——有直接的关系。打个地方:

  1. 一个 React+ES6 的组件,首先一定是一个类,它必须有一个 render 方法,可能有若干生命周期方法。这些是它的结构、骨架,有了骨架,你再往里填东西就是了
  2. 一个 Java 服务, 首先它也一定是一个类,必然是这样的结构: class MyClass { ... }。里面可能有若干方法。这些是它的结构、骨架,有了骨架,再往方法里填东西就是了
  3. 一个用 chai+mocha 写成的 JS 单元测试。首先它一定具有 describe('', () => { it('', () => {}) }) 这样 的骨架,一个测试里,一定有 given(准备数据)、when(调用方法)、then(验证返回)三个部分。有了骨架,你再往方法里填东西就是了

可以看到,这些代码,都不一定是有价值的代码。你所写真正的代码,应该是那些骨架里的函数、方法里的那些代码。骨架代码,生成就行了。这是我要提的第一个点,骨架代码生成。说白了,就是这样一个 API:

generateSkeletonCode(...techStack)

基本控制结构

好,我们真正要写的就是那些骨架里的函数方法代码。但是莫急!这些函数里面,依然不需要你去写的所有的代码,我们还有更为基本的组件。那,就是我们经典的三大编程结构statementif-elsewhile。顺序结构、条件结构、循环结构。各种结构有变体,不妨碍使用,而且为了减少记忆负担,尽量只用一种可应对万能情况的结构。

细细拆分下来,顺序结构里面,一般是 变量计算API 调用赋值 等,本质都是通过计算和请求获得可供下步计算或返回的 数据;循环结构,其实在 JS 这种特定语言里,又可以使用函数式编程来代替。所以,我们在实现函数或代码的时候,可用的编程结构分列如下:

  • 顺序结构 statement
    • 变量计算。通常无特定模块,手敲即可
    • API 调用。这个又是一个子模块,它又根据你所用的技术栈不同而有不同的语法(如你用 $.ajax()fetch() 不同的 API 语法不同,你用 HTTP 请求与用 FTP 请求需要的协议参数又可能不同),但它又有共通的接口,如都需要你传入 urlsettings(optional)、回调等。其实又有一个编程结构的 API:generateAPICode(...techStack, url, settings, params, successCallback, errorCallback)
    • 赋值。上两步都是为了取得数据供后续计算,那么数据就得保存起来,会发生一次赋值操作。这个在 Intellij 里已经有后向声明这样的特性支持
  • 条件结构 if-else switchgenerateConditionComponent(condition, ...opeartions)。这个 Intellij 里也已有 if 这样的 live template
  • 循环结构 whilegenerateLoopComponent(startCondition, stopCondition, accumulateCondition, operations)。对于数组来说,这样的循环则可进一步简化为高阶函数式编程,现已有完美支持:array.map()array.filter()array.reduce()array.find()array.any()

理解了这些,其实编程产生的直接价值,真正需要你的东西,除了把代码写好让人容易理解到极致之外,就只是输入数据了。我们的工作,其实就是运用调配这些框架代码、编程结构,从原始的输入数据处,产生正确的输出。如是而已。中间调配过程,能越快完成越好。

实践落地

说了那么多,怎么落地呢!?

Mindset

思维转换。比如要 TDD,就要先把思维切换到 任务分解、快速反馈验证 这样的工作论上来;这种编程模型,本质是把代码做从上至下的组件划分,从框架性的最高层组件,到下面的结构组件,通过分离组件模板代码和真正需要我们编写的代码,尽量剔除无用的工作。新的思维模型会出来,正是因为以往直白的直觉思维,已经无法高效应对更复杂的问题。因此,尝试、辩证、质询看待一种新的思维方式,才是成长式的思维嘛。

真的要落地了

  • IDE 支持:WebStorm 插件?
  • 没了?

自己撸一个。核心代码尽量做成可复用的 API,这样不同的编辑器插件只需依照不同的模板集成就行了。就像 JUnit 5 分离出一个 jupital-core 的核心包出来一样,以后即可适应 gradle runner, maven runner, Intellij plugin, Eclipse plugin 等等不同的三方插件了。

API

举个非常简单的:

1  import React from 'react'
2  
3  class **TodoApp** extends React.Component {
4    static propTypes = {
5      **todos**: React.PropTypes.string
6    }
7 
8    render() {
9      return (
10       **<ul>**
11       **{ todos.map(todo => <li>{ todo.name }</li>) }**
12       **</ul>**
13     )
14   }
15 }
16

这个16行的 React 类里,其实真正需要我们写的,只有打了星号的部分,仅3行 + 2个变量名,也就是 类名、传入参数、组件 render 方法真正要做的事,其他的什么 class xxx extends React.Componentrender() 等都是 ES6+React这个技术栈本身所需要的骨架结构,完全可以一键生成;map 是实现过程中使用到的循环结构;html 这些,甚至可以用 emmet 这样的工具插件来完成。emmet 这个工具其实也是一样的思想,HTML 的标签都是模板,尽量生成就好,手撸个啥,HTML 页面真正需要你写的,就是把传入的数据展示出来,如是而已。

实际产出 / (实际产出 + 框架代码 + 基本编程结构) 这个公式来看,写一个16行的类,不产生直接价值、可通过模板生成的代码有75%。

好在,在 React 上,现在真的有 Intellij 插件完成这个事情了。剩下我们自己真正做的,真的就只有对输入的处理逻辑,这是我们最应该专注的地方。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文