php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你

2023-08-26 0 6,374 百度已收录

作者|贝尔·凯塞尔斯

译者| 新月

出品| CSDN(ID:CSDNnews)

在本文中,我们解释了使用框架构建软件如何不利于软件的可维护性。 我认为:

有哪些框架

首先,让我们弄清楚框架到底是什么。 框架不仅仅是使用第三方代码,也不仅仅是一种方式或结构:

软件框架(softwareframework)一般是指为实现某种行业标准或完成某项特定的基础任务而制定的软件组件规范,也指为实现某种软件而提供该规范所需的基本功能的软件产品组件规格。

软件框架和普通代码库之间有几个关键区别:

根据定义,框架的主要功能是提供功能、行为、流程和默认值,所有这些都是框架外部的,其中一些无法修改或指定。 框架允许用户添加代码,但不允许修改其代码。

所有软件框架都会带来维护问题,但我个人对框架的经验仅限于 Web 服务(API、后端、全栈)、命令行和 GUI。 2022 年,越来越多的软件正在向 Web 方向发展。 因此,本文讨论的示例仅限于 Web 框架。

人们使用框架以更标准化、更快、更容易、更安全、更可扩展、更一致或更有趣的方式开发软件。 但讽刺的是,根据维基百科的说法,使用框架并没有任何好处,只有缺点。

标准化背后的想法是迫使开发人员根据预定义的形式编写代码。 除了使用框架来统一代码的组织形式之外,API和逻辑也更容易识别。 然而我发现结果却适得其反。 2021 年 DevOps 状况报告(参考链接:)表明,使用框架等技术根本不能保证项目成功。 强迫开发人员使用框架只会让情况变得更糟。

效率低下的公司的弊病通常表现为这样一个事实:一个团队定义了其他团队必须遵循的标准、流程、实践、框架或结构。

相比之下,高绩效的公司往往缺乏这种所谓的“统一标准”。

换句话说:技术的强制性标准化往往得不偿失。

当然,这也不是没有道理的:如果你强迫公司里的每个人都使用Django,不管项目的实际情况如何,那么最终一定会有很多项目因为选择Django而到处碰壁。

也就是说,框架确实为项目或团队带来了好处。 此外,标准化(和统一)基本上是无用的,而且弊大于利。

一个项目的开发速度、乐趣和难度很大程度上取决于项目所处的阶段。 模型的代码是借助框架生成的,可以节省编写初始代码的时间。 我也同意这一点。 而且,对于一个发展了十几年的中小型团队来说,节省的时间(半个小时?)微不足道。 特别是,在这么长的时间里,框架可能已经生成了数百个这样的模型,而剩下的数万个小时都花在了更改和维护现有代码上。 下面,我详细说明一下,从项目长远发展的角度来看,这些短期的“开发速度提升”是换来的可维护性的损害。

据悉,安全性和性能非常依赖于环境。 框架向您的项目添加了大量代码。 如果幸运的话,这种代码是无害的; 但如果你运气不好,它可能会带来很多潜在的点击和大量的开销。 我将在下面展示,在不使用框架的情况下似乎更容易保护和提高性能。

“不利于可维护性”是什么意思?

软件已经成功启动并投入使用,我们只需正常维护即可。 维护保养一般分为以下几类:

然而,在本文中,我将考虑软件上线后的所有更改作为维护。

在维护期间,任何妨碍维护工作继续进行的激励措施均应视为损害。 因此,如果框架的使用减慢了新功能的发布速度,则被认为是有害的。

据悉,如果在软件开发初期,使用框架有助于快速发布功能,但相应的代价是后期新功能的发布速度变慢,这被认为是不利的。可维护性。

第三个危害是框架的使用需要我们付出额外的努力,但这部分工作并不为客户提供价值,比如框架升级、弃用、教育和信息摄入(比如学习新功能)等。这种工作需要很高的价格,而且往往是稀缺资源。 比如,你需要花费大量的时间来升级技术栈。 最初,这些时间应该花在提供用户或市场想要的新功能上。

最后一个危险是,将来该框架可能不再适合该项目。 如果框架往不同的方向发展,或者使用该框架的软件往不同的方向发展,那么两者就不再契合。

