程序员为什么需要框架?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://csdnnews.blog.csdn.net/article/details/100059270

 

640?wx_fmt=gif

Clojure 是一种运行在 Java 平台上的 Lisp 方言,它的出现有助于将比较复杂的表述定义成简洁的呈现。与此同时,Clojure 也具备诸多的工具来解决程序员经常需要面对的难题。

不过随着对该语言的深度学习与应用之后,Clojure 开发社区中开始出现一批对使用框架有着强烈反感的程序员群体,而这到底是怎么回事?框架对 Clojure 编程语言来说是否真的多余?

 

640?wx_fmt=jpeg

作者 | Daniel Higginbotham

译者 | 苏本如,责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

以下为译文:

 

似乎Clojure开发社区对使用框架有着强烈的反感。其它语言可能需要框架,但我们Clojure不需要!因为我们有无所不在的函数库!

这种态度并非毫无理由。首先,我们当中的很多人都是在深受像Rails这样的神奇框架荼毒后选择使用Clojure编程语言的,因为在那里我们不得不花费大量的时间来处理这些框架的缺点。另外,像Luminus这样的Clojure开发工具和它捆绑在一起的顶级Web开发库提供给开发人员一种富有成效的体验,框架对Clojure编程语言来说似乎是多余的。

尽管有各种各样的理由,但是我对Clojure开发社区这种对待框架的主流观点不太认同。我认为框架对Clojure开发是有用的。首先,让我解释一下什么是框架。我还没有读过任何让我满意的框架定义,我认为针对框架的一些仇恨源于对它们究竟是什么缺乏明确的定义。它们只是对开发库的名称上的美化吗?它们必须具备魔法吗?有没有强制要求它们的价值必须大过它们制造的麻烦呢?所有这些问题都将在本文中阐明。

我认为,要想让一个框架的效用容易被大家理解,就必须对这个框架所服务的目的,以及如何实现这一目的,作一个清楚地描述,并且这个描述还应该阐明什么是一个好的框架,而坏的框架为什么最终会伤害我们。我希望你会发现这个讨论有趣而且令人满意,并且能够为你提供一个崭新的,有帮助的视角,不仅仅是从框架方面,更是从总体编程方面。即使你读完本文后仍然不想使用框架,我也希望你能更好地理解一个框架所要解决的问题,这会帮助你更好地设计应用程序。

框架具有二级优势,本文也将介绍这些优势。概括来说,框架使得可重用组件的生态系统得以存在。框架使编程变得更加有趣。并且框架使初学者更容易出成果。

在本文的最后,我将对Clojure编程语言特别适合创建真正了不起的框架的特性作一个介绍。


640?wx_fmt=png

什么是框架?

 

框架是一组开发库的集合,它们的职责是:

  • 管理对编写应用程序所需资源进行协调的复杂性…

  • 通过提供这些资源的抽象...

  • 以及在这些资源之间进行通信的系统...

  • 在一个环境中...

  • 使得程序员能够专注于编写特定于其产品的业务逻辑。

下面我将以Rails框架和操作系统(可以称其为终极框架)作为例子,详细介绍上面的每一点。

你可能会想,操作系统怎么会是一个框架呢?当你查看上面的框架职责列表时,你会注意到操作系统不但处理了所有这些职责,而且处理得非常好。简而言之:操作系统为硬件资源提供虚拟抽象,这样程序员就不必关注细节,比如将字节推到某个特定磁盘上或管理CPU调度。它还提供了带有由正斜杠分隔的名称组成的寻址系统的分层文件系统的协议,并且这些协议提供了一种资源相互通信的方法(进程A可以写入/foo/bar,而进程B可以读取)。相像一下,如果每个程序员都有自己的特定的寻址系统,那将是一场灾难。而现在操作系统为我们处理了这个问题,因此我们可以将重点放在特定于应用程序的任务上。

操作系统作为一个非常成功的框架,下面我们将详细介绍它们的一些特性,以便更好地了解一个好的框架设计应该是什么样子。

协调资源

资源是程序用来完成工作的“材料”,它们可以分为四类:存储资源、计算资源、通信资源和接口资源。存储资源的示例包括文件、数据库和缓存。计算资源的示例包括进程、线程、参与者、后台作业和core.async进程。通信资源则有HTTP请求、消息队列和事件总线。而接口资源通常包括键盘和鼠标,再加上屏幕和用于在屏幕上显示内容的系统:如GUI工具包、浏览器和DOM等等。

专用资源建立在更通用的资源之上(有些人将这些专用资源称为服务或组件)。我们从硬件开始,在上面构建虚拟资源。对于存储资源来说,操作系统从磁盘和内存开始,并将文件系统创建为顶部的虚拟存储资源。像Postgres这样的数据库使用文件系统创建另一个虚拟存储资源来处理文件系统不能满足的用例。Datomic数据库则使用其他数据库(如Cassandra 或 DynamoDB)作为其存储层。浏览器创建自己的虚拟环境并引入新的资源,如本地存储和cookies。

