<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hjiangwen (IvanHuang)</title>
    <link>https://ruby-china.org/hjiangwen</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>Rails PG Extras - PG 性能检查工具</title>
      <description>&lt;h2 id="Gem 介绍"&gt;Gem 介绍&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/pawurb/rails-pg-extras" rel="nofollow" target="_blank" title=""&gt;rails-pg-extras&lt;/a&gt; 是一个 PG 性能检查工具，基于 pg 内置的&lt;a href="https://www.postgresql.org/docs/12/monitoring-stats.html" rel="nofollow" target="_blank" title=""&gt;统计视图&lt;/a&gt;。作者是一名 Rails 以及 PG 性能咨询顾问。一般小团队都没有 DBA，后端开发用这个 gem 就能检查出一些问题～&lt;/p&gt;

&lt;p&gt;rails-pg-extras 提供了以下功能（我只列出了使用频率高的）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;统计情况

&lt;ul&gt;
&lt;li&gt;查看各表、索引大小以及行数&lt;/li&gt;
&lt;li&gt;查看各表的使用情况（多少顺序扫描）&lt;/li&gt;
&lt;li&gt;查看各表的缓存命中率（pg 的内存缓存放在 shared_buffers 中）&lt;/li&gt;
&lt;li&gt;未使用的索引（删掉它们）&lt;/li&gt;
&lt;li&gt;null 值比例高的索引（把它们替换成非 null 的 partial index）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pg 实时情况

&lt;ul&gt;
&lt;li&gt;long running query&lt;/li&gt;
&lt;li&gt;blocking query&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="下一步"&gt;下一步&lt;/h2&gt;
&lt;p&gt;这个 gem 只能基于 pg 内置的统计视图，查看 PG 最新的状态。但是我们通常对比历史数据，才能知道系统的好坏：1000qps 是好还是坏？
以下这些商业工具就是基于统计视图，提供了时间序列的查看方式：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pganalyze.com/" rel="nofollow" target="_blank"&gt;https://pganalyze.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.datadoghq.com/database_monitoring/setup_postgres/rds/" rel="nofollow" target="_blank"&gt;https://docs.datadoghq.com/database_monitoring/setup_postgres/rds/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;因为有历史数据，我们就能查够查看系统的 Top SQL，比如：吞吐量最大的 query、最慢的 query、最耗 IO 的 query。这是 new relic 没提供的功能，new relic 只能查 top table，没有 query 粒度的监控。比如你在 new relic 只知道 users 表请求量最大，这些 query 来自哪些 API/job，但是你不知道具体是哪些 query&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pawelurbanek.com/postgresql-fix-performance" rel="nofollow" target="_blank"&gt;https://pawelurbanek.com/postgresql-fix-performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;。。。未完待续，要出门了&lt;/p&gt;
&lt;h2 id="彩蛋"&gt;彩蛋&lt;/h2&gt;
&lt;p&gt;我贡献的&lt;a href="https://github.com/pawurb/rails-pg-extras/pull/19" rel="nofollow" target="_blank" title=""&gt;一个 PR&lt;/a&gt;被采纳了。🎉 记录我的第二次开源贡献～&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Sun, 13 Mar 2022 10:39:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/42206</link>
      <guid>https://ruby-china.org/topics/42206</guid>
    </item>
    <item>
      <title>关注了一个女 rubist</title>
      <description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Naomi_Wu" rel="nofollow" target="_blank" title=""&gt;她的简介&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In addition to her public work as a maker, Wu says she also works as a professional coder in Ruby on Rails, using a masculine pseudonym to protect her identity and preclude gender discrimination&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;她的 youtube channel&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UCh_ugKacslKhsGGdXP0cRRA" rel="nofollow" target="_blank"&gt;https://www.youtube.com/channel/UCh_ugKacslKhsGGdXP0cRRA&lt;/a&gt;。看视频的时候还能学英语，真不错
