维护大型JavaScript应用程序经验教训 - MathiasSchäfer
栏目: JavaScript · 发布时间: 5年前
内容简介:这是我们从长期维护大型JavaScript应用程序中学到的经验教训。在例如,我们于2012年为贝塔斯曼基金会启动了
这是我们从长期维护大型JavaScript应用程序中学到的经验教训。
在 我们的机构 ,客户项目通常持续几个月。从第一个客户联系和设计阶段到实施和首次启动,项目大致需要半年时间。但有时我们会在几年内开发和维护特定的软件。
例如,我们于2012年为贝塔斯曼基金会启动了 GED VIZ ,并于2013年发布,每隔几年就会增加新的功能和数据。2016年,我们将核心可视化转变为可重用的库,对其进行了重构。欧洲中央银行(ECB)今天仍在使用流数据可视化引擎。另一个长期存在的项目是 OECD Data Portal 前端:我们在2014年开始实施,我们仍在扩展代码库。
在主要开发阶段之后,我们应用修复并添加新功能。通常,没有重大重构甚至重写的预算。因此,在一些项目中,我坚持使用我在4 - 6年前编写的代码以及当时流行的库堆栈。
小改进而不是大改写
前面提到的两个项目都是相当大的客户端JavaScript应用程序。如今,您发现很少有关于维护现有JavaScript代码库的博客文章。你会发现很多帖子都在用你现在流行的JavaScript框架重写你的前端。
迁移到一组新的库和 工具 是一项重大投资,可能很快得到回报。它可以简化维护。它可以降低变更成本。它允许更快地迭代并更快地实现新功能。它可以减少错误,提高稳健性和性能。最终,这种投资可能会降低总体拥有成本。
但是当客户无法进行此项投资时,我们会寻找如何逐步改进现有代码库的方法。
从长期项目中学习
对于一些Web开发人员来说,坚持使用现有的代码库是一场噩梦。对于他们最近一段时间没有修改过的代码,他们以贬义的方式使用“遗产”这个词。
对我来说,情况恰恰相反。在几年内维护一个项目的代码教会了我更多关于软件开发的知识,而不是多个短暂的,即发即弃的项目。
最重要的是,它让我遇到了我多年前写过的代码。我多年前做出的决定对今天的整个系统产生了影响。我今天做出的决定从长远来看决定了系统的命运。
我常常想知道:今天我会做些什么?有什么需要改进的?像每个开发人员一样,我有时会有破坏一切并从头开始构建它的冲动。
但大多数时候,我对现有代码的问题更加微妙:今天,我会编写相同的逻辑,但结构不同。让我向您展示我在JavaScript代码中发现的主要结构问题。
避免复杂的结构
“复杂”我并不仅仅意味着大。每个非平凡的项目都有很多逻辑。很多案例要考虑和测试。要处理的数据不同。
复杂性来自于交织不同的问题。人们无法完全避免这种情况,但我已经学会先将 问题分开 ,然后以可控的方式将它们带回来。
让我们看看JavaScript中的简单和复杂结构。
函数
最简单的可重用JavaScript代码是一个函数。特别是,一个 纯函数 ,它获取一些输入并产生一个结果(返回值)。该函数显式获取所有必需的数据作为参数。它不会更改输入数据或其他上下文数据。这样的功能易于编写,易于测试,易于记录,易于推理。
编写好的JavaScript不一定需要高级设计模式。首先,它需要技能以巧妙和有益的方式使用最基本的技术:用一些 正确的 函数构建程序。然后将低级函数组合到更高级别的函数。
JavaScript中的函数是完整的值,也称为第一类公民。作为一种多范式语言,JavaScript允许强大的函数式编程模式。在我的职业生涯中,我只是用JavaScript编写了函数式编程的表面,但理解基础知识已经有助于编写更简单的程序。
对象
下一个复杂的结构是一个对象。在最简单的形式中,对象将字符串映射到任意值,没有逻辑。但它也可以包含逻辑:函数在附加到对象时成为方法。
const cat = { name: 'Maru', meow() { window.alert(`${this.name} says MEOW`); } }; cat.meow();
JavaScript中的对象无处不在且功能多样。对象可以用作附加几个处理函数的参数包。对象可以对关联的值进行分组,但也可以构建程序。例如,您可以在一个对象上放置几个类似的函数,并让它们对相同的数据进行操作。
类
JavaScript中最复杂的结构是一个类。它是物体的蓝图,同时也是这些物体的工厂。它将原型继承与对象的创建混合在一起。它将逻辑(函数)与数据(实例属性)交织在一起。有时在构造函数上有属性,称为“静态”属性。像“singleton”这样的模式会使一个具有更多逻辑的类重载。
类是面向对象语言中常见的工具,但它们需要 设计模式 的知识和对象建模的经验。特别是在JavaScript中,它们很难管理:构建继承链, 对象组合 ,应用mixins,超级调用,处理实例属性,getter和setter,方法绑定,封装等.ECMAScript也没有为常见的OOP概念提供标准解决方案。社区是否就使用类的最佳做法达成一致。
如果具有一个定义的目的(banq:标签),则类是合适的。我学会了避免在类上增加更多的顾虑。例如, 有状态的React组件 通常声明为类。这对特定问题域有意义。它们有一个明确的目的:对属性,状态和两个功能进行分组。该类的核心在于render功能。
我停止用更多,松散相关的逻辑来丰富这些类。值得注意的是,React团队正逐渐从类转向 有状态的函数组件 。
同样, Angular 中的 组件类 是几个关注点的交集:使用@Component()装饰器应用的元数据字段。基于构造函数的依赖注入。将状态作为实例属性(输入,输出以及自定义公共和私有属性)。这些课程根本不是简单或单一目的。只要它们只包含所需的Angular特定逻辑,它们就是可管理的。
选择结构
多年来,我已经达到了这些指导方针:
- 使用最直接,最灵活和多函数的结构:函数。如果可能的话,让它成为一个纯粹的函数。
- 如果可能,避免在对象中混合数据和逻辑。
- 尽可能避免使用类。如果你使用它们,让他们做一件事。
大多数JavaScript框架都有自己的结构代码方式。在基于组件的UI框架(如React和Angular)中,组件通常是对象或类。选择组合比继承更容易:只需创建一个新的轻量级组件类来分离关注点。
这并不意味着需要坚持使用这些结构来模拟业务逻辑。最好将这个逻辑放入函数中,并将它们与UI框架分开。这允许分别发展框架代码和业务逻辑。
模块,很多
管理JavaScript文件和外部库之间的依赖关系曾经是一团糟。在9elements,我们是CommonJS或AMD模块的早期采用者。后来社区决定使用标准的 ECMAScript 6模块 。
模块成为JavaScript中必不可少的代码结构。这取决于它们是否带来简单性或复杂性的用法。
我对模块的使用随着时间的推移而改变。我曾经用多个导出创建相当大的文件。或者,单个导出是将一堆常量和函数分组的巨大目标。今天我尝试用一个导出或只有几个导出来创建小而扁平的模块。这导致每个函数一个文件,每个类一个文件,依此类推。文件foo.js看起来像这样:
export default function foo(…) {…}
如果您更喜欢命名导出而不是默认导出:
export function foo(…) {…}
这使得单个函数更易于引用并且更易于重用。根据我的经验,许多小文件不会带来很大的成本。它们允许更容易地在代码中导航。此外,特定代码片段的依赖性更有效地声明。
避免创建无类型的对象
JavaScript的最佳功能之一是对象表示法object literal。它允许您使用任意属性快速创建对象。我们已经看到上面的一个例子:
const cat = { name: 'Maru', meow() { window.alert(`${this.name} says MEOW`); } };
JavaScript对象表示法是如此简单和富有表现力,以至于它变成了一种无处不在的独立数据格式:JSON。但是在ECMAScript版本的过程中,对象表示法获得了越来越多超出其原始目的的功能。新的ECMAScript功能,如 Object Rest / Spread, 可以更自由地创建和混合对象。
在小代码库中,动态创建对象是一种生产力功能。然而,在大型代码库中,对象表示法成为一种负担。在我看来,具有任意属性的对象不应该存在于这样的项目中。
问题不在于对象表示法本身。问题是不符合中心类型定义的对象。它们通常是运行时错误的来源:属性可能存在与否,可能具有某种类型。该对象可能具有所有必需的属性,但也更多。通过阅读代码,您无法确定对象在运行时将具有哪些属性。
JavaScript没有类型定义,但有几种方法可以更加可控的方式创建对象。例如,函数可用于创建看起来相似的所有对象。该函数确保所需的属性存在且有效或具有默认值。另一种方法是使用一个创建死简单 值对象 。
同样,函数可以在运行时检查参数是否可用。它可以明确地检查使用类型typeof,instanceof,Number.isNaN等或隐式使用 duck typing 。
更彻底的解决方案是使用类型定义(如TypeScript或Flow)来丰富JavaScript。例如,在TypeScript中,首先定义重要数据模型的接口。函数声明其参数的类型和返回值。TypeScript编译器确保仅传递允许的类型 - 假定编译器可以访问所有调用。
强大的代码
这些指南涉及代码的整体结构。多年来,我在大型JavaScript项目中学到了更多的技术和实践。最常见的是影响JavaScript应用程序的健壮性:了解JavaScript程序如何失败以及如何防止它。我在免费的在线书籍中汇编了这些技巧:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 开发对接过程中的教训
- 使用Kubernetes两年来的经验教训
- 多任务深度学习的三个经验教训
- 生产环境使用一年Kubernetes的经验教训
- 机器学习的教训:5家公司分享的错误经验
- 医疗领域构建自然语言处理系统的经验教训
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Flash与后台
刘明伟 / 清华大学出版社 / 2007-6 / 52.00元
《Flash与后台:ASP/ASP.NET/PHP/Java/JavaScript/Delphi总动员》从目前热门的F1ash与ASP、ASP.NET、PHP、Java、JavaScript和Delphi的交互知识入手,深入浅出地讲解了F1ash与后台通信的原理和交互的过程,力求使阅读《Flash与后台:ASP/ASP.NET/PHP/Java/JavaScript/Delphi总动员》的每一位读......一起来看看 《Flash与后台》 这本书的介绍吧!