Hotwire 本身并不复杂,跟前端相比简单非常多。Hotwire 本身是服务端渲染框架的一部分,跟服务端耦合非常紧密(因为本身就是全栈框架解决方案的一部分)不会有一个人专门写前端。换句话说用 Hotwire 就不是给前端工程师用的,要目的让使用者一个人完成一个 end to end 功能,尽可能少写 js 又能达到接近 SPA 的体验 (hey.com 的 js bundle 只有 40k)。
所以要用 Hotwire 就要会后端,后端知识 + 非主流前端的知识(其实经历过 jquery 跟 backone 时代的就还好)在新生代前端工程师看来就会复杂好多好多好多。。。。。。
。但是对于已经有全栈基础的人来说(会后端,会基础 css+javascript),学 Hotwire 比 react/vue 生态轻松非常多。
现实情况是大家都提倡分工协作,全栈方案会越来越小众,所以 Hotwire 也注定不会很流行,只适合爱折腾追求单人工作效率的小团队。
刚写了一个 go 版的 actioncable https://github.com/piecehealth/actioncable,可以用得上
Rails 6 之前的 loader 在一些设置不对的情况下会有些坑,主要是报错信息跟实际问题不相符。所以才有了新的 zeitwerk loader。zeitwerk 对文件名/常量名约束的更严格,报错信息也更明确。
不方便用 Zeitwerk loader 的话先检查一下项目 autoload path 设置的有没有问题,再从错误堆栈找线索。sping stop 也能暂时缓解一下。
用的比较多的规范是 (应该也是 rubocop 默认的) 如果只有一个条件unless condition
优于if !condition
,两个以上条件用if
,比如if condition1 || condition2
关于性能优化可以看一下 https://nateberk.gumroad.com/l/apocrypha。 优化的核心思路是
- Observation (Noticing behavior in production or development)
- Hypothesis (Profiling to figure out what's causing the behavior)
- Test (Benchmarking)
- Analyze (Observing new production behavior)
书上的内容虽然作者的博客上大部分都有,不过现在才 10 美元,书也是这两年刚发得,内容没有过时,看看也能有不少收获。
postgresql 可以用pghero跟strong_migrations
Rails core team 都是用 MySQL,Postgres PR 基本没人理 https://github.com/rails/rails/pull/41288
rails 是可以在不胖,胖,超胖之间取舍,别的只能选择不胖。
就是充血模型跟贫血模型,Ruby 的表达能力强,比较适合容易实现充血模型。
先说结论:Ruby 不适合做微服务。微服务也不一定适合你的项目。
微服务主要解决的问题是“人”:项目越久,业务越复杂,团队扩张越快,一个巨型单体应用加新成员的边际效率就越低,微服务确实能解决这个问题。 有些人误以为微服务能解决性能问题跟 scalability 的问题,这些人主要是假设单体应用只有单关系型数据库。即,非单数据库的单体应用的性能,scalability,甚至可用性都高于或等于微服务。
如果说微服务主要解决的问题是提高加人的边际效率,那么 Ruby 并没有比其他语言更好。像 go 语言就不挑人,有很多工具能保证程序员不会提交太愚蠢的代码,工程师可以做到“即插即用”;微服务后业务也足够简单,作为一个螺丝钉不需要很高级的抽象能力。Ruby 保证新人提交代码质量,只能通过 code review 跟 unit test(大家想想自己呆过的公司 code review 跟 unit test 做的好不好)。说到 Rails,本来就是为单体应用而生的,如果强用 Rails 做微服务,可能只会用到 Rails 中非常小的一部分功能,很多微服务特有的问题,比如文中提到的分布式事务,或者响应 rpc 请求都要自己开发或者找社区方案,这些都与 Rails 本身没关系。
而且最重要的问题是你们公司有没有建设/维护一套微服务架构的能力,后端服务用什么语言/框架与这个能力相比都不值一提。
总结一下是如果现在项目已经有成熟的微服务架构,Rails/Ruby 做微服务肯定没有问题,只是没有多大优势。如果靠把 Rails 应用做成微服务而反推微服务架构,有点本末倒置。
其实解决“人”的问题不一定非要选择微服务。如果一个老的单体应用要继续前进、扩展,有另一条经济实惠的路:modular monolith。即可以现在单体应用本身分模块,建立边界,既可以减少新工程师理解业务知识的负担,也可以复用现有架构,shopify 就是这么做的https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity
当然微服务也有很多好处,比如你想混个架构师 title 方便过几年跑路,请务必推微服务 [狗头表情]
ruby 性能不拔尖,不过也够用了,99% 的 web 应用足以胜任。说差的要不就是那剩下的 1%,要不就是跟风的。
例如我对 Phoenix 的 live view 有兴趣,不知道跟 Rails 最近出的 turbo_stream 有什么不同。
turbo_stream 是服务端推 html 片段,页面直接替换相应的 html 片段,简单粗暴。
live view 可以理解为 state 在服务端的 react。服务端 state 改变,通过 webocket 把 diff 发给页面,页面有一个小的 js 库根据 diff 改变 html。
turbo_stream 是 sever agnostic 的,任何 web 后端框架都可以用,包括 Phoenix。
live view 是基于 OTP 的,只有 Phoenix 可以用。
turbo_stream 基本是 web 老一套包装包装,上手不难。
live view 改变了 web 的开发方式,很多理念完全是新的,用起来别扭,我至今未上手。
live view 是可以完全不写 js 的,turbo_stream 没有要革 js 命的意思,标配 stimulus 一起用。
国外的企业同事之间不讨论政治宗教不是很正常的事情吗。越多元化的地方越什么都不能说,说什么都能得罪到部分人。
我经历过的外企政治正确有
https://ruby-china.org/topics/40583
但是,历史遗留问题依然需要解决。随着 Fiber Scheduler 在 Ruby 3 引用来提高 I/O 密集场景下单一线程利用率极低的问题;我们需要进一步解决,计算密集场景下,多线程的利用率。 为了解决这一问题,Ruby 3 引入了 Ractor 模型。
先看你要解决的是什么问题,rails 项目可不是计算密集场景
就算 ractor,fiber 成熟了,对 rails 使用者也应该是无感知的,业务代码都会跑在单个 ractor/fiber 里,是框架跟 webserver 决定的,就像现在 puma rails 都用多线程编程,但是作为 rails 使用者几乎不需要写多线程代码,如果对多线程理解不好,多线程代码反而会拖慢项目速度,比如你多线程查数据库,别的请求就拿不到数据库连接。
您说的没错,Ruby 是众多编程语言“爬楼梯”吊车尾的,这点毋庸置疑。如果需要处理“爬楼梯”场景,java 也可以略过,直接上 c c++ rust。
绝大部分应用处理的是“坐电梯”的事情,语言之间的差距是“走进电梯里的那一小步”,即使有差距也并不明显,主要看电梯调教的怎么样。
Ruby 慢这种事没什么好争的,但是“应用慢是因为 Ruby”这样的结论大部分情况是不客观的。
所以面试考算法是有道理的,这个方法慢主要是因为写的有问题。
def fib(n, cache = {0 => 0, 1 => 1})
return n if cache[n]
cache[n - 1] ||= fib(n - 1, cache)
cache[n - 2] ||= fib(n - 2, cache)
cache[n - 1] + cache[n - 2]
end
java 可能对烂代码有优化,如果很需要这种优化就选 java 吧。
对运维来讲 nosql 肯定方便一点;对开发来说还是 sql 数据库写业务简单,完全不需要提前设计 key 跟索引。
规避网络请求
可以用vcr
puts 是一个 IO 操作,可以看作是一个很短暂的 sleep,这样 2-1=1 的线程有很大几率等到 1-1=0 的线程,一起退出循环。多跑几次下面的代码也会有减到 -1 的情况。
这个测试
RSpec.describe do
describe 'method' do
let(:instance) { A.new }
it 'test public method' do
expect(instance.end_method).to eq('abcd')
end
end
end
测
class A
def end_method
return_a + return_b + return_c + return_d
end
private
def return_a
'a'
end
def return_b
'b'
end
def return_c
'c'
end
def return_d
'd'
end
end
代码覆盖率也是 100%,广义的覆盖率是指测试执行以后多少比率的被测代码被执行过。
另外我更推荐用 Rails 内置的测试框架,一是因为 RSpec 语法太花哨,增加新手学习成本,学会了也没什么好处;二是 Rails 跟内置的测试框架配合更好,rspec-rails 现在还不支持并行跑测试,Rails 多数据库的测试 RSpec 也需要打 patch 才能跑。
我支持提交的代码需要被测试覆盖,但是不一定要测试驱动,我更习惯先写代码再写测试,写代码的时候也能顺便理清思路。而且测试作用除了保证现有代码符合预期,也能增加日后重构/做改动的人的信心,对有年头的项目尤其重要。
试试 server sider rendering?https://github.com/reactjs/react-rails#server-side-rendering
mysql2 是一个 mysql c client 的 wrapper,io 操作在 c 那边,用不上 fiber。用 fiber 的是https://github.com/socketry/db-mariadb。
生产力是杠杠,但我觉得 Rails 的性能还是要差些,当项目做大了以后,比如我们的一个 API,用 Rails 5.2 + Jbuilder。500 左右的 RPM,在缓存全中的情况下服务器响应时间还是要 400ms 左右,JSON 内容有 400kb 左右。
我们 RPM 比 500 高非常非常多,响应时间 P50 不到 30ms,P95 150ms 左右,供参考。
Rails 一个 action 能根据 Accept Type 返回不同的形式,如 html, json, xml。Accept Type 可以通过 http header 指定,也可以通过 url 后缀指定。不指定的话默认的就是 html,即 https://ruby-china.org/topics/40441 等同于 https://ruby-china.org/topics/40441.htmlrails返回给你一个html页面。,告诉
这是有人挖坑需要你来填的问题,就算你能找到捷径,也是坑上加坑,不是填坑。
你想测一个本身很复杂的东西,你对它又不够了解,那是没法测的。
真正解决方法也不是技术上的了:短期来说要让你老板知道这坑不是你挖的,要不就绕着走,要不就填。要填的话又需要多少工作量多少收益跟老板讲清楚。通过一些“技巧”坑上蹦迪是最害人的。长期来说是你们团队 code review、测试覆盖不规范,不纠正的话代码会走上超难维护的道路。
你要是测 SaleReport,就往组成 view 的表里插数据。你的测试要依赖 SaleReport,就直接 mock。
直接 mock SaleReport 查询的返回
可以先加我们 hr 聊聊,微信 ch3_monkey