框架与个人或团队有不同的目标

php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你

Ruby on Rails 创始人 DHH 曾说过:

其实你对框架寄予了很大的希望,但是框架并没有给你任何承诺。 框架可以朝创始人喜欢的任何方向发展。 而你只能像忠实的兔子一样默默跟随。

我确信大多数框架的创始人对用户没有敌意,他们真正关心用户,DHH 也绝对希望用户在使用 Rails 时感到高兴。 而且,这种创始人更关心的是有多少用户愿意使用这个框架并一路陪伴,而不是你在未来十五年到二十六年能够继续创造价值。

许多 Web 框架(例如 Django、Rails、Spring、Gatsby 和 Symfony)在其营销中都提到了维护和可维护性。

Symfony:提高 PHP Web 应用程序的创建和维护速度。 放弃重复的编程任务,享受控制代码的力量。

那么他们是怎么做到的:

使用最佳实践来确保应用程序的稳定性、可维护性和可升级性。

Rails 关于框架如何提供长期支持的官方立场是:

当某个版本系列不再受支持时,您有责任修复错误和安全问题。 我们向 git 提供修复和版本的向后移植,但不提供新版本。 如果您无力维护自己的版本,则应升级到受支持的版本。 (参考链接:)

他们的立场很明确:该框架不会提供长期支持。 为了让项目使用最新版本的Rails,需要更新或迁移框架,但这种工作需要资源。

此外,虽然该框架与您现在的目标完全一致,但未来呢? 尤其是刚刚启动的项目,谁能预测未来呢? 你的产品会坚持Web应用路线吗? 您确定以后只发布Windows桌面版应用程序吗? 您确定关系数据库是未来几年最好的存储解决方案吗? 您确定需要可扩展性吗? JavaScript PWA 会在六年内存在吗?

然而php强制转换,当您选择一个框架来构建您的产品时,您就深深地受其束缚。 永远被束缚。 在项目开始时,当您掌握的信息最少时,您会做出最关键的决策。

框架设计中的权衡可能会损害项目的可维护性

与任何其他软件一样,框架创建者必须做出权衡。 例如,从流行框架的网站推广可以看出,所有流行框架越来越注重开发速度和可扩展性。

php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你

然而,这两个特性与可维护性无关,并且在某些情况下两者都会损害可维护性。

开发速度的提高部分来自样板代码的生成,但更多的时候来自继承。 当框架生成代码时,意味着创建新的代码,但它不负责维护这些代码。 像react-boilerplate或create-react-app这样的框架会生成大量样板代码,它们只是代码生成器。 但代码必须维护,否则就会降级并引发各种问题,比如大量重复、不一致、不兼容等,也就是我们常说的“代码腐烂”。

框架可以通过其他方式解决代码模具问题,例如将所有代码打包到一个超类(或可重用函数)中,以便可以在合理的地方统一提供样板代码。 作为用户(即使用框架的开发人员),您可以继承类,或者以 mixins 的形式使用其他类、模块或函数的代码。

例如,在Rails中,您只需要继承“一个模型”,就可以让对象公开大量方法。 作为反例,假设 Post 有三个数据库数组:

class Post < ActiveRecord::Base; end

这样,你至少可以获得767个公共类方法和487个公共实例方法,也就是说,你可以通过子类继承1200多个方法!

由于Post类提供了如此多的方法,因此您必须维护它们。 虽然,您的类为用户提供了这种方式。 这种方式存在于你的班级、你的实例中。

它们深深地埋藏在框架的代码中,维护它们成为您的责任。 这就是框架的本质,你无法改变它们,也无法控制它们。

框架甚至可能决定在某个时候弃用或更改某个技巧。 由于使用框架,我们提供了大量的公共套接字,但没有能力控制它。 关于我们的一切都会被压垮,希望框架的创建者是个好心人,提供更新,保证框架的向后兼容性和可用性。 事实上,大多数框架的创建者都是非常友好的,但没有人能保证这个API永远稳定。 像 Drupal 这样的框架提供的升级是如此巨大,以至于用户必须完全重新绘制项目并每隔几年进行一次这样的升级! 看起来有些框架很友好,会尽量保持向后兼容,但每次升级都是一小步,但更新还是避免不了。 而我们只能在必要的时候低头改变现有的代码。