对于计算资源,操作系统引入进程和线程作为虚拟资源的代表和管理程序执行。Erlang语言使用了一种与底层操作系统显著不同的流程模型创建了一个环境。Clojure语言的core.async处理了同样的问题,它引入了通信顺序进程(CSP)计算模型。它是由Clojure宏定义的虚拟模型,先“编译”成核心Clojure,再编译为JVM字节码(或JavaScript!),然后必须由操作系统进程执行。

接口资源遵循相同的模式:在可视显示端,操作系统向监视器绘制图像,应用程序向自己的虚拟画布上绘制图像,浏览器引入了自己的资源(DOM和<canvas>)的应用程序,而React则引入虚拟DOM。Emacs是运行在操作系统之上的操作系统,它有自己的windows和frames。

资源管理自己的实体(entity)。在数据库中,entity可以包括表、行、触发器和序列。文件系统的entity包括目录和文件。图形用户界面的entity包括窗口、菜单栏和其他组件。

(我意识到,这种对资源的描述并不像程序员喜欢的那样严密,公理化和详尽。其中的一个不足之处是资源和应用程序之间的界限不是非常清晰:Postgres本身是一个应用程序,但从Rails应用程序的角度来看,它又是一个资源。不过,希望我在这里对资源的解释已经足够清楚,你对我对资源的所有阐述都能够理解。)

协调这些资源本身就很复杂。其实,协调任何事情都不简单。我还记得我第一次在小联盟比赛中因为缺乏协调性而被棒球打到脸上。还有一段时间,当时我还是个孩子,我上跆拳道课,当每堂课结束的时候,我经常背靠着墙坐在地上,痛苦地闭着眼睛。原因有两个:a)我妈妈因为某种原因拒绝给我买护具,b)我缺乏协调性,在对抗练习时不能保护好自己。

在构建一个产品时,你必须决定如何创建、验证、保护和处置资源实体;如何将实体从一个资源传递到另一个资源;以及如何处理诸如竞态条件(race condition)下的定时安排和在资源交互时出现的故障处理等问题,所有这些都需要好好协调。例如,Rails框架被设计用来协调浏览器、HTTP服务器和数据库。它必须将用户输入传递到数据库,还必须通过HTTP请求和响应检索和呈现数据库记录以供用户界面显示。

没有一个公认的或绝对正确的方法来协调这些资源。在Rails框架中,HTTP请求将被发送到一个控制器(Controller),该控制器负责与数据库交互,并使数据能够为视图(View)可用,该视图将渲染可以发送回浏览器的HTML。

你并非必须使用Rails框架的MVC(Model/View/Controller)模式来协调Web应用程序的资源,但你必须以某种方式协调这些资源。这些决策涉及到权衡和施加约束,以实现可扩展性(创建一个足够通用的系统以让新资源加入)和控制力(允许系统充分利用特定资源的独特功能)之间的平衡。

即使对于经验丰富的开发人员来说,这也是一项非常困难的任务,并且你所做的选择可能会产生负面影响,而且这些负面影响直到你进行了大量投资之后才能明显看到。例如,在Rails框架中,ActiveRecord(AR)为数据库提供了一个很好的通用抽象,但在早期,它很容易生成效率极低的SQL,而且有时很难生成高效的SQL。所以你经常需要手工编写SQL,这就首先消除了使用AR的一些好处。

对于完全初学者来说,正确地做出这些权衡是不可能的,因为这样做需要经验。初学者甚至不知道做这些决定的必要性。同时,有经验的开发人员更愿意花时间和精力解决更重要的问题。

而框架会帮助我们做出这些决策,使我们能够更加专注于业务逻辑。框架通过引入通信系统和抽象来实现这一点。

资源抽象

我们的软件通过抽象与资源交互。我认为抽象是:

  • 用于表示资源的数据结构

  • 资源响应的一组消息

  • 资源用于调用应用程序代码的机制

 

 

 

(抽象在这里可能是一个可怕的词。每一个三年以上的开发者对它都有自己的定义,如果我的定义与你的不一致,那请你放过,让我们继续下去:)

Rails框架通过ActiveRecord抽象,公开了一个你的应用程序代码可以与之交互的数据库资源。其中表对应于类,而行则对应于该类的对象。这是一个带有折衷的选择,行可以表示为Ruby的哈希对象(类似于JSON对象的基元),这可能使它们更易于移植,但同时也使得简洁地表达数据库操作(如save和destroy操作)变得更加困难。抽象还可以响应查找(find)、创建(create)、更新(update)和销毁(destroy)等操作。它通过生命周期回调方法调用应用程序的代码,比如before_validation方法。而框架的意义是通过识别这些生命周期并在它们不在底层资源中时为它们提供接口,来体现它的价值。

