<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>gracezhangyaofei (Grace Zhang)</title>
    <link>https://ruby-china.org/gracezhangyaofei</link>
    <description/>
    <language>en-us</language>
    <item>
      <title>ROR Optimization Tips</title>
      <description>&lt;h2 id="案例背景"&gt;案例背景&lt;/h2&gt;
&lt;p&gt;Model&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;音乐 Music&lt;/li&gt;
&lt;li&gt;活动 Event

&lt;ul&gt;
&lt;li&gt;Event has_many users, Event has_many musics&lt;/li&gt;
&lt;li&gt;User has_many musics&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;人员 User

&lt;ul&gt;
&lt;li&gt;对应 Event 的角色：[host, viewer]&lt;/li&gt;
&lt;li&gt;对应音乐的角色：[owner, participator]&lt;/li&gt;
&lt;li&gt;特殊权限的用户：[system_admin]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Policy Objects"&gt;Policy Objects&lt;/h2&gt;
&lt;p&gt;用来处理 permissions, roles, and policies 的工具，需要处理比如某 object 是否有执行某 action 的权限，虽然很多 gem 已经做了类似的事情，比如 pundit, Cancan, and Cancancan，也是用了这个 pattern，但是还是有很多特殊场景，需要手动创建 policy 来满足需求。&lt;/p&gt;
&lt;h3 id="需求"&gt;需求&lt;/h3&gt;
&lt;p&gt;对 Music 有编辑权限的 3 种场景&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;event host: music belongs_to event&lt;/li&gt;
&lt;li&gt;music owner: music belongs_to event &amp;amp;&amp;amp; music owner belongs_to event&lt;/li&gt;
&lt;li&gt;有特殊权限的用户&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="实现"&gt;实现&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;policies&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;musics_edition_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MusicsEditionPolicy&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:music&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;music&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@music&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;music&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;edit?&lt;/span&gt;
    &lt;span class="n"&gt;event_host?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;music_owner?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;special_guest?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="c1"&gt;# implement your logic with each methods&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;event_host?&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;music_owner?&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;special_guest?&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="分析"&gt;分析&lt;/h3&gt;