&lt;img src="https://l.ruby-china.com/photo/hjiangwen/68f1616a-a104-4073-a0a8-c741b8539cdf.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Thu, 12 Aug 2021 22:27:36 +0800</pubDate>
      <link>https://ruby-china.org/topics/41577</link>
      <guid>https://ruby-china.org/topics/41577</guid>
    </item>
    <item>
      <title>为什么 PostgreSQL 所有会话都在等待磁盘读操作，导致所有 sql 都无法响应？</title>
      <description>&lt;h2 id="问题"&gt;问题&lt;/h2&gt;
&lt;p&gt;在生产环境遇到一个问题，在请求量非高峰期间，所有 sql 语句都很慢，响应时间平均在 7s，最慢 10s。这个现象持续了大约 10s，才慢慢恢复正常。&lt;/p&gt;

&lt;p&gt;下图是 AWS RDS performance insight 的图，可以看到所有 pg 会话都在等待读磁盘（具体等待事件是 DataFileRead 和 buffer io）。这种问题最近一周出现一次。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/hjiangwen/3ba3f91b-1f76-47aa-9324-e3bf399528cf.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;从&lt;a href="https://www.postgresql.org/docs/10/monitoring-stats.html" rel="nofollow" target="_blank" title=""&gt;pg 文档&lt;/a&gt;中，我们可以知道等待事件的具体含义&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DataFileWrite:    Waiting for a write to a relation data file.&lt;/li&gt;
&lt;li&gt;buffer_io: Waiting for I/O on a data page.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="解释"&gt;解释&lt;/h2&gt;
&lt;p&gt;我想这表示&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pg 无法从共享内存的 shared_buffer 中找到对应的 table/index page&lt;/li&gt;
&lt;li&gt;那些执行 sql 的会话就得等 pg 从磁盘中读取 page（DataFileWrite event）&lt;/li&gt;
&lt;li&gt;然后写到 shared_buffer 中（buffer_io event）&lt;/li&gt;
&lt;li&gt;会话此时才能继续执行&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="猜测"&gt;猜测&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;是不是请求量超过了数据库 IO 极限？&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不是，我查了当时的 IOPS，没达到那台数据库的极限。而且当时的 IO 也比不上每日高峰，数据库的 IO 能力能满足每日高峰，所以一定也能满足当时的请求量。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;会不会是 shared_buffer 不足？&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;可是每日高峰也能正常工作呀，如果 shared_buffer 不足，每日高峰应该也会遇到这个问题，所以我觉得不是内存配置问题。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;会不会是&lt;a href="https://www.percona.com/blog/2018/08/06/basic-understanding-bloat-vacuum-postgresql-mvcc/" rel="nofollow" target="_blank" title=""&gt;bloat tuple&lt;/a&gt;？

&lt;ul&gt;
&lt;li&gt;可能，我们的表行数挺多，而且经常被更新，的确会产生 dead tuple。而 pg 的定期 vacuum 只会把 dead tuple 空出来，一个用户在一个表的所有 rows 在 table page 文件会比较分散，导致当我们在一个表查用户的所有 rows 时，一个 query 要在磁盘上查很多 index/table page 才能找出所有 rows。&lt;/li&gt;
&lt;li&gt;如何验证？如何复现呢？🤔  通过 explain 来检查一个 query 要查多少 page？&lt;/li&gt;
&lt;li&gt;如果真的是这个问题，那我们可以用&lt;a href="https://github.com/reorg/pg_repack" rel="nofollow" target="_blank" title=""&gt;pg_repack&lt;/a&gt;来解决它。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="求助"&gt;求助&lt;/h3&gt;
&lt;p&gt;大家觉得是什么问题呢？&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Sun, 27 Jun 2021 22:21:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/41415</link>
      <guid>https://ruby-china.org/topics/41415</guid>
    </item>
    <item>
      <title>计算阻塞 IO web server 的最大吞吐量</title>
      <description>&lt;h2 id="计算"&gt;计算&lt;/h2&gt;