你已经知道这一点,但这里值得再强调一下:抽象让我们在更高的层次上编码。框架抽象解决了我们对特定于资源管理的关心,让我们专注于构建产品。框架通常设计良好,能够实现松耦合。

没有什么比Unix框架引入的大量成功的文件抽象能够更好地证明了这一点。接下来我们将详细介绍,因为它体现了设计智慧,可以帮助我们理解什么是一个好的框架。

文件操作的核心功能包括打开(open),读取(read)、写入(write)和关闭(close)。文件被表示为连续的字节流,这和ActiveRecord使用Ruby对象的选择一样。在进程中,打开的文件表示为文件描述符,通常是一个小整数。open函数接受一个文件路径并返回一个文件描述符,read、write和close函数使用一个文件描述符作为参数来完成它们的工作。

这里有一个神奇的诀窍:文件并不一定是指磁盘上的文件。正如Rails框架实现了MySQL和Postgres的ActiveRecord抽象一样,操作系统(OS)实现了管道、终端和其他资源的文件抽象,这意味着你的程序可以使用与将文件写入磁盘相同的系统调用来写入它们。实际上,站在一个程序的立场上看,它只知道它正在写入一个文件;它不知道文件描述符所指的“文件”实际上可能是一个管道。

作为读者的一个练习:写几段话,准确地解释选择这种程度的松耦合设计的好外。以及这些选择如何帮助我们评估和设计框架?

这种设计是Unix著名的简单性的重要组成部分。这就是让我们能够在shell中运行下列命令的原因:

 

 


 

shell解释这条命令,然后启动ls进程。通常,当一个进程启动时,它会创建三个文件描述符(记住,它表示打开的文件):0表示STDIN(标准输入),1表示STDOUT(标准输出),2表示STDERR(标准错误),shell会将每个文件描述符设置为引用你的终端(终端可以是文件!吃惊吗?!?)。当你的shell看到管道符号“|”后,就将ls进程的STDOUT设置为管道的STDIN,将管道的STDOUT设置为wc进程的STDIN。管道链接了进程的文件描述符,使得进程可以读写“文件”,而不必知道另一端实际上是什么。不开玩笑,每次想到这一点,我的脊椎底部都会有点兴奋,因为我是个书呆子。

这就是为什么文件I/O被称为通用I/O模型的原因。在下一节中,我将介绍更多关于这方面的内容,我在这里分享它是想让你知道,如果你找到正确的抽象,你的编程环境会有多么强大。文件I/O模型在引入几十年后仍然占据主导地位,它使得我们的编程生活更轻松,甚至不必了解它的实际工作原理。

任何初学者程序员都要做的第一个经典的练习是编写一个打印“Wassup, homies?”的程序。这个程序利用了文件模型,但是初学者甚至不需要知道这种东西的存在。这就是一个好的框架需要做的。一个设计良好的框架可以让你轻松地开始构建简单的应用程序,更不会在你学习了更多知识后,阻止你构建更复杂和有用的应用程序。

关于抽象的最后一点:它们提供了调用应用程序代码的机制。我们早些时候在ActiveRecord的生命周期方法中看到了这一点。框架通常提供应用程序应如何与其环境交互的总体结构,定义了一套你可以为其编写自定义处理程序的事件集。有了ActiveRecord生命周期,before_create、create, after_create的结构是预先确定的,但是你可以定义在每个步骤中发生的事情。这种模式被称为控制反转,许多开发人员认为它是框架的一个关键特性。

对于*nix操作系统,你可以说在C程序中的main函数是一种onStart回调(callback)。操作系统调用main,然后main告诉操作系统应该运行什么指令。但是,执行指令的实际时间是由操作系统控制的,因为操作系统负责调度。这也是一种控制反转,对吧?

通信

框架协调资源,协调需要通信。而通信并不是件容易的事。框架通过将资源所说的完全不同的“语言”转换为一种或多种易于理解和高效的通用语言,同时确保可扩展性和可组合性,使通信更容易实现。框架也做了一些确保弹性的工作。这通常需要:

  • 建立命名和寻址约定

  • 制定如何构建内容的约定

  • 引入通信代理

  • 处理通信故障(如数据库关闭!该文件不存在!)

许多人熟悉的一个例子是HTTP stack,它是一种用于在浏览器和服务器资源之间通信的“语言”,它包括了:

  • HTTP结构内容(请求头和文本格式的请求正文)

  • TCP通信故障句柄

  • IP寻址句柄

 

 

 

约定