&lt;p&gt;（why 适合用 policy objects 实现）&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;涉及到多个 model 的关系&lt;/li&gt;
&lt;li&gt;判断 edit? 的地方比较多，也分布在 view/controller&lt;/li&gt;
&lt;li&gt;condition 可能变化，不是一成不变&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Presenter Pattern"&gt;Presenter Pattern&lt;/h2&gt;
&lt;p&gt;把大量的判断逻辑放到 view 里面，一方面会让 view 很 heavy，另一方面会让测试很麻烦，可以把一些 view 上面臃肿的逻辑放到 presenter 里面，仅对 presenter 写单元测试也更聚焦。presenter 是很好的后台 model 和前端 view 的一个桥梁。（decorator 有类似的效果，略有不同，这个链接不错哦 &lt;a href="https://stackoverflow.com/questions/7860301/ruby-on-rails-patterns-decorator-vs-presenter" rel="nofollow" target="_blank" title=""&gt;Presenter VS Decorator&lt;/a&gt;）&lt;/p&gt;
&lt;h3 id="需求"&gt;需求&lt;/h3&gt;
&lt;p&gt;用户自己 login 的导航/对外 music 的封面/用户管理页面，显示不同的用户名字&lt;/p&gt;
&lt;h3 id="实现"&gt;实现&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;presenters&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;user_presenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserPresenter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;SimpleDelegator&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;official_name_for_music&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;official_name_for_admin&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="分析"&gt;分析&lt;/h3&gt;
&lt;p&gt;（why 适合用 presenter pattern 实现）&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;用在 view 层面，并且很多地方适用&lt;/li&gt;
&lt;li&gt;有判断逻辑，比如：是否登陆还是站外，当前显示在 what 页面等&lt;/li&gt;
&lt;li&gt;不是一个简单的 helper 方法可以 hold 住&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Query Objects"&gt;Query Objects&lt;/h2&gt;
&lt;p&gt;总有一些判断 query 条件是在很多地方用到，api v2/graphql/normal controller etc，&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;放到 model 很 fat&lt;/li&gt;
&lt;li&gt;放到 service 里面让 service 本身的功能不聚焦，去做了查询的事&lt;/li&gt;
&lt;li&gt;放到 base controller 里面会出现不是所有场景都可以继承，有 duplicate code&lt;/li&gt;
&lt;li&gt;放到 concern 里面制作 query，确定合适么
query objects 就是来解决上面的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="需求"&gt;需求&lt;/h3&gt;
&lt;p&gt;查询所有 current_user 有权限编辑的音乐&lt;/p&gt;
&lt;h3 id="实现"&gt;实现&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;music_query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MusicQuery&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;editable&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;active&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="分析"&gt;分析&lt;/h3&gt;
&lt;p&gt;（why 适合用 query objects 实现）&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;同样 query 逻辑多处被使用&lt;/li&gt;
&lt;li&gt;放到其他的位置，单元测试需要考虑不同条件下返回的情况，使自己本身的使命不清楚&lt;/li&gt;
&lt;li&gt;参考此处开头位置&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;模型需求纯属自编自演，如有雷同个纯属巧合。ENDING！！！&lt;/p&gt;</description>
      <author>gracezhangyaofei</author>
      <pubDate>Wed, 16 Dec 2020 18:50:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/40707</link>
      <guid>https://ruby-china.org/topics/40707</guid>
    </item>
    <item>
      <title>Let's GO 语言吧</title>
      <description>&lt;p&gt;最近有一个机会了解了一下仰慕已久的 GO，将静态语言的安全性和高效性与动态语言的易开发性进行有机结合，大力支持网络通信、并发和并行编程的，GO 确实很多方便做的不错，虽然在国内一直是不温不火的状态，哈哈～&lt;/p&gt;

&lt;p&gt;这次使用的最初原因是在 ROR 中，需要发送大量 header 请求到第三方，在 worker 里面做，每 1k 请求耗时大概 2-3mins，几个 worker 还是有点浪费资源。GO 这个时候真的是体现了自己大 BOSS 的价值。GO 的 concurrency 的特性，可以实现 1k 个请求 1.5mins。一方面速度很快，当然另外一方面，实现起来也比 ROR 里面笨重的 worker 好很多。但是提到 concurrency，大多数小伙伴会想到 parallelism，但是其实还是完全不同的二个东西。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2018/be99fbb6-3e4b-453b-b3b4-b066b0d04d77.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;concurrency 是通过将一个大任务，切成可以单独运行的小块，并且让这些小的代码快很好的沟通的过程。而 parallelism 是同时执行计算的过程。看图：
&lt;img src="https://l.ruby-china.com/photo/2018/1f7afd58-329e-4b4f-a284-d024d0676e82.jpeg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;既然是 concurrency，那么 Go Scheduler 是如何管理所有的 go routine 来提高速度呢？看图：
&lt;img src="https://l.ruby-china.com/photo/2018/0052f186-b187-4722-bc7e-5d32933c13b0.jpeg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当正在运行的 go routine 被 block，比如正在发送第三方请求，那么 Scheduler 会重新选择一个新的 go routine，继续运行，不会让 CPU 闲置。正是因为 go 这样灵巧的管理机制，才可以让 CPU 到达了最大的利用率，从而节约时间。
另外再把 goroutine 和 channel 结合使用，即可达到预想的效果了！（字迹很丑，请多包含！）&lt;/p&gt;</description>
      <author>gracezhangyaofei</author>
      <pubDate>Sun, 24 Jun 2018 15:37:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/37037</link>
      <guid>https://ruby-china.org/topics/37037</guid>
    </item>
  </channel>
</rss>
