前端架构设计要注意的方面

 二维码

000118

前端架构存在的目的,


1、提高代码的可读性。


一个好的架构,代码的可读性一定是强的。


简单来说,假如有一个新人加入团队,那么他接手这个项目,一定是容易上手的,能简单轻松的了解整个前端部分的相互关系,从而找到自己需要重点关注的点。而不是需要花很多时间去熟悉这个项目的很多细节,才能开始上手做东西。


就文件来说,可以从文件名上,分清哪些是页面、哪些是逻辑、哪些是样式、哪些是可以复用的组件、哪些是图标组、又有哪些是移动端或是PC端专享的样式/逻辑等。


就代码来说,包括统一的命名风格,封装在同一个文件里的代码的相关性足够强等。


2、提高代码的可维护性。


一个好的架构,一定是易于维护的,例如在新增需求、更改需求、修正bug,都不会造成意料之外的变化,比如说修改了一个页面组件的内容,却导致另外一个页面组件发生变化(这也太坑了)。


因此,要低耦合,高内聚,以及输入和输出是可预期的。


3、提高代码的可扩展性。


一个好的架构,一定扩展性要强,不能写死。


需求变更太正常了,新增需求也太正常了。因此好的架构,必须要考虑到这些情况的发生,因为他们是一定会发生的。所以,一定要避免把代码写死。


比如页面组件A里需要有一个日历组件,而这个日历组件引用的是别人的(比如从github上找的),那么尽量不要直接在页面组件A里面直接引用这个日历组件,而是将写一个日历组件B,在这个日历组件B里封装你引用的日历组件C,然后通过这个日历组件B来进行操作。


原因很简单,假如某天产品经理说,这个日历组件太丑了,我们换一个吧。如果你直接在页面组件A里内嵌这个引用的日历组件C,你很可能就要改很多代码(因为不同日历组件的使用方法和暴露的接口可能不同)。假如你还在其他多个地方引用了这个日历方都要改。


而若是将引用的日历组件C封装到自己写的日历组件B之中,那么你只需要改日历组件B里的相应代码即可,而因为日历组件B暴露的接口是不变的,那么自然不用修改页面中的代码了。


4、便于协同。


包括前端和后端的协同,前端和前端之间的协同。


具体来说,前后端的协同通常是以ajax为交互,那么应至少有一个用于专门封装了所有ajax请求的文件,所有ajax请求都封装在这里。在开发时,这里封装的方法应该可以模拟发送和接收约定好的交互内容,方便开发联调。


而前端和前端的协同,主要体现在同时在更改代码时,不会影响对方代码的正常运行。因此要求封装、解耦以及低干扰度是必须的。


5、自动化


自动打包,压缩,混淆,如果有必要,再加上自动单元测试。

前端架构师们认为有多个关键的决策需要在项目启动之初就制定下来,如果等到开发阶段的后期再考虑,不是已经用不上,而是一开始错误的决定已经造成了无法挽回的损失。一旦做出这些决策,我们的任务就是去辅助视觉设计、平台开发、底层结构,使之能最大程度满足需求,要做到以下几点;


模块化标记


我们都在追求的理想的状态是,网站每一行HTML都由程序自动生成,而作为前端开发人员,我们只需要管理这个用来产生标记的模板和流程,遗憾的是,现实通常并非如此。即使在最好的情况下,也存在用户生成的内容,而这些内容几乎都无法自动添加CSS类名来标记。无论CMS系统(可以理解为后台)自动生成HTML的能力如何,让CMS决定类似表单和导航栏这样的标记,有时候会更简单。


模块化标记和手写的静态标记的区别在于,程序化地执行完之后,我们还可以通过一套类名系统给标记动态添加CSS类名。而且不再通过元素标签和层级关系来决定视觉外观。让我们看看如何用BEM原则(一个CSS规则,下面会说到)模块化地实现一个简单的导航:


   <navclass="nav">

     <ulclass="nav__container">

        <liclass="nav__item">

           <ahref="/products">

              <ulclass="nav__container--secondary">

                 <liclass="nav__item--secondary">

                    <ahref="/socks">


要使用这种模块化方法,我们首先需要改变构建页面的方法和思路。作为前端开发人员,我们的工作就是把视觉语言拆解成最小单元,拆解之后,我们可以创建规则,对这些最小单元进行重组。


上面提到的BEM(Block Element Modifier,块元素修饰符)是一个CSS类名命名规则,它建议每个元素都添加带有如下内容的CSS类名:


    块名。所属组件的名称。

    元素。元素在块里面的名称

    修饰符。任何与块或元素相关联的修饰符


过多的CSS依赖


如果我们想渲染我们样式中的某一块内容,首先需要加载以下内容