文件模型是一种“通用语言”,操作系统使用设备驱动程序在文件模型和硬件设备所说的任何本地语言之间进行转换。文件模型有命名和寻址约定,允许你使用由斜杠分隔的字符串指定文件系统上的文件,斜杠转换为内部inode(一种存储文件和目录详细信息(如所有权和权限)的数据结构)。我们已经习惯了这一点,所以很容易忘记这是一种约定;*nix系统的设计可能会使你不得不使用数字或UUID来引用文件。我在上一节中讲到的文件描述符也是一种约定。

文件模型引入的另一种约定是将内容构造为字节流,而不是位流、字符流或XML文档。但是,字节通常级别太低,因此操作系统包含了一套命令行工具,它通过将字节解释为字符(sed, awk, grep,和friends)来引入字节构造的进一步约定。最近,人们引入了更多的工具,将文本解释为YAML或JSON。Clojure世界有更多的工具将JSON解释为Transit。我的YAML工具不能用jack工具链来处理JSON文件,但是因为这些格式都是用较低级别的格式表示的,所以较低级别的工具仍然可以使用它们。结构影响可组合性。

文件模型的简单性使得它成为“通用I/O模型”。想象一下,如果所有的Linux进程都必须与XML而不是字节流通信的话!哎呀,那这个世界就疯狂了。拥有一个简单的、通用的通信系统,使得新资源能够非常容易地参与进来,而无需直接了解彼此。它允许我们轻松地编写命令行工具。它允许一个程序读取一个日志的同时,另一个程序写入该日志。换句话说,它支持松耦合和所有附带的好处。

通信代理

全局可寻址通信代理(像文件系统、Kafka队列或数据库)对于可组合系统的启用至关重要。全局(Global)意味着每个资源都可以访问它。可寻址(Addressable)意味着代理(broker)为独立于其客户的实体维护标识符,并且客户可以使用这些标识符指定实体。通信代理(Communication broker)意味着系统的目的是将数据从一个资源传输到另一个资源,并且它具有明确的语义:队列具有FIFO语义,文件系统具有就地更新语义等等。

如果Linux没有文件系统,只允许进程通过管道进行通信的话,那将是一场噩梦。间接信通比直接通信更灵活。它支持基于时间的解耦,因为读和写不必同步进行。它还允许参与者独立地进出通信系统。(顺便说一句,我想不出这个概念的名字,也想不出更好的表达方式,希望能得到你们的反馈。)

我认为这是框架设计中最棘手的部分。在本文的开头,我提到开发人员可能最终会绕过框架的约束,而且我认为主要的约束通常是通信代理的缺失。框架的设计者引入了新的资源和抽象,但是把它们组合到一起的唯一方法是通过直接通信,并且有时候还用“魔法般”的方法来处理直接通信。(我似乎记得Rails框架就是这样工作的,控制器和视图之间有紧密的耦合,并且缺少将控制器数据传输到系统其他部分的选择)。如果有人想要引入新的抽象,他们必须解开所有的魔法,并深入到框架的内部,使用(应该是)私有的代码,甚至依靠打补丁来解决问题!

我记得MongoDB发布时,我在Rails上遇到过这个问题。文档数据库(document database)资源与关系型数据库(relational database)资源完全不同,MongoDB几乎不可能参与ActiveRecord抽象,而且引入一种可以很好地与Rails生态系统的其他部分配合使用的新的数据存储抽象也非常困难。

对于更为当前的示例,前端框架可能将表单标识为资源,并为它创建一个很好的抽象,用于处理验证和表单提交生命周期之类的事情。如果表单抽象是在没有通信代理(如全局状态容器)的框架中编写的,那么将很难满足“使用表单筛选表中的行”这一常见使用情况,因为渲染表数据的代码无法访问表单输入的值。你可能会想出一些类似于定义导出表单状态的处理程序的黑客方法,但是在特殊的基础上这样做会导致代码混乱和脆弱。

相比之下,通信代理的存在可以使生活更轻松。在Clojure世界中,React框架下的re-frame和om.next包含了全局状态atom,这是一种类似于文件系统的通信代理(atom是一种内存存储机制)。它们都有定义良好的通信协议。我对Redux不太熟悉,但我听说它也包含了一个集中管理的全局状态容器。

如果使用re-frame创建一个表单抽象,就可以在全局状态atom中跟踪它的状态。还可以为表单建立命名约定,这样其他参与者就更容易查找表单的数据并对其做出反应。(剧透警告:我工作中一直使用的框架就是这样做的!)

通信系统是基础。没有它们,除了最简单的应用程序之外,你很难构建任何东西。通过提供通信系统,框架减轻了构建程序的许多认知负担。通过建立通信标准,框架使开发人员能够创建可组合的工具,这些工具让使用该框架的每个人都受益。标准使基础设施成为可能,而基础设施使生产力得以提高。