&lt;p&gt;如果我们用 RPM（每分钟请求量）来衡量吞吐量，我们可以用这个公式来计算阻塞 IO web server 的最大吞吐量：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;线程的 RPM = 60s / 平均响应时间&lt;/li&gt;
&lt;li&gt;一个容器的 RPM = 进程数 * 线程数 * 线程的 RPM&lt;/li&gt;
&lt;li&gt;所有容器的 RPM = 一个容器的 RPM * 容器数量&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;假设我们 web server 的平均响应时间是 150ms，一个容器里有 2 个进程，每个进程有 5 个线程，那么&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;线程的 RPM = 60s / 150ms = 400&lt;/li&gt;
&lt;li&gt;一个容器的 RPM = 2 进程 * 5 线程 * 400 = 4k&lt;/li&gt;
&lt;li&gt;如果我们运行 50 个容器，则吞吐量是 50 * 4k = 200k RPM&lt;/li&gt;
&lt;li&gt;如果我们运行 500 个，则吞吐量为 500 * 4k = 2m RPM&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="慢API如何影响吞吐量"&gt;慢 API 如何影响吞吐量&lt;/h2&gt;
&lt;p&gt;假设我们依赖的外部服务不可用，导致请求超时，而且我们&lt;strong&gt;没设置请求超时时间&lt;/strong&gt;，惨。导致关键 API 变得很慢，外部服务的响应时间甚至达到了 30-60s。
这时假设平均响应时间从 150ms 变为 10s，那么&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;线程的 RPM = 60s / 10s = 6&lt;/li&gt;
&lt;li&gt;一个容器的 RPM = 2 进程 * 5 线程 * 6 = 60&lt;/li&gt;
&lt;li&gt;所有容器的 RPM = 60 * 500 个 = 30k&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最终这个慢 API 导致我们的 RPM 从 2m 变成 30k，接着用户体验会变得很糟糕，第 30000 个之后的请求都会被放到请求队列中，请求积累的越来越多，大部分请求还在排队时，就已经超时了。用户在 app 只能看到加载动画或者错误。&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Thu, 24 Jun 2021 20:47:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/41408</link>
      <guid>https://ruby-china.org/topics/41408</guid>
    </item>
    <item>
      <title>用 class_eval 动态定义 method，比 define_method 更易读</title>
      <description>&lt;p&gt;下面这段代码，has_one 通过下面的代码，生成以下 3 个 API&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码位置：&lt;a href="https://github.com/rails/rails/blob/v4.2.10/activerecord/lib/active_record/associations/builder/singular_association.rb#L15" rel="nofollow" target="_blank"&gt;https://github.com/rails/rails/blob/v4.2.10/activerecord/lib/active_record/associations/builder/singular_association.rb#L15&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_constructors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;mixin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class_eval&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__LINE__&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;
    def build_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;(*args, &amp;amp;block)
      association(:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;).build(*args, &amp;amp;block)
    end

    def create_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;(*args, &amp;amp;block)
      association(:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;).create(*args, &amp;amp;block)
    end

    def create_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;!(*args, &amp;amp;block)
      association(:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;).create!(*args, &amp;amp;block)
    end
&lt;/span&gt;&lt;span class="no"&gt;  CODE&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Thu, 29 Oct 2020 20:10:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/40521</link>
      <guid>https://ruby-china.org/topics/40521</guid>
    </item>
    <item>
      <title>谨慎使用 has_one 带来的 build_association API</title>
      <description>&lt;p&gt;当我们使用 build_association 时，即使新的 model 对象还没有保存，旧的 association 就已经取消关联了（外键被置空/直接删除）&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Address&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:customer&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;
&lt;span class="n"&gt;address1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;customer: &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;address2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_address&lt;/span&gt; &lt;span class="c1"&gt;# 还没插入 address2 到数据库&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;address1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customer_id&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Thu, 29 Oct 2020 19:55:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/40520</link>
      <guid>https://ruby-china.org/topics/40520</guid>
    </item>
    <item>
      <title>开发利器，预设变量到 Python 控制台</title>
      <description>&lt;p&gt;原文地址：&lt;a href="https://www.jianshu.com/p/884e0b2f5a45" rel="nofollow" target="_blank"&gt;https://www.jianshu.com/p/884e0b2f5a45&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;在用 Rails 开发 Web 应用时，经常需要调试某些类的 API，看一下输出是什么。