Boostrap CSS: 114KB(未压缩)。其实网站本身没怎么调用Boostrap库的代码,但我们编写所有CSS的前提条件都是Boostrap已经重置了基本样式。

   

核心的网站CSS: 500KB。虽然一般来说,每块内容都有一个单独的关联文件。但这个文件不是这块内容的单一样式来源。样式不仅来源位置多样,并且常常基于位置和页面的类被覆盖重写。


自上而下的样式命名方法意味着,每次修改我们都要写一个更长的、更具体的选择器,同时,因为标记顺序极为严格,每块内容都很难重排或者替换。当然我们可以抽出一个单独文件,并把它需要的所有样式合并到单独的一个文件里,但是这么做基本意味着完全重做这个组件里的CSS文件,每块内容都很难重排或者替换。


因此我们指定了一些规则,以下是我们指定这些规则时需遵循的规范:


只包含不可变的规则,而不是笼统的说明。

   

总是把规则提炼成最简单的表达。

   

总是首先说明规则时什么,再说明“如果不这样,那么会怎么样”

   

每个规则必须包含以下词的一个——总是、永远不要、只有、每一个、不要、要


最后指定的设计系统的规则如下


    永远不要给布局的子内容强加内边距和元素样式。布局只关注垂直对齐、水平对齐和文字间距。


    主题和别的数据属性值永远不要强制改变外观,他们必须保持布局、组件和元素可以应用于其上。


    组件总是贴着它的父容器的四个边,元素都没有上外边距和左外边距、所有的最后节点(最右边和最下边的节点)的外边距都会被清楚。


    组件本身永远不要添加背景、宽度、浮动、内边距和外边距的样式,组件样式是组件内元素的样式。


    每个元素都有且只有一个唯一的且作用于只在组件内的CSS类名,所有的样式都是直接应用到这个选择器上, 并且只有上下文和主题能修改元素的样式。


JavaScript


为js创建规范是非常有必要的,可以参考以下建议:


保持代码整洁。JS Hint是这写工具中一个很好的例子,这里有几条可以通过JS Hint检查的规则:


    强制使用===和!==代替==和!=


    限制代码块嵌套深度


    限制函数的参数数量


    如果函数重复定义,发出警告


    如果变量创建后未被使用,发出警告


创建可复用的函数。比如我们常用的addClass操作,如果需要多次创建新的.green-alert类名,只需要修改定义好的add_background方法:


   $.fn.add_background =function(color){

       this.css('background-color',color);

       returnthis;

   }


测试核心;


在开始为应用程序规划测试时,请记住以下几条建议:


    测试用例应该在建站的同时或之前开始编写


    测试代码是真实的代码,应该一起或立即提交到系统代码库中。


    必须在所有的测试用例都通过之后,才能把代码合并到主干上。


    在主干上运行测试工具,结果都应该为通过。


单元测试时将应用程序分解为尽可能小的函数,并创建可重复的、自动化的测试用例的过程。“一次只做一件事,并把它做好”是构建基于单元测试的应用程序的原则(函数式),我们在写函数时经常想同时实现很多功能,结果最后不仅降低了了效率,还增加了测试的难度。


单元测试的基本思路是调用要测试的函数,传递一些预先设置好的参数,并描述结果是什么。


   function calculateShipping(distance){

      switch(distance){

          case(distance< 25):

             shipping= 4;

             break;

          case(distance< 100):

             shipping= 5;

             break;

          case(distance< 1000):

             shipping= 6;

             break;

          returnshipping;  

      }

   }

   QUnit.test('CalculateShipping', function(assert){

       assert.equal(calculateShipping(24),4, '24 Miles');

       assert.equal(calculateShipping(99),5, '99 Miles');

       assert.equal(calculateShipping(999),6, '999 Miles');

       assert.equal(calculateShipping(1000),7, '1000 Miles');

   })


确定合适的测试覆盖率是一件很难权衡的事,在我们的项目中,如果一个新功能需要花费8小时开发完成,我们要确保另外预留2个小时来编写用例并验证测试覆盖率。尽管这会多花费25%的时间,但这其实会节省很多后续回头追查bug的时间。

性能测试


把你的网站性能基线与行业平均水准和通用的最佳实践相比较是必不可少的。


HTTPArchive(http://httparchive.org/)是个不错的服务,它测试并记录了几十万个网站,有几个值得注意的数据如下:


    页面大小:2061KB


    总请求数:99


    可缓存资源所占比例


因此,如果想让自己的网站比大部分网站都快,可以考虑设定一个目标:一个1648KB的网站,包括79个请求,其中44个请求可以缓存,这将使你的网站领先平均水平20%。