在这一部分中,我主要关注文件模型,因为它非常成功,并且我认为我们可以从中学到很多东西。其他模型包括事件总线和消息队列等等。我就不在这里一一赘述了。

环境

构建框架是为了协调特定环境中的资源。当我们谈论桌面应用程序、Web应用程序、单页应用程序(SPA)和移动应用程序时,我们谈论的是不同的环境。从开发人员的角度来看,环境是以可用的资源来区分的,而从用户的角度来看,不同的环境意味着不同的使用模式,和对分发、可用性、许可和支付的期望。

随着技术的进步,新的资源变得可用(互联网!数据库!智能手机!强大的浏览器!AWS!),新的环境将不断发展以组合这些资源,并创建针对这些环境的框架。这就是为什么现在我们谈论移动框架和桌面框架之类的东西。

我不再使用Rails框架的原因之一是因为它是一个Web应用程序框架,但是我想构建的是单页应用程序。当时(大约2012年左右?)我正在学习使用Angular,并希望使用它来部署应用程序,但是它并不是真正适合Rails框架的设计。

不过没关系。有些人为Linux编写程序,有些人为macOS编写程序,出于某种原因,有些人仍然为Windows编写程序(开玩笑!饶了我吧!)。框架是一种工具,而工具是为特定目的而构建的。如果你试图达到一个工具所不能达到的目的,那就使用一个不同的工具。

 

640?wx_fmt=png

使用框架的更多好处

 

到目前为止,我主要讨论了框架为单个开发人员带来的好处。在这一节中,我将解释框架如何让整个社区受益,框架是如何让编程变得有趣,以及(也许最重要的)框架为何对初学者来说是一个巨大的助力。

首先,让我们回顾一下,框架是一组开发库的集合,它们的职责是:

  • 管理对编写应用程序所需资源进行协调的复杂性…

  • 通过提供这些资源的抽象...

  • 以及在这些资源之间进行通信的系统...

  • 在一个环境中...

  • 使得程序员能够专注于编写特定于其产品的业务逻辑。

 

 

 

 

 

仅此一点就减轻了开发人员的巨大负担。如果我阐述的不够充分,那请你记住,这些职责的实现工作是很难的,如果每次你想使用的时候都必须这样实现一遍的话,那会让人沮丧和筋疲力尽的。实际上,让我换个说法:要是我必须实现框架的这些职责的话,那一定是令人沮丧和筋疲力尽的。这就是为什么当我在2005年第一次遇到Rails框架时,感觉它是如此的神圣。

框架给社区带来的好处

清晰的抽象和通信系统允许人们共享模块、插件或任何你想称之为框架扩展的东西,从而创建一个充满活力的可重用组件生态系统。

如果你接受我关于操作系统是框架的断言,那么你可以将通过操作系统的通信系统(套接字、文件模型等)进行通信的任何程序视为框架的扩展。比如说,Postgres是一个关系型数据库管理系统(RDBMS)资源的框架扩展。而StatsD是一个监控资源的扩展。

同样地,Rails框架使开发人员能够识别专门的资源并扩展框架以方便地支持它们。其中一个最受欢迎和最强大的是Devise,它负责协调Rails资源以引入新的用户认证资源。正如人们倾向于使用Postgres,而不是手动操作自己的数据一样,人们也倾向于使用Devise,而不是手动来管理自己的认证系统。

是否有可能为Clojure语言创建一个Devise呢?我不认为有这个可行性。Devise被设计成数据库无关的,但是由于Clojure语言没有一个真正的值得信赖的框架来指定或引入值得信赖的数据库抽象,因此没有人能够以这样一种方式编写与Devise等效的东西,使得它可以很容易地支持任何RDBMS数据库。没有这样的一个框架,就不可能有人能够编写一个你可以重用的功能齐全的认证解决方案;即使你编写了一个,其他人也不太可能看到你共享它的好处。Clojure语言正在和这些生态系统的好处擦肩而过,我认为这对Clojure来说太糟糕了。

另一个框架带来的不很明显的好处是,它们为开发人员如何使用你的语言构建应用程序提供了一个连贯的故事,这使你的语言更具吸引力。构建应用程序意味着为目标环境(桌面、移动、SPA等)协调资源。如果你的语言没有针对目标环境的框架,那么学习或使用该语言的风险更大。构建产品有一个更高的障碍:开发人员不仅必须学习语言的语法和范例,他们还必须弄清楚如何使用语言的范例来执行抽象和协调资源的复杂任务。如果你的目标是创建一个大众市场产品,那么选择一种没有目标环境框架的语言是一个危险的选择。