比如执行 view helper API：&lt;a href="https://ruby-china.org/topics/3506" title=""&gt;https://ruby-china.org/topics/3506&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;最近用 mongo 存爬取的数据，但是对 mongo 的 CRUD 操作不熟悉，经常需要进入 python 控制台调试 API。&lt;/p&gt;

&lt;p&gt;每次都要敲入 &lt;code&gt;$ python&lt;/code&gt;，然后实例化 mongo 对象，期间还要加载 &lt;code&gt;.env&lt;/code&gt; 文件里的环境变量，过程实在麻烦。所以想像 Rails 一样，搭建一个预设变量的控制台，提前创建出 mongo 对象，方便自己调试。&lt;/p&gt;

&lt;p&gt;首先新建一个文件 &lt;code&gt;console.py&lt;/code&gt;，把下面代码拷贝进去&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pymongo&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;

&lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 读取环境变量
&lt;/span&gt;
&lt;span class="c1"&gt;# 设置常用的变量
&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pymongo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MONGO_URI&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MONGO_DATABASE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;question_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;question_stats&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;answers&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;# 进入python控制台，并且传入本地变量
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在控制台执行，就能访问提前设置好的变量啦&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python console.py            
Python 3.7.4 (default, Aug 13 2019, 15:17:50) 
[Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
&amp;gt;&amp;gt;&amp;gt; db
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'zhihu_spider')
&amp;gt;&amp;gt;&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;想起以前开发 Android App 时，也没有控制台。调试一个涉及到页面的几个 API，还得打包，安装 App 到手机上（现在打包速度提升不少了），点一下按钮或者进入主页面来触发代码，这个开发效率，一言难尽，想哭，哈哈&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Sun, 29 Mar 2020 12:52:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/39680</link>
      <guid>https://ruby-china.org/topics/39680</guid>
    </item>
    <item>
      <title>编程语言表达能力高带来的好处</title>
      <description>&lt;p&gt;编程语言的表达能力高可以体现在使用该语言时，一行代码就可以完成一样事情，而表达能力低的语言 B 需要一二十行代码才可以完成这件事。&lt;/p&gt;

&lt;p&gt;比如 ActiveRecord 通过 Ruby 可以“动态定义方法”的能力，一行表达式可以声明 2 张表之间的关联关系，给予一些实用的方法。 ​​​​&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 可以获得以下实例方法&lt;/span&gt;

&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="c1"&gt;#author # 访问作者&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="c1"&gt;#author=(author) # 将作者和帖子关联起来&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="c1"&gt;#build_author(attrs) # 给帖子实例化一名作者&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="c1"&gt;#create_author(attrs) # 给帖子实例化一名作者，并持久化&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Sun, 22 Sep 2019 20:39:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/39076</link>
      <guid>https://ruby-china.org/topics/39076</guid>
    </item>
    <item>
      <title>[译] 提高编程能力的秘诀</title>
      <description>&lt;p&gt;原文：&lt;a href="http://blog.thefirehoseproject.com/posts/learn-to-code-and-be-self-reliant/" rel="nofollow" target="_blank" title=""&gt;The Key To Accelerating Your Coding Skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hjiangwen.github.io/2019/01/25/key-to-accelerating-your-coding-skills.html" rel="nofollow" target="_blank" title=""&gt;译文地址&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="TL;DR"&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;作者把学习编程分为 2 个阶段，第一个阶段是&lt;strong&gt;辅导阶段&lt;/strong&gt;，这个阶段有 2 个重点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;通过教程学习具体的技能，比如怎么使用 Vue 来响应一个按钮的点击事件。&lt;/li&gt;
&lt;li&gt;仔细查看错误信息，调试程序。因为一个小小的拼写错误也会导致程序出错，所以得格外注重细节。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个阶段的秘诀是&lt;strong&gt;注重细节，以及从每一个错误/难题中学习&lt;/strong&gt;，当解决一个难题后，思考一下难在哪里、原因是什么、怎么避免，好记性不如烂笔头。&lt;/p&gt;