虽然很多框架不像Rails那么极端,但是常见的socket包含了超过1200个trick。 但所有框架都为用户提供API、函数和类,尽管这是框架的目的。

我们使用这种代码,并随着时间的推移,将我们的代码更紧密地耦合到框架中。 直到我们的代码完全依赖于框架。

所以人们常说在框架内开发软件,而不是借助框架来开发软件,因为你真正在框架中创建了一个项目。

据悉,该框架能够提供的性能和扩展水平与其他同类框架进行了比较。 如果我们能够选择底层架构并对其进行优化,我们就可以用更少的代码编写更高效、可扩展的软件。 另一方面,各种框架因项目引发的性能问题频频出现在各大新闻头条。 例如,Facebook 的“Fail-Whale”(失败鲸鱼)风暴就是由 Rails 性能不佳引发的,随后 Facebook 宣布用 Java 重新绘制了 Rails 代码库。 这场风波证明大多数框架都会显着降低性能开销。

解决扩展和性能问题的常见方法是选择合适的架构,优化底层代码,减少总代码大小,这意味着我们必须能够在发现性能问题时自由更改代码。 只有掌握了足够的信息,我们才能做出正确的选择和优化。 而且框架会损害可扩展性,因为我们很难从一种框架迁移到其他框架或者更合适的框架,或者构建更合适的设置。 当遇到“Fail-Whale”这样的问题时,我们都希望优化有问题的代码,而不是重新绘制Java中的所有代码。

php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你

构建框架是为了控制您的项目

使用框架开发软件时,项目必然与框架深度绑定。 每次我们在Rails中写:belongs_to(:author),或者在Django中:models.ForeignKey("Band"),都会让我们的项目与框架的绑定更加紧密。

如果只有一小部分代码绑定到框架上,这样可以保证一定程度的可维护性。 然而,当这些绑定的覆盖范围较大时,边界就变得模糊,或者完全消失,就很难维护了。 当我们的领域和业务逻辑与框架代码混合在一起时; 中层业务概念与底层架构机制相混合; 当业务逻辑与底层架构混合时,我们必须阅读控制器、视图、模型、工厂、服务、配置文件、库和框架代码,你可以理解为什么在案例A中创建了User,而在案例B中则没有创建User,所以可维护性不可能。

该框架体现了许多技术细节。 他们会提供一个ORM来体现数据库的处理。 有时开发人员甚至不需要知道他们正在使用数据库。 他们只需调用 model.save 或 User.find_by(email:"example.com"),就可以保存或获取数据,甚至不知道数据实际上存储在 PostgreSQL、sqlite 或 MongoDB 中。 实际上我们不会绑定到特定的数据库,而是绑定到 ORM 和框架。 您可以自由使用任何数据库,但要付出另一个 ORM 和框架的代价。

HTTP、存储(如数据库)、事件总线、日志、消息传递等底层机制,这些都是细节,与你的业务逻辑和领域无关。

会计应用的框架应该叫“会计”,而不是Spring&Hibernate。 @叔叔马丁

然而,此类框架也鼓励开发人员将逻辑与框架代码混合在一起。 它们提供了各种API、类和函数供我们在业务逻辑中使用。 为此,我们的代码不仅会与框架紧密耦合,而且会彻底混合业务逻辑和样板代码。 更糟糕的是,他们经常鼓励我们通过这样的“细节”来传播业务逻辑。 在MVC模型中,M是存储,V是模板,C是HTTP层,但它没有提供一个统一的、逻辑的地方来存储逻辑和领域代码。 框架鼓励我们将此类代码放在最接近的地方,而不是最容易维护的地方。

在框架中开发软件时,出现以下情况并不少见:

def create if User.exists?(email: params[:email])  render :new, status: :already_exists  elsif user.save flash[:success] = flash_message_for(@user, :successfully_created) redirect_to edit_admin_user_path(@user) else render :new, status: :unprocessable_entity endend
def user_params params.require(:user).permit(permitted_user_attributes | [:use_billing, role_ids: [], ship_address_attributes: permitted_address_attributes, bill_address_attributes: permitted_address_attributes])end