最后,框架成为你可以为其创建工具的基层。文件系统的引入使得人们可以编写易于创建和操作文件的工具。Rails框架的抽象使得生成用于创建新的数据库表,以及用于与之交互的整个堆栈(model, view, controller)的代码变得更加轻松。

框架使开发变得有乐趣

如果你仍然认为框架是多余的或者麻烦大过它们的价值的话,相信我,我理解你。当我从Rails框架切换到Clojure时,我非常喜欢它的“使用库,不用框架”的方式。我感觉使用框架是没有必要的,因为所有的部分都是如此简单,以至于我把它们粘在一起时不费吹灰之力。而且,我觉得解决一个我熟悉的问题对我来说是纯粹的乐趣,因为它帮助我学习了这门语言。

好吧,就当我放了一个无聊的千年臭屁吧。因为我现在不再认为这工作有趣了。我想要构建产品,而不是构建用于构建产品的基础架构。我想要一个插件,它可以帮我处理重置密码的过程。我想要一个管理面板,五分钟内我就要它能够工作。框架能够处理那种理想情况下只需要完成一次的工作。我不想每次想做点什么的时候都要一遍又一遍地做同样的工作。

对我来说,编程是一项创造性的工作。我喜欢做些傻事,并且把它们摆在人们面前看看会发生什么。Rails框架帮助我构建了像phobiatopia.com(现在已经失效)这样的网站,在那里用户可以分享他们害怕的东西。这个网站会使用用户的IP地址来得到用户的地理坐标,并且使用谷歌地图来显示全球恐惧地图。它显示很多人害怕熊。

框架让你专注于构建应用程序的有趣部分。框架可以让你更快地实现一个想法,无论这个想法有多么愚蠢。

框架帮助初学者

框架可以帮助初学者构建真实的,并且能真正运行的应用程序,他们可以自豪地向朋友们展示这些应用程序,甚至可以用它们来赚钱,而不必完全理解,甚至不需要知道他们使用的所有技术。能够变魔术般地召唤出一个完整的创造物,不管它有多小或者多么粗糙,it is the very breath of wonder and delight。(我不知道这句英文什么意思,但我喜欢它的发音!)

有一种看法认为:框架是不好的,因为它们允许初学者构建东西,而不必知道它们是如何工作的。ActiveRecord正在腐蚀年轻人,因为它允许他们构建应用程序,甚至在他们不知道如何正确发音SQL的情况下。

也有另一种看法认为:让初学者更容易构建出东西是不对的。人们必须为了学习而努力或经受磨难,否则就不合乎道德。

忘掉上面这些愚蠢的,无聊的废话。我认为快乐胜过每一次的痛苦。让你的学习更加快乐,让更多的人从你创造的任何工具或产品中获益。

我是个摄影师。我有一台专业相机,我知道怎么用。我的一些照片需要大量的技术知识和专业设备(如下图):

640?wx_fmt=jpeg

上面这张照片不是你能用手机创造出来的东西,不知道为什么,我能享受我自己的技术和艺术创作,但是我也不讨厌“傻瓜”相机的存在,我也不抱怨人们喜欢它们。

新手从专家指导中受益匪浅。我不认为你能用手机拍照而成为一名大师级的摄影师,但是有了手机的“指引”,你可以拍一些非常好的照片并为它们感到骄傲。而如果你真想成为一名摄影大师,这种积极的反馈和成就感会激励你坚持下去,学习一些困难的东西,而获得更多的进步。

框架通过在“流沙”和“陷阱”周围创建一条安全的路径来提供这一“指引”,来帮助你在创建应用程序时规避这些陷阱。框架帮助初学者,这是它的一个好处,而不是一个bug。

 

640?wx_fmt=png

我的Clojure框架

 

框架用来管理协调资源的复杂性。看到了吗?“Managing Complexity”(管理复杂性)是Clojure英文全称Clojure Managing Complexity McCarthy-Lisp的中间部分。就我个人而言,我想要一个单页应用程序(SPA)框架,Clojure语言的设计和理念有很多方面,让我认为创建一个真正了不起的框架是非常可能的。下面我只举几个例子。

首先,考虑一下像sed和awk这样的Linux工具如何实现文本导向的。开发人员可以通过将文本格式化为JSON或YAML向文本添加附加结构,而这些文本处理工具仍然可以处理结构化的文本。

同样,Clojure语言强调简单数据结构,这意味着我们可以创建专门的结构来表示表单和Ajax请求,以及处理这些结构的工具。但是,如果我们用地图和向量来定义这些结构,我们仍然可以使用一个庞大的功能生态系统来处理那些简单的结构。换句话说,创建专门的结构并不妨碍我们使用为更简单的结构而构建的工具,对于许多其他语言来说,情况并非如此。