&lt;p&gt;第二个阶段是&lt;strong&gt;拐点阶段&lt;/strong&gt;，这个阶段是学会独自编程、独自解决问题的过程。在软件开发中，永远都学不完所有你需要知道的知识，总是存在你没遇到过的问题。我们得拆分问题，然后正确地搜索和提问（&lt;a href="https://ruby-china.org/topics/24325" title=""&gt;提问的智慧&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;此时的秘诀是&lt;strong&gt;尽早独自解决问题，拆分问题&lt;/strong&gt;，将问题拆分到自己能执行的粒度为止。&lt;/p&gt;

&lt;p&gt;作者认为 Web 开发需要 2 样能力：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Web 开发能力，能基于数据库开发任何你遇到的应用。其中应该包含：数据库技能（设计表、查询）、一门服务端语言、前端技能（JS、HTML 和 CSS）。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;算法和数据结构能力，有这个能力的开发者可以解决逻辑较复杂的问题。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以下是原文。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;当你学习编程时，会有一个时刻一切开始改变。在 Firehose，我们喜欢称这时刻为编程的拐点（inflection point）。经过这个阶段，你作为开发者的工作方式将大不相同。爬到拐点是在编程上变得独立（self-sufficient）的过程，达到拐点后你不再需要别人手把手教你完成功能。它是一个艰难的过程，但是一旦你经历了，会让你很有信心。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/e060bcf2-0681-4de8-99b0-8785efd86c75.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;在 Firehose，我们的目标不仅仅是教你 Ruby，怎么构建 Web 应用或者怎么写测试。虽然我们的确教这些技能，&lt;strong&gt;但是我们的主要目标是让学生更快通过拐点，让他们有能力解决遇到的任何问题。&lt;/strong&gt;我们认为能独自解决问题是很宝贵的技能。这种教学方法相比单纯地教如何构建应用，可以让你走的更远。&lt;/p&gt;
&lt;h3 id="辅导阶段(Tutorail Phase)（认真编程 3 - 8 周）"&gt;辅导阶段 (Tutorail Phase)（认真编程 3 - 8 周）&lt;/h3&gt;
&lt;p&gt;当你开始学习编程，你有许多还不了解的信息。这些信息叫领域特定知识（domain-specific knowledge），例如：怎么用 ruby 写循环语句、怎么使用 Rails 从数据库提取记录。&lt;/p&gt;

&lt;p&gt;成为一名独立（self-sufficient）的开发者第一步是学会怎么执行一个具体的任务。当你掌握几个方法后，就逐渐知道这些碎片是如何拼到一起，以完成功能。经过一段时间，你将开始理解，一开始令你困惑的东西最终会变得自然起来。&lt;/p&gt;
&lt;h3 id="对于刚起步的学生，要获得的最重要的技能是关注细节"&gt;对于刚起步的学生，要获得的最重要的技能是关注细节&lt;/h3&gt;
&lt;p&gt;在阅读文档或教程时，&lt;strong&gt;关注细节&lt;/strong&gt;十分重要。即使是最小的拼写错误也会导致错误。一开始看错误信息是一个艰难的过程，但它在学习过程是一个至关重要的步骤。在这阶段中处理错误信息和问题会教你一个编程中最重要的技能：注重细节。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;排除故障十分重要。&lt;/strong&gt;事实上，错误信息是编程的一部分：缺乏经验和非常有经验的开发者都会遇到。唯一的不同点是，处理错误信息的经验越多，修复它们所需的时间就越少。因为：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;经过一段时间，你将&lt;strong&gt;学会如何阅读错误信息&lt;/strong&gt;和快速提取问题的相关细节。你第一次看到一个错误信息，会花你一些时间了解它到底是什么意思。但当你遇到几百次错误信息后（你还会再遇到无数错误），你将能定位发生问题的地方，找到修复它们所需要的相关细节。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你应该&lt;strong&gt;从你解决的每一个错误中学习&lt;/strong&gt;。不要修复完就算了，理解代码到底有什么问题。从每一次错误学习，下次你犯了同样的错，你将会更快的修复它。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一开始，你每次遇到错误都会请求帮忙。慢慢地，你会仔细检查代码和去 Google 搜索，慢慢减少求助频率。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在辅导阶段，你会跟随教导。一开始，你觉得跟随教导指令有难度，经常出现错误。慢慢地，你将学会调试错误，更注重细节，并且你会学得越来越快。当你通过辅导阶段，你会注意到你能以更快速度的写代码。&lt;/p&gt;

