本文概述
- 故事
- 提案
- 为什么我选择JavaScript
- 端到端JavaScript:Node.js和MongoDB
- 使用Express.js进行服务器组件化
- 单页应用程序
- 带有Backbone.js, Marionette.js和Twitter Bootstrap的客户端MV *
- 最佳实践:Grunt.js, Mocha.js, Chai.js, RequireJS和CoverJS
- 使用分支切换要素
- 使用Init启动项目并立即部署到Heroku
故事
所以, 你和你的联合创始人对企业有一个伟大的构想, 对吗?
你一直在脑海中添加功能。
通常, 你会向潜在客户征求意见, 他们都喜欢。
好的, 所以人们想要它。甚至可以赚钱。他们无法拥有它的唯一原因是因为你尚未实现它-到目前为止。
所以最后, 你坐下来一天, 然后说:”做吧!”很快, 你将试图弄清楚如何实现应用程序的业务逻辑, 这是将产品推向前进的杀手级功能:你知道如何做到这一点, 并且知道可以做到。
“做完!有用!”你说。你的概念证明是成功的!剩下的就是将其打包到网络应用中。
你说:”好, 我们来创建一个网站。”
然后, 你意识到了事实:你需要选择一种编程语言;你需要选择一个(现代)平台;你需要选择一些(现代)框架;你需要配置(和购买)存储, 数据库和托管提供程序;你需要一个管理界面;你需要一个权限系统;你需要一个内容管理员。
你想变得苗条, 想要敏捷。你想使用可以在短期和长期内成功的技术。而且它们并不总是很容易被挑选出来。
你需要做出数十项建筑决策。你想要做出正确的选择:你想使用允许快速开发, 不断迭代, 最大效率, 速度, 鲁棒性等的技术。你想变得苗条, 想要敏捷。你想使用可以在短期和长期内成功的技术。而且它们并不总是很容易被挑选出来。
你说:”我不知所措。”你的精力与以往不同。你尝试将各个部分拼凑在一起, 但这工作太多。
你的概念证明慢慢地枯萎而死。
提案
在以这种方式自己放弃大量想法之后, 我决定设计一种解决方案。我称之为” Init”项目(或init.js)。
这个想法的核心是有一个项目来启动所有这些项目, 让开发人员或技术创始人立即做出所有这些重要决定, 并根据这些决定获得合适的开始模板。我知道反对者会说什么:”一个解决方案不能解决所有问题”(讨厌的人会讨厌)。他们可能是正确的。但是我们可以尽力创建一个近似的解决方案, 我认为Init非常接近。
为了最好地实现这一目标, 我们必须牢记一些关键思想。在开发Init时, 我考虑了:
-
组件
组件化是任何系统的关键特征, 因为它允许你在不同项目中重用软件组件, 这是Init的主要目标。但是组件化还附带有一个副产品”可替换性”, 它将是我们用”几乎”相同的解决方案攻击几个不同问题的最佳盟友。
-
易于发展
有些问题, 某个地方最好用Brainf * ck编写解决方案。但是(在Brainfuck中)实现该解决方案几乎是不可能编写的, 更不用说阅读了。这将花费你时间和大量精力。通常, 你应该使用使开发更容易而不对你(或以后可能进行任何工作的人)来说更轻松的语言和平台。
-
社区
无论选择哪种平台, 都要确保它拥有一个庞大的社区, 并且可以帮助你解决最常见和最不常见的问题。请记住:jQuery可能不是最快, 最干净或最优雅的库, 但由于其社区而成为赢家。
牢记这些目标, 接下来我将向你展示如何在创建Init时做出自己的决定。
Init的核心是利用”全栈JavaScript”范式(有人将它或它的一个子集称为MEAN Stack)。通过使用这样的堆栈, Init能够仅使用一种语言, 同时创建用于开发Web应用程序的极其灵活且功能齐全的环境。简而言之, Init使你不仅可以将JavaScript用于客户端和服务器开发, 还可以用于构建, 测试, 模板化等等。
但是让我们放慢脚步并问自己:使用JavaScript真的是个好主意吗?
为什么我选择JavaScript
自1998年以来, 我一直是一名Web开发人员。那时, 我们在大多数服务器端开发中都使用了Perl, 但即使到那时, 我们在客户端上都使用JavaScript。从那时起, Web服务器技术发生了巨大变化:我们经历了一波又一波的语言和技术, 例如PHP, AP, JSP, .NET, Ruby, Python。开发人员开始意识到, 在客户端和服务器环境中使用两种不同的语言会使事情变得复杂。最初尝试用一种语言进行统一的尝试是在服务器上创建客户端组件并将其编译为JavaScript。这无法按预期进行, 并且其中大多数项目都失败了(例如:ASP MVC取代了ASP.NET Web表单, 而GWT可能在不久的将来被Polymer取代)。但从本质上讲, 这是一个好主意:客户端和服务器上使用一种语言, 允许我们重用组件和资源(这是关键字:resources)。
答案很简单:将JavaScript放在服务器上。
JavaScript实际上是Netscape Enterprise Server中的JavaScript Server Side附带的, 但是当时该语言还没有准备好。经过多年的反复试验, Node.js终于出现了, 它不仅将JavaScript放在服务器上, 而且还提倡了非阻塞编程的思想, 从而永远改变了我们编写”读取”(I / O)的方式(请阅读此处)了解更多)。
一句话:非阻塞编程旨在将耗时的任务搁置一边, 通常是通过指定完成这些任务后应执行的操作, 并允许处理器同时处理其他请求。
但是这些想法并不新鲜-那么为什么它们在Node.js中变得如此流行?简单, 无阻塞的编程可以通过多种方式实现。也许最简单的方法是使用回调和事件循环。在大多数语言中, 这不是一件容易的事:虽然”回调”在某些其他语言中是常见的功能, 但事件循环却并非如此, 并且你经常会发现自己在使用外部库(例如:Python和Tornado)。但是在JavaScript中, 回调和事件循环一样都内置在该语言中, 几乎每个甚至精通JavaScript的程序员都熟悉它们(或者至少使用过它们, 即使他们不太了解事件是什么)循环是)。突然, 地球上的每个初创企业都可以在客户端和服务器端重用开发人员(即资源), 从而解决” Python Guru Needed”职位发布问题。
突然, 地球上的每个初创企业都可以在客户端和服务器端重用开发人员(即资源), 从而解决” Python Guru Needed”职位发布问题。
因此, 现在我们有了一个令人难以置信的快速平台(由于采用了非阻塞编程), 其编程语言非常易于使用(感谢JavaScript)。但是够了吗?会持续吗?我相信JavaScript在将来会占有重要地位。让我来告诉你为什么:
-
功能编程
JavaScript是将功能范例带入大众的第一门编程语言(当然, Lisp排在第一位, 但是大多数程序员从未使用Lisp构建可用于生产环境的应用程序)。 Lisp和Self是Javascript的主要影响力, 充满了创新思想。这些想法可以解放我们的思想, 探索新技术, 新模式和新范式。他们都继承了JavaScript。看一下Monad, 教堂编号, 甚至(对于一个更实际的示例)Underscore.js的collections函数, 它们可以节省行和代码行。
-
动态对象和原型继承
没有类(并且没有无休止的类层次结构)的面向对象编程允许快速开发(创建对象, 添加方法并使用它们), 但是最重要的是, 通过允许程序员修改对象实例来减少维护任务期间的重构时间类。这种速度和灵活性为快速发展铺平了道路。
-
JavaScript是互联网
JavaScript是为Internet设计的, 从一开始它就已经存在, 并且一直没有消失。销毁它的所有尝试均以失败告终:例如, Java Applets的垮台, VBScript被Microsoft的TypeScript(可编译为JavaScript)取代, 以及Flash在移动市场和HTML5手中的消亡。在不破坏数百万个网页的情况下替换Javascript是不可能的, 因此我们的未来目标应该是对其进行改进。没有比ECMA 39技术委员会更好的工作了。
好的, JavaScript的替代品每天都在诞生, 例如CoffeeScript, TypeScript和数百万种可编译为JavaScript的语言。这些替代方案可能对开发阶段有用(通过源映射), 但是从长远来看, 它们将无法取代JavaScript, 原因有两个:它们的社区永远不会变大, 并且它们的最佳功能将被ECMA脚本采用(即JavaScript)。 )。 JavaScript并不是一种汇编语言:它是一种高级编程语言, 带有你可以理解的源代码, 因此你应该了解它。
现在, 由于有了Esprima项目, 你可以创建自己的工具来处理源代码, 对其进行修改, 更改其样式, 添加注释, 检测以及通过使用程序的抽象语法树可以想象的所有事情。就像你在使用DOM树一样。
端到端JavaScript:Node.js和MongoDB
因此, 这些就是使用JavaScript的原因。现在, 我将使用JavaScript作为使用Node.js和MongoDB的理由。
-
Node.js
Node.js是一个用于构建快速且可扩展的网络应用程序的平台, 这与Node.js网站所说的差不多。但是Node.js不仅限于此:它是任何具有I / O访问权限的JavaScript应用程序的首选运行时环境。即使你不打算使用Node.js编写主服务器应用程序, 也可以使用在Node.js之上构建的工具来改善开发过程。例如:Mocha.js用于单元测试, Grunt.js用于自动构建任务, 甚至Brackets用于全文代码编辑。
因此, 如果要为服务器或客户端编写JavaScript应用程序, 则应查看一些Node.js示例, 因为你每天都需要使用它。有一些有趣的替代方法, 但是即使在Node.js社区的10%的情况下, 也没有一个。
-
MongoDB
MongoDB是基于NoSQL文档的数据库, 它使用JavaScript作为查询语言, 这使我能够完善端到端JavaScript平台。但这还不是选择此数据库的主要原因。
MongoDB是一种无模式数据库, 可让你以灵活的方式持久化对象, 从而更快地适应需求的变化。另外, 它具有高度的可扩展性和基于地图缩减功能, 因此非常适合大数据应用程序。 MongoDB非常灵活, 可以用作无模式文档数据库, 关系数据存储(尽管它缺少事务), 甚至可以用作缓存响应的键值存储。
使用Express.js进行服务器组件化
服务器端组件化绝非易事。但是随着Express.js(和Connect.js)的出现, 出现了”中间件”的想法。我认为, 中间件是在服务器上定义组件的最佳方法。如果你想将其与已知模式进行比较, 则非常接近管道和过滤器。
基本思想是你的组件是管道的一部分。管道处理请求(输入)并生成响应(输出), 但是你的组件不负责整个响应。相反, 它仅修改需要的内容, 然后委托给下一个管道。当管道的最后一部分完成处理后, 响应将发送回客户端。
我们将这些”管道中的各个部分”称为”中间件”。显然, 我们可以创建两种中间件:
-
中间件:那些处理请求和响应但对响应本身不完全负责的中介, 因此它们委托给下一个中间件。
-
决赛:对最终回应负全部责任的人。他们处理和修改请求和响应, 但不需要委托给下一个中间件。实际上, 建议你无论如何都委托给下一个中间件, 以实现体系结构的灵活性(即稍后再添加更多中间件), 即使该中间件不存在(在这种情况下, 响应将直接传递给客户端)。
举一个具体的例子, 考虑服务器上的”用户管理器”组件。在中间件方面, 我们既有最终产品也有中间产品。对于决赛, 我们将具有创建用户和列出用户的功能。但是在执行这些操作之前, 我们需要我们的中间件进行身份验证(因为我们不希望未经身份验证的请求进入并创建用户)。一旦创建了这些认证中间件, 我们就可以将它们插入我们想要将以前未经认证的功能转换为已认证功能的任何位置。
单页应用程序
Init项目专注于创建单页应用程序(SPA)。大多数Web开发人员不仅仅一次尝试尝试SPA。我已经建立了几个(大部分是专有的), 我可以自信地说它们仅仅是Web应用程序的未来。你是否曾经将SPA与移动连接上的常规Web应用程序进行了比较?响应能力的差异约为数十秒。
你是否曾经将SPA与移动连接上的常规Web应用程序进行了比较?响应能力的差异约为数十秒。
SPA是网络的未来-那么为什么要以旧版形式构建产品?我听到的一个普遍论点是人们担心SEO。但是, 如果你正确处理问题, 那么就不应该成为问题:Google本身有一个很好的有关如何执行此操作的教程, 这里也有一些不错的评论。
带有Backbone.js, Marionette.js和Twitter Bootstrap的客户端MV *
关于SPA的MVC *框架已有很多论述。这是一个艰难的选择, 但我想说的是前三个是Backbone.js, Ember.js和Angular.js。
这三个都得到很好的考虑。但是哪一个最适合你?
不幸的是, 我必须承认我在Angular.js方面的经验非常有限, 因此我将不在讨论之列(有关此内容的更多信息, 请参考Angular.js教程)。现在, Ember.js和Backbone.js代表了解决同一问题的两种不同方式。
Backbone.js最小, 简单, 可为你提供创建简单SPA所需的足够资源。另一方面, Ember.js是用于创建SPA的完整且专业的框架。它有更多的花哨和口哨声, 但也有较大的学习曲线。
根据你的应用程序的大小, 可以像查看featuresUsed / featuresAvailable比率一样容易地做出决定, 这将给你带来很大的提示。
对于Init, 我希望涵盖大多数情况, 因此我选择Backbone.js来轻松创建SPA, 并选择Backbone.Marionette.View进行组件化。这样, 每个组件都是一个简单的应用程序, 最终的应用程序可以像我们想要的那样复杂。
样式也是一个挑战, 但是我们可以再次依靠框架来拯救我们。对于CSS, 没有什么比Twitter Bootstrap更好的了, Twitter Bootstrap提供了一套完整的样式, 既可以直接使用, 也可以轻松自定义。
Bootstrap是使用LESS语言创建的, 并且是开源的, 因此我们可以根据需要进行修改。它带有大量的UX控件, 这些控件已在Bootstrap站点上进行了详细记录。此外, 还有一个自定义模型, 可让你创建自己的模型。绝对是这份工作的人。
最佳实践:Grunt.js, Mocha.js, Chai.js, RequireJS和CoverJS
最后, 我们应该定义一些最佳实践, 并研究Init如何帮助你实现和维护它们。我们的解决方案集中在几个基于Node.js本身的工具上。
Mocha.js和Chai.js:
这些工具使你可以通过应用TDD或BDD来改善开发过程, 并提供用于组织单元测试的基础结构以及可以自动运行它们的运行程序。
有成千上万的JavaScript单元测试框架。那么为什么要使用Mocha.js?简短的答案:它灵活而完整。
答案很长:它具有两个重要功能(界面, 报告程序)和一个重要缺席(断言)。让我解释。
-
界面:你可能已经习惯了TDD套件和单元测试的概念, 或者你更喜欢BDD关于行为规范的想法, 并带有”描述”和”应该”。 Mocha.js允许你同时使用两种方法。
-
报告者:运行测试将生成结果报告, 你可以使用各种报告者格式化这些结果。例如, 如果你需要提供一个Continuous Integration服务器, 则可以找到一个执行此操作的报告程序。
-
缺少断言库:Mocha.js绝不是问题, 它的设计目的是让你使用自己选择的断言库, 从而为你提供更大的灵活性。有很多选择, 但是这里是Chai.js发挥作用的地方。
Chai.js是一个灵活的断言库, 可让你使用三种主要的断言样式中的任何一种:
断言:TDD老派的经典断言风格。例如。:
assert.equal(variable, "value");
期望:可链接的断言样式, 是BDD中最常用的样式。例如。:
expect(variable).to.equal("value");
应该:也用于BDD中, 但我更希望使用Expect, 因为”应该”在行为规范”它(“应该做某事。”))中听起来是重复的。例如。:
variable.should.equal("value");
Chai.js与Mocha.js完美结合。仅使用这两个库, 你就可以用TDD, BDD或任何可以想象的样式编写测试。
Grunt.js:
Grunt.js允许你自动化构建任务, 从简单的复制粘贴和文件串联到模板预编译, 样式语言(即SASS和LESS)编译, 单元测试(使用mocha.js), lint和代码最小化(例如, 使用UglifyJS或Closure Compiler)。你可以将自己的自动化任务添加到Grunt, 或搜索Grunt注册表, 那里有成百上千个可用的插件(同样, 使用背后有强大社区的工具也会有回报)。 Grunt还可以监视你的文件并在文件被修改时触发操作。
RequireJS:
RequireJS听起来可能只是用AMD加载模块的另一种方式, 但是我可以向你保证它远不止于此。为了理解原因, 我们首先需要提及模块命名空间的概念(例如demo.views.hello), 该方法通过将每个模块包装在其自己的命名空间中来避免污染全局命名空间。问题是, 这些模块不可重用:如果你修改一个”实例”的名称空间, 那么你正在修改所有”实例”的名称空间。与此相反, RequireJS允许你从一开始就定义可重用模块。 (此外, 它可以帮助你接受依赖注入, 从而避免模块访问全局变量。)
CoverJS:
代码覆盖率是评估测试的指标。顾名思义, 它告诉你当前测试套件涵盖了多少代码。 CoverJS通过在代码中检测语句(而不是像JSCoverage这样的代码行)并生成代码的检测版本来衡量测试的代码覆盖率。它还可以生成报告以供你输入Continuous Integration Server。
使用分支切换要素
当我启动Init时, 我需要一种让用户激活和停用他们在项目中可能想要的各种功能的方法。我决定对git的分支系统采取彻底的方法来实现此功能。
本质上, 每个分支代表用户可能希望包含的功能。如果你是从头开始的项目, 请从所需的最小分支开始, 然后通过与所需分支合并来添加其他技术。例如, 假设你要使用Backbone.js和Marionette.js启动你的项目。好了, 你可以从Backbone.js分支开始, 然后将其与Marionette分支合并, 然后继续执行你要添加的所有功能。
目前, 这种合并添加功能的想法只能用于技术模板(例如Backbone, Node, Express)。但是将来, 你将可以在后端(例如, 从MongoDB到Postgres)和客户端实施之间进行切换。
使用Init启动项目并立即部署到Heroku
从来没有一个简单的方法可以启动一个项目。只需访问GitHub存储库, 检查包含最新提交的分支(现在是usermanager, 尽管将来可能会更改), 然后:
为你的项目创建目录(或使用现有目录)。
使用” git init”创建存储库(或使用现有存储库)。
使用init添加一个遥控器
git remote add init git://github.com/picanteverde/init.git
获取你想要的分支
git pull init usermanager
获取Heroku进程文件
git pull init heroku-webprocess
安装好Heroku Toolbelt后, 创建一个Heroku应用
heroku create
将你的主分支推到Heroku
git push heroku master
在Heroku上启动并运行你的应用程序!
现在, 你只需几行代码就可以开始开发你的杀手级功能。不仅如此, 你还将在尽可能自动化的开发套件中使用最新, 最高效的技术进行开发。
我希望你可以使用Init来启动你的下一个大想法。切记检查Init存储库中是否有新的修复程序和功能-它的开发工作非常实时, 我期待收到你的反馈。