仔细阅读上面的代码php强制转换,会让人感到害怕。 这段代码特别缺乏连贯性。 我们的思维从领域逻辑跳转,通过框架API跳到交付机制的细节,然后跳到安全细节,跳到业务逻辑,最后返回。 看似是一段HTTP层代码,但里面却混杂了很多业务逻辑。

如果是在干净的分层架构中,我们肯定会把这种技术细节分开,防止它们混在一起,同时把业务逻辑放在一个地方。

在这样的框架中,框架的作用并不重要,域(或层)的意义在于独立,没有任何依赖。 这样的域代码不依赖于任何技术细节,例如反序列化 JSON、HTTP contax、数据库事务、连接池等。这样的域只关心域语言,例如它只会调用具体方法 posts_repository.create(post )。

这样的系统具有很好的可维护性,因为所有代码的作用都是非常明确的。 这样的系统是孤立的,也是一个整体。 如果你想改变Post的存储方式(比如放弃MongoDB,直接将Markdown文件保存在c盘),只需要改变PostsRepository即可。 任何与业务逻辑相关的代码都不需要移动。

将这些实现细节放到一个单独的层中,软件会更容易维护,因为代码更改是分开的。 这样的结构,虽然使用了框架,但也会被扔到一边,一次只能更换一小块的难度就大大增加了。

php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你

采用前馈方式采用框架,除了享受框架的好处外,还可以防止可维护性受损

很多人可能会说,不使用框架意味着我们需要手动编写所有代码。 这些非黑即白的想法有点太极端了。 我们可以很好地使用库和框架,而且还可以编写良好的代码。 我们应该聘请(安全)专家来编写与安全相关的代码。 如果可以预防,我们为什么要学习如何编写加密算法或处理密码的代码。 我们应该使用一个库来处理这种细节。

然而,我们应该明确指定一个地方。 负责将HTTP路径映射到方法调用的代码应该放在HTTP层,并且不应该涉及任何业务逻辑。 隔离度越高,可维护性越好。 诸如代码令牌身份验证之类的处理不应由我们进行编码,而应合并到单个有界区域中。 最好封装一下,转换成领域语言,比如authentication.is_known_as_admin(request.token)。

发送消息的方式应该简单地定义为messenger.deliver(recipent, body)。 这个方法的背后是一个完整的消息传递框架,除了提供指数退避重试、缓冲、智能路由等功能外,还可以推送通知、发送邮件。

存储费用的方式称为expense_repository.add(expense),其背后可能是世界上最复杂的分布式数据库框架,或者是一个将费用推入某些在线会计工具的漂亮框架。

重点不是永远不要使用框架,而是将它们隔离并从一个地方统一调用它们。 我们有责任尽量减少该框架的影响范围。

然而,大多数框架预先订购了很多技术细节,但都混合在一起。 因此,我们很难将它们分开。 这样的框架早已失去了意义,很快就会变成一个库。

为什么没有这样的框架呢?

首先,我们的基本思想是不依赖框架,而是在不使用框架的情况下构建框架,这与框架本身的目标是背道而驰的。

其次,可维护性良好的软件会随着时间的推移而不断发展,以满足不断变化的需求。

从 HTTP 迁移到 Stormbus 时,您实际上不再需要 HTTP 框架。 当从基于Web的服务切换到原生联通应用服务时,您需要的不再是HTML/CSS/asset,而是序列化和处理JSON请求的技能。 可维护性要求软件不断发展。 HTTP框架提供了HTTP服务,但是当需求发生变化而不再需要HTTP服务时,没有办法删除这个框架。 一些MVC框架使用关系数据库提供ORM,但是如果ORM框架已经过时,就没有办法摆脱它们。

第三,有些实现不需要框架。 CQRS这样的框架其实就是一个简单的if语句:if(is_command){command(params)}else{query(params)},写这些代码根本不需要框架。

最后,维护的难易程度与使用特定的工具或框架无关。 正如 Symfony 强调的那样:

最佳实践确保应用程序的稳定性、可维护性和可升级性。

而“最佳实践”之一就是不要让框架控制你的项目!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php强制转换-不要让框架控制你的项目,过度依赖框架最终可能会害死你 https://www.wkzy.net/game/156402.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务