&lt;p&gt;在这时，一些人会感到有信心，他们准备抛弃指导，可以不依靠指示开始构建东西了，并开心地投入身心进去。一些学生会寻找更多教程，尝试获得更多领域特定知识，以寻求“完全理解”。不幸的是，教程只能带你到这里，真正的自信不是在教程里找到的。&lt;strong&gt;真正的自信来自与一个你不知道怎么解决的问题纠缠，并且自己发现解决办法。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;编程肮脏的小秘密是...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;你永远不会知道解决你所有的问题所需要的所有知识。编程时一个终生学习的过程。经验丰富的软件工程师寻找他们没遇到过的问题的解决方案，因为这是他们学习的机会。如果你发现自己在等待这样一个时刻——你终于觉得你知道了关于编程的所有知识，告诉你：你永远等不到这一天，但这是一件美妙的事情。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2019/e58dbe97-cbc9-4b47-8891-9cd75d795582.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当你达到以下状态，你将进入下一个阶段：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;你已经遇到足够的错误，不再害怕遇到它们。而且，你知道如何弄懂它们表示什么和哪段代码出了问题。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;熟练地使用 Google 寻找解决方法。当你编写一个功能时或者遇到一个让你困惑的错误时，你知道搜索什么来找到你需要的信息。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;你可以参考你项目中已经写过的代码，跟随这些模板来增加功能，而不是总是寻找手把手的教导。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="拐点阶段（The Inflection Point）（2 - 4 周）"&gt;拐点阶段（The Inflection Point）（2 - 4 周）&lt;/h3&gt;
&lt;p&gt;这个阶段是学习编程中最容易让人气馁的阶段，某些方面来讲，这是唯一重要的阶段。在这个阶段你渐渐不使用教程，独自解决问题，没人告诉你解决方法。&lt;/p&gt;

&lt;p&gt;某些时候，你会觉得你还没准备好应对这个阶段，想回去编写那些有详细解决步骤的项目。不要被这种心态影响了，你觉得难受的原因是：&lt;/p&gt;
&lt;h4 id="在拐点阶段期间，相比前一个阶段，你的编程速度要慢 10 - 20 倍。"&gt;在拐点阶段期间，相比前一个阶段，你的编程速度要慢 10 - 20 倍。&lt;/h4&gt;
&lt;p&gt;你开始怀疑自己是否有能力成为一名程序员。在这个阶段，没有信心和怀疑自己是很常见的。&lt;/p&gt;

&lt;p&gt;尽管你觉得自己以慢地多的速度学习和完成事情，但实际上你正在习得最重要的技能。当你领域特定知识（domain-specific knowledge）学得足够了（学完最小必要知识），你接下来学的一切都是有关程序性知识的（procedural knowledge）（指关于“如何做”的知识）。&lt;/p&gt;

&lt;p&gt;程序性知识是教会自己你不知道的东西的能力。当你需要实现一个新功能，你要怎么搜索？当你需要实现许多东西时，你会觉得很无助。学会如何独自找到出路很重要，因为你永远不会知道所有要知道的东西，你必须有能力教会自己如何解决手头上的问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;很多人没意识到，学习编程，你得学习领域特定知识以及程序性知识。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="接下来，每天挑战自己的极限"&gt;接下来，每天挑战自己的极限&lt;/h3&gt;
&lt;p&gt;有些软件工程师一旦找到了稳定的岗位，就停在舒适圈。这些程序员被称为维护程序员（maintenance programmers）。这不是你的努力的目标。相反，你应该每天都挑战自己的极限。程序员跳槽的最常见原因是：这份工作已经不再有挑战性了，因为我已经解决了所有有趣的问题，&lt;/p&gt;

