• 赞一下 LZ 的博客,但我觉得 Goldiloader 这种 gem 还是不用为好。

    本来 N+1 就是因为开发人员疏忽,但程序聪明的做了一些事情,让问题隐藏下来了。更深入一点想,是开发者对程序失去了控制:你不确定它什么时候在干什么事情,当然容易出问题。

    Goldiloader 也是聪明的帮人做了一些事情,同样容易隐藏问题:

    1. 触发一些不必要的 includes/preload。
    2. 如果用了一段时间之后,因为一些原因把某个关联 auto_include: false 了,也不知道哪些地方会重新触发 N+1 查询。
  • 这种思路本质是靠猜测前置任务的执行时间,影响因素太多且有潜在的时间浪费(任务失败,队列拥挤,Sidekiq 挂掉重启……)。

    更稳定的做法是用 sidekiq-status 这类记录任务状态的插件,比如把前置任务 A 的 id 全部记下来,在 B 里检查前置任务的状态,再做针对性处理,比如全部完成且正确率到 90% 就处理,否则把自己 enqueue 到 n 秒之后。这个方法也能很容易的扩展成多级的任务链。

    Sidekiq Pro 也有 batch 功能解决这类问题,我这种没钱用户没体验过。哪位有经验可以分享一下。

  • 说说我前段时间碰到的类似问题,希望对你有帮助。当时也是装第三方 apt 源不成功,不过错误类型是 apt-get update 报 403。后来发现是阿里云的主机对 apt 配置了代理,应该是为了让内网机器访问自家的源加速,但影响了第三方源的获取。

    代理配置在 /etc/apt/apt.conf 里,把它注释掉再 update 就没问题了,注释用 # 号:

    Acquire::http::Proxy "http://mirrors.aliyun.com/";
    
  • @lgn21st 同类型数据库肯定是用 dump 工具方便。实际上 pg_dump 如果导出成 SQL 的话,也是默认生成 COPY 。跨数据库才需要一个双方都能交流的格式。

  • @lgn21st Excel 也是很蛋疼的东西 😭 @hooopo CSV 做数据库互导还是很方便的。

  • 我觉得这个需求跟 CMS 很类似,所以 LZ 可以先找一下 Ruby 社区的开源 CMS,看看它们的实现能否有所帮助。如果自己做的话,可以找一下有没有能在运行时动态增减路由规则的 router 组件,然后 mount 进 Rails。

  • @novtopro 并没有说这是 Rails 不能做的。Changeset 也有 ROM 在尝试,进一步放到语言层面来看,又有多少特性是一种语言完全没法实现的呢?这里只是举个例子说明下各家对同一个问题的不同处理思路。

  • 前几天 Quora 上也有讨论 Rails 是否还值得学,还引得 DHH 亲自回答。见 What makes Rails a framework worth learning in 2017?

    个人看法,高度集成的解决方案总是有市场的,默认集成了很多最佳实践,可以节省很多琐碎的决策和时间,前提是你认可框架给你的大多数解决方案。Rails 一直走的就是这条路,也总是在很积极的吸收其他好的实践,所以也不算过时。而且前端再怎么变化,其核心也是更注重展示和交互的,后端功能总得有人写吧。前端现在少有高度集成的框架,原因也很简单,各个基础组件方面都还没杀出最终的优胜者呢,还不是时候选出“最佳实践”的集大成者。

    不过现在其他语言的框架都吸收了 Rails 不少优点,并且也有各自的闪光点,比如我很喜欢 Laravel 单独抽了 validator 出来在 controller 那一层校验 params 的想法,更喜欢 Ecto 的 changeset。Rails 不再是领先“友商”X 年了的选择,但对于 Rubyist 而言仍然是个好选择。这有点类似 iPhone 的现状 -- 不再是唯一的选择,但仍然是部好手机,对果粉而言更是……

  • 👍 换头像了导致我没认出来,哈哈

  • #67 楼 @jimrokliu 是的,Supervisor 是 OTP 内建的行为之一,经历了这么多年足够稳健。类似的机制其他语言并不是不能做,不过稳定性这东西是需要时间积累的。

  • 圣诞礼物:Ruby 2.4.0 Released at 2016年12月25日

    每年圣诞有惊喜

  • 思路还是 GraphQL 那一套,那我更宁愿去试试 GraphQL/Falcor。而且它的简单基于一个假设:JSON resource 结构跟数据库的表结构一致。现实中稍微复杂点的模型都不是这样的。所以 -- 不怎么看好。只说说我还算了解的 JSON API 和 GraphQL。

    JSON API 适合粗粒度场景,是 REST 思路的延伸,各方面都有所考虑,对处理 relationship 有自己的一套解法。如果自己定义 API 规范有些想不清楚的地方,这个规范值得参考,但不见得值得使用。不过如果非要在同类规范(HAL, Siren 等)中选一个,我更愿意选择它。最后,如果使用 Ember + Ember Data 的话,这个规范还是推荐的。

    GraphQL 没实际写过,感觉适合细粒度场景,适合前端频繁变化的应用,配合 Relay 和 React 可以有效的整合各个组件中的请求。我个人更喜欢这种方式的数据层,屏蔽了发起哪些查询和何时发起查询等细节。

    最后,写 API 本来就是个体力活,这部分本该自动化一点。

  • 果然大部分是 Ruby 转过去的,不过 Erlang 人群居然很少。

  • Leftover 的编程语言漫画 at 2016年12月18日

    上周刚看过,另外 The difference between Java and JavaScript 也很搞人。左箭头翻页就是。

  • #10 楼 @chenge 这个别问我,我真的不知道,而且最近也没有学图理论和相关算法的计划。

  • #7 楼 @chenge 没有,这属于图理论的,我一点都没学过。你感兴趣的话还是查 wiki 吧,理论搞懂了应该不麻烦。

    #8 楼 @nightire 有空写点 Elixir kata 练练?

  • #5 楼 @nightire Codewars 上已经有了啊

  • #2 楼 @chenge 自己去看吧 。8kyu 是最低难度,1kyu 最高,其实看颜色也看得出来啊。如果是 Codewars 自己推荐的话,应该会根据你的账号等级来推荐匹配的 kata,也不会开始就给你很难的题目。除非你自己选择 1kyu 去了……

    Codewars 里面也不全是那些枯燥的算法题,也有很多很有意思的题目。所以我还挺喜欢这个,不太想去 Leetcode。

    • 有的锻炼基础数据结构,比如这个 链表系列。我最近在写一个 系列博客,有兴趣可以看看。
    • 有的需要了解特定的语言特性,比如 A Chain adding function
    • 有的就比较奇怪了,比如 Snail 这种用递归简单的不行但用循环难得要死的题。顺带一提,Ruby 的某个迭代器方法可以一行代码搞定。
  • Codewars 难度也不大啊,5 级以上的几乎没难度。可能你开始没找对难度?他家的是数字越大难度越低。

  • 你如果坚持,同事就会很难过了 😢

  • 这个不错,以后连带的一堆 xxx_tag 的 helper 也可以去掉了。

  • #50 楼 @blacktulip 这也是萝卜白菜各有所爱。Web 框架的适用范围也不就那些。如果说比功能现在流行的框架都不差,细节处各有优劣。这些框架多余么?我觉得不多余。毕竟除了考虑功能,照顾开发者偏好也很重要。能让做 Web 的 Elixir 的开发者有个好工具,Phoenix 达到这点就足够了。至于高并发么,我只能说,虽然大多普通人都是钱够用就好,但也没人会嫌自己钱多。

  • #24 楼 @rupertqin 我对宏也只是一知半解,但 unquote 还是可用的。一个变通做法如下,来源是这里: http://stackoverflow.com/questions/30498528/how-to-create-a-dynamic-function-name-using-elixir-macro

    defmodule Util do
      for type <- ["function", "list", "map"] do
        def typeof(x) when unquote(:"is_#{type}")(x) do
          unquote(type)
        end
      end
    
      def typeof(_), do: "unknown"
    end
    
    IO.puts Util.typeof(fn -> true end)  # function
    IO.puts Util.typeof([1, 2, 3])       # list
    IO.puts Util.typeof(%{a: 1})         # map
    IO.puts Util.typeof(1)               # unknown
    

    关于 DSL 我还是持谨慎态度(并非觉得研究宏没用)。因为我觉得 Elixir 的主张就是 make the complex part explicit 。Jose 在 Domain Specific Language 里拿 validation 举的例子也挺好。

    # 1. data structures
    import Validator
    validate user, name: [length: 1..100],
                   email: [matches: ~r/@/]
    
    # 2. functions
    import Validator
    user
    |> validate_length(:name, 1..100)
    |> validate_matches(:email, ~r/@/)
    
    # 3. macros + modules
    defmodule MyValidator do
      use Validator
      validate_length :name, 1..100
      validate_matches :email, ~r/@/
    end
    
    MyValidator.validate(user)
    

    总的来说,数据结构的方式最灵活最容易组合。函数的方式适合复杂的 API,加上管道运算符也足够描述逻辑。宏的方式实现起来最复杂并且限制最大(想想 conditional validation)。这点其实跟 Ruby 社区近几年更推崇传统的 Object 组合而不是更多的 DSL 是一个意思。

  • #21 楼 @rupertqin 不知道宏该怎么写,但 typeof 这种需求用 Protocols 来做更好吧。 http://elixir-lang.org/getting-started/protocols.html

  • #25 楼 @tony612 这个不错!

    #28 楼 @chenge 是的,有些错误不用追究原因,下次还能工作就行。

  • #17 楼 @hisea 赞一个。最近在啃 Programming Elixir 1.3,这个语言带给人的思维改变是非常有意思的。做练习的时候经常有种感叹“居然还可以这样用!” 。有些事情对没了解过 Elixir 或者 FP 的人来说是很难描述清楚的。

    我一开始也不理解 let it crash 的设计,觉得如果每个异常都 crash 去了那也太频繁了。深入了解一些后才明白不是这么一回事。很多语言把异常作为控制流的一种,有些地方甚至只用 if/else/case 描述理想状态的流程,其他情况一律设计成异常类。Elixir 并不把异常作为控制流的一种,异常只用在那些“正常情况下几乎不可能发生的事情”上,比如数据库断线,HTTP 请求超时,配置文件不存在等等。那些在预料之中情况一般都用 {:error, reason} 加模式匹配处理掉了。这样想其实也挺合理。更进一步思考,没有哪个程序能保证处理了一切意外情况的,这种时候简单重启一下保证服务不挂掉反而是更好的做法。

  • 👍 开始还以为是那篇老的 7 Patterns。举的例子都挺好。Interactor 那部分感觉有点多余,其实可以跟 Service Object 合并起来。如果遵从 DCI 的模式,也应该是 Interactor 里面调用 Context 的回调(虽然我不喜欢这种做法)。

  • #11 楼 @qhwa 你们监控是如何做的呢?貌似 Elixir 现在还没有好的监控服务。

  • 老实说,这篇博客的例子举得有点不到位,作者的目的是试图把逻辑从 model 层挪出去,从而简化 validation 和 callback。如果照这个思路思考,会发现这篇文章的核心思路就是 Service Object(文章里面的 Signup)。至于单独弄出来的 persistence,测试的时候建立一个 Fake Object 也没问题,不过我觉得这跟 stub 了 model 的 save! 方法没有任何区别,只是前者通常自我感觉比较 pattern,而后者有时候会被鄙视为肮脏。

    说完这个再说 DAO,作者对 AR 的处理确实 DAO 了,这恰恰是我贴的 Martin Fowler 那篇文章所反对的,而他推荐的解决方案恰恰是 DDD 中的 Domain Model。

    我们来看看 Martin 老爷子说 DAO 这种模式有什么特点:

    The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects which capture all the domain logic. These services live on top of the domain model and use the domain model for data.

    然后 DAO 这种方式的问题:

    The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk.

    然后看看博客里把 model 的逻辑抽到所谓的 StateMachine ,不觉得有一样的问题么?model 本身空空如也,抽出来的逻辑不知道放在那里,或许也不知道起什么名字,只好起一个 "状态机" 这种完全没有业务表达力的名词。

    我赞同把 validation 抽离成单独的 Object,赞成把独立的业务逻辑(比如发 email)从 model callback 中抽成单独的 Object,也赞成把这些不同的逻辑在 Service Object(文章里的 Signup)里聚合,不是因为这些符合某种架构 pattern,而是因为这些都是 OO 的正常做法。我唯独不赞成 StateMachine 的逻辑。这本就应该是 User 这个 model 干的事情。

    Rails 的 AR 复杂已经被吐槽过很多次了,但为什么至今仍然还有很多人把逻辑往 callback 里写,我觉得有部分原因是例子举得不到位,他们对 pattern 一知半解,把事情变得复杂,却没有获得应有的好处,相反让一些不明就里的开发者连一些好的 pattern 都开始抵制起来。

  • 用户权限方面改怎么选择 at 2016年11月24日

    推荐 pundit。cancancan 导致 ability 文件过于庞大,而且 DSL 会导致一些权限代码不是很清晰。pundit 基于一个很简单的概念 -- 把每段权限检查的逻辑抽到 Ruby Object 中去。用它之前先看看 作者博客 ,会很有帮助。