第二,Clojure语言基于协议(protocol)和多方法(multimethod)的抽象机制非常灵活,这让我们在新资源可用时能够方便地实现它们的抽象。

第三,你可以在前端和后端使用相同的语言!!!!不仅如此,Transit还允许两者轻松地通信。这就消除了其他语言框架必须解决的一整类的协调问题。

在我看来,Clojure粉丝们认为框架的麻烦超过它的价值的立场完全是一种倒退:Clojure语言给我们打好了创建一个真正了不起的框架的基础!它就是那么简单易行。这不是做梦,这是事实!

我的目标是建立一个SPA框架,帮助目前和未来的Clojure开发人员,使我们的想法能够快速地投入生产。我希望我们能够花更多的时间在困难的事情上和有趣的事情上。我希望我们在发布新产品时能够更加轻松和自信。

我正在构建的框架是建立在一些真正令人惊叹的库之上的,这些库主要包括Integrant, re-frame,和Liberator。Integrant引入组件抽象,并负责处理应用程序的启动/停止生命周期。re-frame为前端提供了一个文件系统和通信代理。Liberator引入了一个处理HTTP请求的标准模型。

如果我的框架最终有用的话,那是因为这些工具的创建者已经完成了所有繁重的工作。我的框架引入了更多特定于创建单页应用程序的资源和抽象。例如,它创建了一个用于包装Ajax请求的抽象,以便在请求处于活动状态时轻松地显示活动指示器。它也创建了一个表单抽象,用于处理输入更改和表单提交发送,以及整个表单生命周期(包括fresh,dirty,submitted,invalid,succeeded等等)的所有管道。它同时为组织数据制定了一些约定。

正如我所提到的,这个框架还没有完全准备好供公众使用,因为在实现我的想法的时候,我仍然对有些地方举棋不定,而且现在基本上没有任何文档。但是希望在不久的将来我能够将它发布出来。

但是,如果你现在就想看到一个使用这个框架的生产应用程序的话,我邀请你去看看Grateful Place(感恩之地)这个网站。这是一个社区网站,为那些希望通过实践同情心、感恩、慷慨和其他积极价值观来支持彼此的人提供恢复力、平静和快乐。通过加入这个社区,你不仅仅是帮助自己,你还通过让别人知道你支持他们并分享他们的价值观来帮助他们。

你可以到处点击看看那些漂亮时髦的动画加载。如果你被它感动了,请一定加入!我喜欢在相互支持共同价值观的背景下与人互动。除了Clojure,我唯一关心的事情就是帮助人们开发工具来引导他们在这个疯癫的世界里航行。

同时,我将继续努力使这个框架为公众使用做好准备。期待另一篇博客文章分享Grateful Place(感恩之地)网站如何实现的一些细节。最后,期待框架本身的发布声明:)

如果你不耐烦等我的新框架,那就看看已经存在的一些神奇的Clojure工具(如下):

  • Luminus:http://www.luminusweb.net/

  • Fulcro它可以做我希望我的框架能做的一切,只是更好:http://book.fulcrologic.com/

  • re-frame仍然是我最喜欢的前端框架:https://github.com/Day8/re-frame/

  • duct很不错,但它的文档还不太好:https://github.com/duct-framework/duct

  • Coast on Clojure,一个全栈Web框架:https://github.com/coast-framework/coast

 

原文:  http://flyingmachinestudios.com/programming/why-programmers-need-frameworks/

本文为CSDN翻译,转载请注明来源出处。

【END】

易学,好用的Python,发展前景居然也这么好:

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

640?wx_fmt=jpeg

 热 文 推 荐 

☞重磅!全球首个可视化联邦学习产品与联邦pipeline生产服务上线

撬动百亿台设备,让物联网“造”起来!

☞ 细数微软 Teams 的 14 宗“罪”!

☞ 华为暂没有推出鸿蒙手机计划;苹果否认 iPhone 辐射超标;Kotlin 1.3.50 发布 | 极客头条

☞ 我是如何通过开源项目月入 10 万的?

语音识别技术简史

意大利黑手党四大家族做了条"犯罪链", 把家族的权利被分的明明白白的……

Istio 庖丁解牛六:多集群网格应用场景

如何写出让同事无法维护的代码?

 

 

 

 

 


 
展开阅读全文

插件框架系列之一——为什么需要插件和插件框架的任务

11-10