&lt;p&gt;你应该寻找超出你目前技术栈的问题，而不是一直编写在你舒适圈内的项目。这是积累和扩展你技能的唯一方法。&lt;/p&gt;
&lt;h3 id="在 Web 开发，有 2 个拐点会汇集到一起"&gt;在 Web 开发，有 2 个拐点会汇集到一起&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Web 开发拐点&lt;/strong&gt;是你有能力写任何数据库驱动的应用的拐点。这意味着你能构建一个 Web 应用，它有多个从数据库存取信息的页面。Web 开发者称这个为：熟练掌握 CRUD。在这个阶段，你应该可以跟着文档或者文章集成任何第三方库。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;算法和数据结构拐点&lt;/strong&gt;是一个不那么明显的拐点，但它实际上更重要。除了掌握了编程的基础和拥有解决复杂编程问题的知识外，克服这个拐点的同学应该已经掌握了他正在使用的语言。&lt;/p&gt;

&lt;p&gt;攻克算法和数据结构拐点的人可以：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;编写排序算法&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;实现和倒置链表&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;理解栈、队列和树以及在程序中利用它们&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用递归和循环解决问题&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;总之，一旦你经过这个拐点，你将掌握数据操作和理解你代码的性能。传统的计算机科学学位专注于让学生通过算法和数据结构拐点。许多大学用行业上通常不使用的语言来教这些内容，如 Scheme, Racket, LISP。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;大多数技术面试，面试官会当做你已经通过了 Web 开发拐点，因为它相对容易，然后将问题集中在评估你在算法和数据结构上的能力。&lt;/strong&gt;这些问题一般集中在我们上面提到的话题：排序算法、倒置链表和使用栈、队列以及树。&lt;/p&gt;
&lt;h3 id="一旦程序员通过了 Web 开发拐点和算法、数据结构拐点，他们就掌握了关键技能（hold the keys to the kingdom）"&gt;一旦程序员通过了 Web 开发拐点和算法、数据结构拐点，他们就掌握了关键技能（hold the keys to the kingdom）&lt;/h3&gt;
&lt;p&gt;这些程序员有能力解决两者相交的挑战：在高级 Web 应用中构建复杂算法。这是资深 Web 开发每天做的事情。&lt;/p&gt;
&lt;h3 id="拐点的结果（Consequences of the Inflection Point）"&gt;拐点的结果（Consequences of the Inflection Point）&lt;/h3&gt;
&lt;p&gt;当你第一次听到拐点最大的结果时，会觉得有点反直觉：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;学编程时，领域特定知识在宏观（the grand scheme）上并不重要。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;是的，我没有在开玩笑，它真的一点都不重要。一旦你经过了拐点，学习那些概念（领域特定知识）只需一周或者 2 篇教程，甚至只要几天。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;最重要的是：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;你得熟悉 Web 开发&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;原文是：You have a solid grasp on a web development framework，但是前面又说领域特定知识在宏观上不重要，但一个 Web 框架不应该是作者所指的特定知识吗？所以我觉得应该是指 Web 开发&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;你可以熟练地使用任何编程语言写复杂的算法代码&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="人事主管想招的是有扎实 Web 开发和算法技能的开发者"&gt;人事主管想招的是有扎实 Web 开发和算法技能的开发者&lt;/h3&gt;
&lt;p&gt;当我在 PayPal 工作时，我们团队招了一个没有 Rails 开发经验的高级 Rails 开发者，他使用 Python，LISP 和 Perl 写过很多代码。在几天内，他已经起了很大作用，在几周内，更多的作用。他很快成为技术团队的组长，这是我参与过最好的招聘决定。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;不要担心技术栈。&lt;/strong&gt;很多人这样说：“现在 AngularJS 最火”，“JS 正在崛起”或者“最新的潮流是...”。我的回答是：“那有怎样？”当你学习编程，你唯一的目标应该是找到拐点并击败它。一旦你做到了，学习新的潮流技术一点也不难。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;变得独立（Become self-reliant）。&lt;/strong&gt;有能力不依靠完整的指导学习新的技术，意味这你不再需要等别人来教你。大多数你想学的东西，你只需在网上搜索，阅读关于各种各样你想知道的东西的材料。&lt;/p&gt;

&lt;p&gt;这不意味这你马上知道了所有东西，只是所有东西都是可以解决的、可执行的（figure-out-able）。你可以说是不可阻挡的了。&lt;/p&gt;
&lt;h3 id="在拐点你会学到的技能"&gt;在拐点你会学到的技能&lt;/h3&gt;
&lt;p&gt;作为一名软件开发者，最好的参考材料是你写过的相似代码。当你完全理解了你写的代码，你不需要记住所有细节。&lt;strong&gt;当你写一个新功能时，你应该问自己的第一个问题是：“我有写过相同的功能吗？”。&lt;/strong&gt;如果是，重新打开代码，一行一行的看，跟自己解释它在做什么，问自己：“我现在可以用同样的方法吗？”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;视频很难解释领域特定知识的细节，&lt;/strong&gt;因为视频得花很多时间来看。比如你想集成 Google 地图 API，如果你集成过，不用花一分钟就可以打开代码，复制代码，将它粘贴到新项目。而重新看视频得花 10 - 30 分钟。&lt;/p&gt;
&lt;h3 id="高效通过拐点的策略"&gt;高效通过拐点的策略&lt;/h3&gt;
&lt;p&gt;因为通过拐点是学习编程最重要的一部分，你应该让自己精力充沛，让这个过程尽可能顺利。这意味这你在辅导阶段时就应该开始准备，并且在这过程中保持良好的心态。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;在辅导阶段期间，不依赖完整的教程，让自己挑战问题。&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;每一节课程，&lt;strong&gt;尝试做一些超出教程范围的东西。&lt;/strong&gt;如果你正在阅读的教程提供了课后练习，请全部做完。解决没有指导的问题将给你很重要的独自解决问题的经验。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;尽可能少的使用教程。&lt;/strong&gt;在 Firehost，我们经常详细地向学员讲解如何使用文档集成第三方库或者做某事，而不是简单地跟着教程中的指令，这些教程是提供给刚刚起步的同学的。许多学生将跟着文档学习，将教程作为备选材料。&lt;strong&gt;请注意，文档会把你当成已通过拐点的开发者。&lt;/strong&gt;习惯于阅读和跟着 GitHub 上的文档进行开发，对你独自开发时将很有帮助。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;关注重要的事并且重复练习。&lt;/strong&gt;学会怎么做常见的任务，比如从零开始快速启动一个项目、将一个新应用推送到 GitHub 和 Heroku、尽早地执行数据库迁移。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;通过拐点很难，这里有一些忠告帮助你通过它：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;认识到这是一个艰难的过程，让自己放松，树立合理的预期。&lt;/strong&gt;你不能拿辅导阶段的超人速度和自学阶段的蜗牛速度对比。请记住，你正在学习很多东西，你在学习一个新的技能——独自解决问题。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果你觉得没自信，你得知道，这是非常正常的感觉。继续前进，如果你还在挣扎中，尝试与刚通过拐点的同学交流，他们能感受到你现在的处境，并且向你保证你正在经历的只是暂时的。&lt;strong&gt;不断学习，但是不要过度。&lt;/strong&gt;在这个阶段，你最多只能每天学习 6 小时。在筋疲力尽的状态下学习只会延长你花在拐点的时间。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个阶段获得自信的最好办法是解决你的疑问，你的情绪会像坐过山车那样，有时，你觉得很焦急，但经过 15 小时的解决过程，有相反的感受是很常见的。&lt;/p&gt;

&lt;p&gt;如果某个问题花了你 5 分钟或者 5 小时后还没有头绪，这会让人很心烦。但每次解决它并且成功实现一个新功能，会让你感觉自己很牛。在没有帮助下解决许多难题后，你会沉迷于构建超出你舒适区的东西的感觉。&lt;/p&gt;
&lt;h3 id="怎么知道你何时通过了拐点"&gt;怎么知道你何时通过了拐点&lt;/h3&gt;
&lt;p&gt;拐点的最后阶段是接受（The final stage of the inflection point process is acceptance）。接受软件开发是一个不断学习的过程。接受你已经学会了一切的感觉只意味着你应该开始考虑解决更复杂的问题。&lt;/p&gt;</description>
      <author>hjiangwen</author>
      <pubDate>Fri, 01 Feb 2019 01:12:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/38074</link>
      <guid>https://ruby-china.org/topics/38074</guid>
    </item>
  </channel>
</rss>