很多情况下我们的小组或者部门甚至我们的公司都会专注于软件的某一应用领域。此时客户的需求有很大的重叠度。为了避免重复的工作,程序员们会通过合理的架构将重叠部分制作成可以重用的模块,如DLL文件,直接用到新项目中。这确实是一个不错的选择,但是仅仅使用动态链接技术最终的执行文件并没有很好的扩展性,并且在每次创建系统原型时我们都做了许多重复的工作。全插件结构能够很容易避免这些问题。通过编写一个简单的系统结构配置文件或者使用系统配置工具就能够快速装配出一个系统原型。rnrn但是在创建全插件框架时有几个非常基本的问题需要考虑。第一,各个插件应该怎么装载。插件需要被主程序装载然后调用。第二,怎么实现界面模块和功能模块的分离。分离是为了让界面模块的更新不至于对功能模块的影响太大。第三,怎么实现界面和功能的连接。很多功能都是通过界面上的操作调用的,所以连接也是个基本的问题。当然关于连接,我们所考虑的当然不只是怎么将没有参数的方法通过点击界面上的一个按钮调用起来,还需要考虑一些复杂的情形以使装配出来的应用程序符合合理的界面设计原则。rnrn这些合理的界面设计原则有:rnrn1、如果系统需要针对登入的用户限制一些功能,最好的做法是将调用当前用户不可使用方法的节目元素的Visible属性设为false。rnrn 2、界面元素的Checked与Enabled的状态以及其它属性也要能够表示出用当前的操作、当前用户数据所处的状态、用户下一步可进行的操作。rn[img=http://img616.ph.126.net/iuFr-Vjsbolidk2sy3HIaA==/1990309560323108981.bmp][/img]rnrn 在上面的网页浏览器中,组合框中显示了当前页面的网址。这就是界面元素的属性表示了用户当前操作的——用户正在浏览网址为**的网页。状态栏中的进度条是满的,说明当前页面下载完成了,这就是界面元素表示了当前用户数据状态的例子。浏览栏、状态栏、收藏栏都是可见的,同时相应的菜单项的Checked属性都为true,这也可以认为是界面元素表示了当前用户数据的状态。如图,在当前页面中打开新网址的界面元素处于可用状态,这是由于当前有页面打开;这就是界面元素表示了用户下一步可进行的操作。rnrn3、界面不应该单调乏味,比如界面上只有按钮和菜单项。单调乏味的界面不仅影响美观,还会影响功能。在这个浏览器的界面上如果只有按钮和菜单项的话,输入网址应该怎么办呢?弹出一个对话框吗?这复杂了用户的操作,明显不符合界面设计的原则。此时带来一个问题,某个界面元素调用的方法所需要的参数需要另外一个界面元素提供。如上图所示,界面元素调用的转到某个网址的方法的参数就需要它左边的组合框来提供。当然更多的情况参数是由调用者界面元素本身提供的,在组合框中输完网址后,按回车键也能够调用转到某个网址的方法。还有些情形下我们需要提供不变的参数。如下图中设置当前搜索引擎的两个菜单项,他们的参数就是固定的,从上到下分别是:“http://www.baidu.com/s?wd=,百度”、“http://www.google.com.hk/search?q=,谷歌”。比如使用百度搜索“Plugin”这个关键 字时的调用URL为http://www.baidu.com/s?wd= Plugin。 “,”之后的文本则是了这个搜索引擎的公认名称。rnrn[img=http://img616.ph.126.net/g9LHCVSWyW8ipap2xC18Ww==/1990309560323108997.bmp][/img]rn “http://www.baidu.com/s?wd=,百度”其实表示了两个参数,“,”是一个分隔符,设置当前搜索引擎的方法的原型为Void SetSearchEngine(System.String, System.String),第一个参数表示搜索引擎的基本URL,第二参数表示搜索引擎的公认名称。这个参数用于更新状态栏中指示当前搜引擎文本框中的内容。如下图所示。rn[img=http://img623.ph.126.net/KpSRa_KsbBLlraN-KrlFfQ==/1943584714189008979.bmp][/img]rnrn 解决了这三个基本问题的插件框架已经具有很高的实用价值了,装配出的系统界面友好,能够很容易的更换界面组件使得系统的界面绚丽美观。此时可以处于效率的目的考虑一些应用情形。有时在一个系统中将会有一些功能很少被使用,但是客户又有这样的需求。在插件系统中就表现为,某些插件加载后,它提供的功能却很少被使用。所以让这些插件在系统一启动就加载是很低效的做法,如果直到系统退出它的功能仍然没有被使用,那它占据的内存就白费了,加载它所消耗的时间也白费了。解决这个问题的办法就是延迟加载,意思是系统启动时不加载,当这个插件提供的功能第一次被使用时加载。rnrn如果仍然有足够的精力,可以再提供另外一些功能。动态加载——在系统运行中项系统中增加新的插件。动态卸载——在系统运行中卸载某个插件而不是等到系统时卸载。如果在系统运行中能够确定某个插件将不再使用就可以将其动态卸载。这两个功能的对于C/S系统的客户端或者本地应用程序并没有太大的意义并且十分难以实现。rn 论坛

没有更多推荐了,返回首页