<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>技术成长 on 易哥</title>
		<link>https://yeecode.top/tags/%E6%8A%80%E6%9C%AF%E6%88%90%E9%95%BF/</link>
		<description>Recent content in 技术成长 on 易哥</description>
		<generator>Hugo</generator>
		<language>zh-cn</language>
		
		
		
		
			<lastBuildDate>Thu, 02 Oct 2025 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="https://yeecode.top/tags/%E6%8A%80%E6%9C%AF%E6%88%90%E9%95%BF/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>记一次源码解读：MyBatis缓存修饰器中的锁</title>
				<link>https://yeecode.top/blog/86/</link>
				<pubDate>Thu, 02 Oct 2025 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/86/</guid>
				<description>&lt;h2 id=&#34;1-问题背景&#34;&gt;1 问题背景&lt;/h2&gt;&#xA;&lt;p&gt;事情是这样的，一天，有一位小伙伴 知乎用户@阳光沙滩裤 私信我问我书中的一个问题，如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/86/pic/001_hu_1b70d1c1779946be.webp&#34; width=&#34;684&#34; height=&#34;417&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;哎，不对啊。我都AT他了，那这图片还打什么码啊！&lt;/p&gt;&#xA;&lt;p&gt;打了个寂寞啊！&lt;/p&gt;&#xA;&lt;p&gt;不管了，继续讨论问题。&lt;/p&gt;&#xA;&lt;p&gt;说实话，这个问题我确实没有注意到。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/86/pic/002_hu_279983edff986986.webp&#34; width=&#34;900&#34; height=&#34;394&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;提问的小伙伴很有心，细致地对比了两个分支的区别。然后提出了这个问题。&lt;/p&gt;&#xA;&lt;p&gt;那当然，我要去给出这个问题的解答！&lt;/p&gt;&#xA;&lt;p&gt;尽量！&lt;/p&gt;&#xA;&lt;p&gt;开始。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-相关知识&#34;&gt;2 相关知识&lt;/h2&gt;&#xA;&lt;p&gt;开始之前，我们需要先介绍下这个问题的相关知识。&lt;/p&gt;&#xA;&lt;p&gt;主要的背景知识分为两块，一块是MyBatis缓存的实现机制，一块是软引用和弱引用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;21-mybatis的缓存&#34;&gt;2.1 MyBatis的缓存&lt;/h2&gt;&#xA;&lt;p&gt;装饰器模式在编程开发中经常使用。通常的使用场景是在一个核心基本类的基础上，提供大量的装饰器，从而使得核心基本类经过不同的装饰器修饰后获得不同的功能。&lt;/p&gt;&#xA;&lt;p&gt;装饰器还有一个优点就是可以叠加使用，即一个核心基本类可以被多个装饰器修饰，从而同时具有这多个装饰器的功能。&lt;/p&gt;&#xA;&lt;p&gt;MyBatis便使用了大量的装饰器实现了不同类型的缓存，它们都在cache包中。在imple子包中存放了实现类，在decorators子包中存放了众多装饰器类。而Cache接口是实现类和装饰器类的共同接口。&lt;/p&gt;&#xA;&lt;p&gt;下面给出了Cache接口及其子类的类图。Cache接口的子类中，只有一个实现类，但却有十个装饰器类。通过使用不同的装饰器装饰实现类可以让实现类有着不同的功能。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/86/pic/Cache_hu_8eee8534b168284.webp&#34; width=&#34;900&#34; height=&#34;670&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Cache接口的源码如下所示，在接口中定义了实现类和装饰器类中必须实现的方法。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Cache&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 获取缓存id&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @return 缓存id&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String &lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 向缓存写入一条数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @param key 数据的键&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @param value 数据的值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;putObject&lt;/span&gt;(Object key, Object value);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 从缓存中读取一条数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @param key 数据的键&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @return 数据的值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Object &lt;span style=&#34;color:#a6e22e&#34;&gt;getObject&lt;/span&gt;(Object key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 从缓存中删除一条数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @param key 数据的键&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @return 原来的数据值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Object &lt;span style=&#34;color:#a6e22e&#34;&gt;removeObject&lt;/span&gt;(Object key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 清空缓存&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clear&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 读取缓存中数据的数目&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @return 数据的数目&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getSize&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * 获取读写锁，该方法已经废弃&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   * @return 读写锁&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;   */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; ReadWriteLock &lt;span style=&#34;color:#a6e22e&#34;&gt;getReadWriteLock&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;缓存实现类&lt;code&gt;PerpetualCache&lt;/code&gt;的实现非常简单，但可以通过装饰器来为其增加更多的功能。&lt;code&gt;decorators&lt;/code&gt;子包中存在许多装饰器，根据装饰器的功能可以将它们可以分为以下几个大类：&lt;/p&gt;</description>
			</item>
			<item>
				<title>编程是件孤独的事情么？</title>
				<link>https://yeecode.top/blog/123/</link>
				<pubDate>Sun, 15 Sep 2024 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/123/</guid>
				<description>&lt;p&gt;是的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;编程，从来就是一件孤独的事情。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;小时候，自己学习编程的时候，周围人都还不知道编程是什么。&lt;/p&gt;&#xA;&lt;p&gt;家在农村，家里当然也没有电脑。&lt;/p&gt;&#xA;&lt;p&gt;于是，就买了几本书籍翻看。&lt;/p&gt;&#xA;&lt;p&gt;然后，想要真正练习的时候，就跑到网吧。下载一套免安装的编程软件（那时候，写的是Flash的ActionScript），在网吧的电脑里写程序。写完之后，再将程序文本复制出来，粘贴到自己的邮箱里保存。&lt;/p&gt;&#xA;&lt;p&gt;那时的网吧管理很混乱，打游戏的、爆粗口的、抽烟的、看片的……全都有&lt;/p&gt;&#xA;&lt;p&gt;或许只有我，用脏兮兮的键盘在写程序。&lt;/p&gt;&#xA;&lt;p&gt;期间，会有几个混混过来好奇的问，“你TM的在干吗的？”&lt;/p&gt;&#xA;&lt;p&gt;我就只能笑嘻嘻地回应下，“写……写点东西”。&lt;/p&gt;&#xA;&lt;p&gt;我既不敢说自己在干吗，免得他们觉着我在装逼；也不敢不说，免得他们觉着我怠慢他们。&lt;/p&gt;&#xA;&lt;p&gt;好在，我戴个眼镜文绉绉的样子，他们也懒得欺负。&lt;/p&gt;&#xA;&lt;p&gt;而最怕的事情，还是死机或者断电！一旦发生，不仅程序没保存，网吧电脑的“还原精灵”还会将你下载的编程软件给清理的干干净净。这时，伴随着网吧此起彼伏的谩骂声重新下载一遍编程软件是少不了的！&lt;/p&gt;&#xA;&lt;p&gt;而当从网吧走出，你会觉着嗓子疼的厉害，好几天都能感觉到干涩——毕竟，在二手烟组成的浓云中呼吸了大半天！&lt;/p&gt;&#xA;&lt;p&gt;那时，编程的书也很少——毕竟从小县城能买到几本就不错了，买啥看啥！&lt;/p&gt;&#xA;&lt;p&gt;不过，那时候，我还是写了一些Flash小游戏。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/123/pic/005_hu_a6cecf7ad8365e7b.webp&#34; alt=&#34;图片&#34; width=&#34;676&#34; height=&#34;493&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/123/pic/009_hu_e3a8962e9793ae52.webp&#34; alt=&#34;图片&#34; width=&#34;701&#34; height=&#34;502&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;我相信，那时候，网吧里的我是孤独的——没有人懂我在做什么！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;上大学时，我也并不是计算机专业。&lt;/p&gt;&#xA;&lt;p&gt;但是，喜欢编程的我参加了许多的比赛，也加入了学校的网站组织——学生在线，负责维护学校的网站。&lt;/p&gt;&#xA;&lt;p&gt;每个五一、十一的假期，我都在工程训练中心度过。&lt;/p&gt;&#xA;&lt;p&gt;那时，已经有了三五个和我一样热爱编程的好友，但我，或者说我们，依旧是孤独的。在学院里、班级里，我们依旧是少数，依旧是孤独的。&lt;/p&gt;&#xA;&lt;p&gt;我曾经被关在空荡荡的实验楼，我也熬过无数的通宵……&lt;/p&gt;&#xA;&lt;p&gt;有一次，在枯燥的实验课上。我和小伙伴总感觉教材上的PLC程序有些问题——在循环一定次数之后，电梯的调度会出现问题。于是，我们俩着手证实这件事。&lt;/p&gt;&#xA;&lt;p&gt;最终，在错过了晚饭、也差点要错过全院会议的时候，我们证实了我俩的判断是正确的，并且让实验课老师相信了这一点：教材上的程序有问题。&lt;/p&gt;&#xA;&lt;p&gt;老师说，这套教材和实验器材已经用了十几年了，从没有人发现过其中的错误。&lt;/p&gt;&#xA;&lt;p&gt;当然，除了上课，我还写过很多有趣的程序：机器人、智能车、供全校师生查校车的软件、许多学院的院系官网……&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/123/pic/006_hu_36676c709219fbd5.webp&#34; alt=&#34;图片&#34; width=&#34;306&#34; height=&#34;230&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/123/pic/003_hu_ce492fd70280142f.webp&#34; alt=&#34;图片&#34; width=&#34;306&#34; height=&#34;230&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/123/pic/004_hu_e21739d27d4f6e70.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;325&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这些事情，有些是我一个人做的，有些是和学院的小伙们做的，有些是和学生在线的小伙伴做的……&lt;/p&gt;&#xA;&lt;p&gt;但是，我们都是孤独的——大多数同学在追求学分，或者沉迷网游，或者享受恋爱，而我们在其中，显然是孤独的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;在大家的眼中，我们是一批怪人。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;即使工作之后，编程也是孤独的。&lt;/p&gt;&#xA;&lt;p&gt;周围的同事当然都是程序员，但是，大多数时候，我们每个人都在忙着自己的事情：想自己的问题、写自己的程序、找自己的Bug。&lt;/p&gt;&#xA;&lt;p&gt;当你遇到些实在难缠的问题时，当然可以寻求同事的帮助，但也要记得：&lt;strong&gt;光是将自己眼前面对的问题阐述给对方，就需要很大的成本。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;你需要说明：整个逻辑的背景、你的编写思路、你遇到了什么问题、你觉着是什么原因、你已经进行了怎样的调试并得到了怎样的结果，然后，对方才能给你一些建议。&lt;/p&gt;&#xA;&lt;p&gt;他们能给的只是建议。而这些建议的落实，还是需要你来进行。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;所以，编程，一直都是孤独的事情。&lt;/p&gt;&#xA;&lt;p&gt;哪怕你周围渐渐有了三五好友，哪怕你周围已经全是码农同事，&lt;/p&gt;&#xA;&lt;p&gt;而&lt;strong&gt;编程，终究是孤独的事情。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;编程，是思维的游戏！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;这也是编程的魅力！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;最后，我是程序员&lt;strong&gt;易哥&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;可以&lt;strong&gt;关注&lt;/strong&gt;我，让我们一起探索编程的魅力！&lt;/p&gt;</description>
			</item>
			<item>
				<title>如何看待程序员持续写技术博客？</title>
				<link>https://yeecode.top/blog/122/</link>
				<pubDate>Sun, 01 Sep 2024 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/122/</guid>
				<description>&lt;p&gt;这是一件&lt;strong&gt;难能可贵&lt;/strong&gt;的事情。&lt;/p&gt;&#xA;&lt;p&gt;首先，我自己也是写技术博客、做开源项目的。&lt;/p&gt;&#xA;&lt;p&gt;技术博客会发在知乎上，也会发在自己的主页里。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/122/pic/001_hu_79c7caafbe2cabf.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;674&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而开源项目主要是通过GitHub。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/122/pic/002_hu_680aead2aa06d4a4.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;628&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而我想说，无论是持续写技术博客，还是做开源项目，都是难能可贵的：一是难能，二是可贵。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一难能&#34;&gt;一、难能&lt;/h2&gt;&#xA;&lt;p&gt;持续做任何事都不太容易，何况是写技术博客。它要求作者必须要有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;强大的学习能力、融会贯通能力。&lt;/strong&gt; 毕竟是技术文章，只有不断地学习，才能赶上最新的技术点。然后还要有自己的感悟、认知，进而能够输出文章。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;恒心，足够的恒心。&lt;/strong&gt; 坚持一件事情，肯定要有恒心！不能一段时间想写，一段时间就断更。当然，这一点我做的不好，有时确实会 忙不开，然后忘记写。&lt;/li&gt;&#xA;&lt;li&gt;**耐心！**其实写文章真的需要耐心。就不提写文章时需要坐在电脑前几个小时，就算是写好了文章然后发布到各个平台，光整理格式也需要很久。所以，我真的是常常写了文章，然后懒得去发……&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;强大的内心。&lt;/strong&gt; 文章写多了，难免会有一些错字、纰漏。可能会被一些读者曲解放大、揪着不放。甚至进行攻击。不过我这个还好，我的读者都比较友好。发现自己有错误也主动认错修改。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;二可贵&#34;&gt;二、可贵&lt;/h2&gt;&#xA;&lt;p&gt;而写技术博客从作者、读者等各个角度看，都是一件很可贵的事情。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;首先，对于作者自己是一个比较好的梳理知识的途径。&lt;/strong&gt; 通过技术博客，能够让作者将原本可能混沌的知识梳理成脉络并沉淀下来。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;其次，对于读者而言，是一个学习知识的平台。&lt;/strong&gt; 对于每个技术人员，其成长的过程中肯定受益于许多的技术文章。这些文章或许让我们入门了某项技术、或许让我们了解了某个前沿、或许让我们解开了某个疑惑。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;然后我还要再说一点：技术博客因为太小众、太专业，大都没什么浏览量。而及时被相关人员看到，大家也大都是看看、收藏，而很少点赞。所以，写技术博客大多时候是一件孤独的事情。这就更加体现了其可贵之处。&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;大家可以看一下我的技术文章，基本是越干货的文章点赞越少。&lt;/p&gt;&#xA;&lt;p&gt;不过，持续写技术博客确实是一件难能可贵的事情。我会继续坚持。&lt;/p&gt;&#xA;&lt;p&gt;想要学习编程的同学也可以&lt;strong&gt;关注&lt;/strong&gt;我。&lt;/p&gt;&#xA;&lt;p&gt;我是程序员易哥。&lt;/p&gt;</description>
			</item>
			<item>
				<title>写在Flash落幕时</title>
				<link>https://yeecode.top/blog/83/</link>
				<pubDate>Sat, 09 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/83/</guid>
				<description>&lt;p&gt;大家肯定也从各种途径听说过，Adobe正式停止了对Flash的支持。&lt;/p&gt;&#xA;&lt;p&gt;Adobe已向用户发出多轮提醒，以通知用户Adobe在2020年12月31日正式停止对Flash Player的更新支持。而且，即便用户不手动删除Flash Player，Flash内容也会在2021年1月份停止工作。&lt;/p&gt;&#xA;&lt;p&gt;Flash终于还是落幕了。&lt;/p&gt;&#xA;&lt;p&gt;其实关于Flash要被淘汰的消息早已人尽皆知，而且Flash本身也式微多年。&lt;/p&gt;&#xA;&lt;p&gt;可当我真正听到这个消息时，还是有些震惊和不舍。&lt;/p&gt;&#xA;&lt;p&gt;一切似乎有点太快。&lt;/p&gt;&#xA;&lt;p&gt;毕竟上古神器Visual Basic虽停止了演化，但微软还是在其稳定性和兼容性上做工作。&lt;/p&gt;&#xA;&lt;p&gt;可对Flash而言，就有点余音尚存却戛然而止的意思。&lt;/p&gt;&#xA;&lt;p&gt;Flash中的ActionScript是我学习的第一门编程语言。正是通过Flash和ActionScript，我才第一次感受到什么是编程。&lt;/p&gt;&#xA;&lt;p&gt;所以，一直想写篇文章记录下，且与一片细数弊端和欢庆落幕的主流论调并不相恰。&lt;/p&gt;&#xA;&lt;p&gt;不过确实很懒，也亏了早上公交车堵，才在上班路上码了下来。&lt;/p&gt;&#xA;&lt;p&gt;自学Flash时是在高中。而且不得不说，Flash确实是一门极好的编程入门环境，直到现在我也这么认为：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;它具有图层和帧，且与编程语言无缝对接。配合图层和帧，你可以快速创建出界面优美、交互良好的界面。相比而言C语言那黑框框简直弱爆了，而VB那上古界面也复杂和逊色太多。&lt;/li&gt;&#xA;&lt;li&gt;它具有强大的本地操作能力。你可以直接通过语句操作本地文件，这点就和C、Java、VB没有太多区别。&lt;/li&gt;&#xA;&lt;li&gt;它可以方便地嵌入网页中，为网页提供固定的或者是可交互的酷炫的动画。这可能是它应用最广的场景。&lt;/li&gt;&#xA;&lt;li&gt;它可以直接导出gif、swf、html甚至exe。尤其是exe，它让你感觉你真的在编写一个“软件”，而不是“网页”，这是JavaScript所无法比拟的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;也正因为以上优点，Flash几乎是最好玩的编程环境，ActionScript几乎是最好的编程语言。你可以用它来写软件、做网页、搞游戏……做好多好多事情……&lt;/p&gt;&#xA;&lt;p&gt;所以，很幸运将它做为上手的编程语言。&lt;/p&gt;&#xA;&lt;p&gt;当然，那时我并没有分析和选择编程语言的能力，或许只是我在写网页时久仰过太多次它的大名。&lt;/p&gt;&#xA;&lt;p&gt;那时，Flash的开发者被称为“闪客”，在我心目中是一个带着光芒的称呼。&lt;/p&gt;&#xA;&lt;p&gt;力有不逮，心向往之。&lt;/p&gt;&#xA;&lt;p&gt;我也尝试和闪客们一样，做一些电子相册之类的东西。例如下面这个就是当时下载了网上的素材包自己做的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/010_hu_3315bfb2e2202b1e.webp&#34; width=&#34;891&#34; height=&#34;539&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但是不得不说，对我而言，太难了。碰撞检测、速度优化，这些东西对面向对象都还没搞明白的我而言都太难了，而且搞完也难有用武之地。&lt;/p&gt;&#xA;&lt;p&gt;所以，大多数时候用它来做的就是写一些照猫画虎的乱七八糟的小游戏。&lt;/p&gt;&#xA;&lt;p&gt;但不得不说，这确实可以给高中的我带来极大的成就感。&lt;/p&gt;&#xA;&lt;p&gt;如今，我电脑上早已没了Flash开发环境，甚至连Flash Player都没有了。但，硬盘中仍保存着高中编写的小游戏。&lt;/p&gt;&#xA;&lt;p&gt;幸运的是，当时为了便于运行，我在有些项目做完后导出了exe。而这些exe文件，至今仍可运行。&lt;/p&gt;&#xA;&lt;p&gt;例如，早在当年，我就为退休后的时光做好了准备——去街头给人电脑算命！&lt;/p&gt;&#xA;&lt;p&gt;“小兄弟，我看你脸色为#FFFF00，近期可能遇到异常啊，要不要来我这测个人品？”&lt;/p&gt;&#xA;&lt;p&gt;然后我就掏出这个软件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/001_hu_d9eff021d6280ebe.webp&#34; width=&#34;591&#34; height=&#34;430&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;给他测一番人品。&lt;/p&gt;&#xA;&lt;p&gt;这东西，融合了东方五千年乾坤瑰宝，吸纳了西方近现代科技文明。给出的结果，谁不信？！&lt;/p&gt;&#xA;&lt;p&gt;这就是说服力，是伏羲、周公、冯诺依曼、乔治布尔等人一同带来的说服力，谁不服？！&lt;/p&gt;&#xA;&lt;p&gt;所以，这个生意一定行！&lt;/p&gt;&#xA;&lt;p&gt;而且，这繁体字体，加上红绿配色给出的结果，让人感觉踏实准确的同时，给人以沁人心脾的美感！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/002_hu_caa82900a56fb867.webp&#34; width=&#34;588&#34; height=&#34;424&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;奥，对了。“电磁铁”是我那时候的网名，初中起的。没啥太大意思，就是酷爱物理，然后起名时恰好看到了物理书上的电磁铁，想到电磁铁看似简单，却实现了电与磁两种看不见摸不着的神奇场的转换。古乘东方司南之意，今切西方电波之味。所以就起了这个名字。&lt;/p&gt;&#xA;&lt;p&gt;而且，这名字，人品好。上图就是证据！&lt;/p&gt;&#xA;&lt;p&gt;而且这软件测得准，准极了！&lt;/p&gt;&#xA;&lt;p&gt;都是随机数出来的，能不准么？&lt;/p&gt;&#xA;&lt;p&gt;不准那也是随机种子选的不对，和程序没啥关系。&lt;/p&gt;&#xA;&lt;p&gt;然后接元宝也做过，老游戏了。&lt;/p&gt;&#xA;&lt;p&gt;天若有情天亦老，春风送暖接元宝！&lt;/p&gt;&#xA;&lt;p&gt;这界面看着就喜庆！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/004_hu_1336910b723d4dba.webp&#34; width=&#34;676&#34; height=&#34;494&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;当时还给自己设计了个吉祥物，毕竟么，玩Flash也不能忘了PhotoShop。&lt;/p&gt;&#xA;&lt;p&gt;萌萌的小熊多可爱！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/005_hu_a6cecf7ad8365e7b.webp&#34; width=&#34;676&#34; height=&#34;493&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而且，这过年有，毕业肯定不能少。&lt;/p&gt;&#xA;&lt;p&gt;毕业的时候，我整理了班级同学的照片，做了个小游戏并发给大家。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/006_hu_69b6a23ad06ea742.webp&#34; width=&#34;700&#34; height=&#34;497&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这个游戏是找不同，也能让大家一起回忆下高中的生活。&lt;/p&gt;&#xA;&lt;p&gt;印象中，如果通关，会有一首我写的小诗。&lt;/p&gt;&#xA;&lt;p&gt;自己——写的——小诗？&lt;/p&gt;&#xA;&lt;p&gt;那肯定很尬，对吧。&lt;/p&gt;&#xA;&lt;p&gt;但放心，我现在完全感觉不到尬！&lt;/p&gt;&#xA;&lt;p&gt;因为当时不知怎么想的，把游戏做的太难了！&lt;/p&gt;&#xA;&lt;p&gt;现在我自己到第三关就卡住了！！！&lt;/p&gt;&#xA;&lt;p&gt;布置关卡的人，被自己的关卡卡住了。&lt;/p&gt;&#xA;&lt;p&gt;哈哈。&lt;/p&gt;&#xA;&lt;p&gt;每张图有三处不同，点击第三处就成功跳转了。所以只能截取到两处的图片。&lt;/p&gt;&#xA;&lt;p&gt;这是第一关（第三处为背后书立上标签少了）&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/83/pic/007_hu_890fb1a7569d5546.webp&#34; width=&#34;702&#34; height=&#34;504&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这是第二关（第三处为左上角的树枝少了一根）&lt;/p&gt;</description>
			</item>
			<item>
				<title>如何阅读源码？</title>
				<link>https://yeecode.top/blog/39/</link>
				<pubDate>Sun, 09 Aug 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/39/</guid>
				<description>&lt;p&gt;本回答将按照下面的章节体系进行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1 我为什么阅读源码&#xA;2 阅读源码的好处&#xA;3 阅读源码的困难&#xA;4 阅读源码的步骤&#xA;5 阅读源码的方法&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;1-我为什么阅读源码&#34;&gt;1 我为什么阅读源码&lt;/h2&gt;&#xA;&lt;p&gt;我开始阅读源码是在进行互联网开发的第八九个年头。在此之前，我做过校园网站，接过网站开发的私活，进行过理论算法相关的研究，也设计开发了许多系统。我对我做过的系统都比较有信心，它们也都运行的不错，但是一个疑问却在我的心头逐渐浮现：我的架构和世界最优良架构之间的差距到底有多大？&lt;/p&gt;&#xA;&lt;p&gt;阅读开源项目的源码能给我答案。&lt;/p&gt;&#xA;&lt;p&gt;许多优秀的开源项目历经数千开发者的数万次提交，被数亿用户使用。这些项目从可扩展性、可靠性、可用性等各个角度考量，都是十分优良的。通过阅读这些项目的源码能让我找到自己在软件设计和开发上的不足。&lt;/p&gt;&#xA;&lt;p&gt;于是我开始了我的源码阅读计划。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-阅读源码的好处&#34;&gt;2 阅读源码的好处&lt;/h2&gt;&#xA;&lt;p&gt;阅读源码的好处很多，而且已经成为共识。光靠铺天盖地的源码阅读活动就能感知一二，虽然我觉着那些活动都太过浮躁，主要是个噱头，学不到啥。&lt;/p&gt;&#xA;&lt;p&gt;但是不可否认，阅读源码的好处极多，包括但不限于：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;透彻地理解项目的实现原理&lt;/li&gt;&#xA;&lt;li&gt;接触到成熟和先进的架构方案&lt;/li&gt;&#xA;&lt;li&gt;学习到可靠与巧妙的实施技巧&lt;/li&gt;&#xA;&lt;li&gt;发现自身知识盲点，提升自身知识储备&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以，我有些后悔，我觉着我应该更早地开始源码阅读。我推荐进行源码阅读的时机是：&lt;strong&gt;学会编程语言的基本知识，并做过少量项目之后&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我们知道，学编程的过程中在不断接收新的知识，进步很快。刚开始做项目时，进入实践领域，进步很快。然后就到了平台期，可能几年下来都是重复的增删改查，毫无进步。&lt;strong&gt;这段平台期实际是进行源码阅读的良好时机，能让你的技术持续进步&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;3-阅读源码的困难&#34;&gt;3 阅读源码的困难&lt;/h2&gt;&#xA;&lt;p&gt;当我们阅读一份源码时，需要面对的困难通常有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;难以归纳的凌乱文件&lt;/li&gt;&#xA;&lt;li&gt;稀奇古怪的类型组织&lt;/li&gt;&#xA;&lt;li&gt;混乱不堪的逻辑跳转&lt;/li&gt;&#xA;&lt;li&gt;不明其意的方法变量&lt;/li&gt;&#xA;&lt;li&gt;……&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以很多人即使知道阅读源码的好处，也坚持不下来。就因为以上困难难以克服。&lt;/p&gt;&#xA;&lt;p&gt;而阅读源码的难，是正常的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;31-时间维度带来的困难&#34;&gt;3.1 时间维度带来的困难&lt;/h2&gt;&#xA;&lt;p&gt;从时间维度上看，每一个优秀的工程项目都经历了从雏形到成熟的曲折演化过程。而整个过程都会被映射到一个时间点上，肯定很难。&lt;/p&gt;&#xA;&lt;p&gt;于是有人提出了“阅读源码时，从第一次提交开始阅读”的主意。我要说一下，这是错误的！&lt;/p&gt;&#xA;&lt;p&gt;这是一种纸上谈兵式的错误，提出这种方法的人肯定没怎么读过源码。事实上，我也有过这种想法，然后在实践中很快被抛弃了。&lt;/p&gt;&#xA;&lt;p&gt;如果一个项目只经过了几次提交，这种方法获取可行。而一个优秀的通常有几千上万次提交，将这几千上万次提交都读完，工作量要比把当前最新版本的代码读完难的多得多！因为其时间维度的复杂度比空间维度复杂度大得多了。&lt;/p&gt;&#xA;&lt;p&gt;我用下面的图片展示了项目发展的过程，一个项目从版本1到版本n，逐渐完善。版本1一般是最简单最基础的，但是，要想从版本1读起，一直读到版本n，可能要阅读几千个版本。难度极大，远不如直接去读版本n。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/39/pic/001_hu_e47191ef4447a2d7.webp&#34; alt=&#34;图片&#34; width=&#34;482&#34; height=&#34;304&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;还有，许多项目的第一次提交并不是只有几行代码的init项目，往往第一次提交就是几百个类。而且，初期的代码组织还比较混乱。毕竟，作者也不知道该项目能火，往往比较随意。&lt;/p&gt;&#xA;&lt;p&gt;更别说，历史提交中还夹杂很多的Bug、回退、依赖包升级等等。想要把每次Bug、回退、依赖包升级所产生的历史背景都搞清楚，这几乎是不可能的任务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;32-空间维度的困难&#34;&gt;3.2 空间维度的困难&lt;/h2&gt;&#xA;&lt;p&gt;每一个优秀的工程项目都凝聚了众多开发者的缜密思维逻辑，而这些逻辑都被投射到了平面的代码上。这使得阅读源码的过程成了逆推开发者思维逻辑的过程，显然，逆推是很难的。&lt;/p&gt;&#xA;&lt;p&gt;不过，这方面的困难真有解决方案：&lt;strong&gt;详细了解开源项目的功能，然后自己琢磨该如何实现&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这样，就将“逆推”的过程转化为了“正向推导+验证”的过程，这样就相对简单了。&lt;/p&gt;&#xA;&lt;p&gt;但无论如何，阅读源码总不会太简单。于是有人说读懂源码比编写源码更为困难，想必也是有一定道理的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;4-阅读源码的步骤&#34;&gt;4 阅读源码的步骤&lt;/h2&gt;&#xA;&lt;p&gt;阅读源码推荐按照下面的步骤进行：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;了解项目的背景。这相当于了解了项目的需求。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;充分了解项目的功能，并熟练使用。我们说过，将“逆推”的过程转化为“正向推导+验证”的过程是阅读源码的一个重要方法。而了解项目的功能是这个方法的基础。&lt;/li&gt;&#xA;&lt;li&gt;调试代码。通过断点调试，掌握整个代码的流程走向、主次关系、依赖关系。&lt;/li&gt;&#xA;&lt;li&gt;划分源码。根据每个包、模块的功能不同，将源码划分为几个部分。&lt;/li&gt;&#xA;&lt;li&gt;由底层到上层，逐个击破。先阅读不依赖其他模块的，或者依赖其他模块比较少的基础模块。然后逐步上移，完成整个项目源码的阅读。&lt;/li&gt;&#xA;&lt;li&gt;横向总结。在由底层到上层阅读完成后，横向以功能点为维度串联源码的实现逻辑。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;一般情况下，一个项目的源码要在3~4个月左右读完。否则，可能读到后面的，已经忘记前面的功能了。&lt;/p&gt;&#xA;&lt;p&gt;当然越快越好，但考虑到我猿们还要加班，时间太短了不太现实。&lt;/p&gt;&#xA;&lt;h2 id=&#34;5-阅读源码的方法&#34;&gt;5 阅读源码的方法&lt;/h2&gt;&#xA;&lt;p&gt;有人说读懂源码比编写源码更为困难，不无道理。&lt;strong&gt;而源码阅读和软件开发一样，是一个非常综合的能力，没有一个万全之法&lt;/strong&gt;。但有很多不错的方法。&lt;/p&gt;&#xA;&lt;p&gt;例如一些常用的方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;调试追踪：多数情况下，当我们对某些变量的含义产生疑惑时，借助开发工具的调试功能直接查看变量值的变化是一个非常好的方法。而且该方法还能指引代码逻辑的跳转过程，对于理解源码极为有用。&lt;/li&gt;&#xA;&lt;li&gt;归类总结：优秀的源码都遵循一定的设计规则，这些规则可能是项目间通用的，也可能是项目内独有的。在源码阅读的过程中将这些设计规则总结出来，将会使得源码阅读的过程越来越顺畅。&lt;/li&gt;&#xA;&lt;li&gt;上下文整合：有些对象、属性、方法等仅仅通过自身很难判断其作用和实现。此时可以结合其调用的上下文，查看对象何时被引用、属性怎样被赋值、方法为何被调用，这对于了解它们的作用和实现很有帮助。&lt;/li&gt;&#xA;&lt;li&gt;类比阅读：如果存在实现某功能的两条或者多条路径，可以类别阅读，找出他们处理逻辑的不同。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;还有很多方法，不再一一介绍。因为没有实在的源码案例，光介绍显得很浮。&lt;/p&gt;</description>
			</item>
			<item>
				<title>《通用源码阅读指导书》前言</title>
				<link>https://yeecode.top/blog/73/</link>
				<pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/73/</guid>
				<description>&lt;p&gt;有一段时间，我觉着我非要阅读开源项目的源码不可。&lt;/p&gt;&#xA;&lt;p&gt;那时，我已经在公司负责设计和开发了许多系统。如果连大学时带领大家开发和维护学校网站也算上的话，我已经进行软件开发整整十个年头了。在这十个年头里，我对自己设计和开发的系统都很有信心。但却有一个疑惑一直在我心头萦绕：我不知道，我的架构和世界最优良架构之间的差距到底有多大。&lt;/p&gt;&#xA;&lt;p&gt;阅读开源项目的源码能给我答案。&lt;/p&gt;&#xA;&lt;p&gt;许多优秀的开源项目历经数千开发者的数万次提交，被数亿用户使用。这些项目从可扩展性、可靠性、可用性等各个角度考量，都是十分优良的。通过阅读这些项目的源码能让我找到自己在软件设计和开发上的不足。&lt;/p&gt;&#xA;&lt;p&gt;于是我开始了我的源码阅读计划。&lt;/p&gt;&#xA;&lt;p&gt;在阅读源码的过程中，我看过不少资料。但很多资料对于源码中简单的部分讲解的细致入微；而对复杂的部分则避而不谈或含糊其辞。&#xA;在阅读源码的过程中，我也走过了不少弯路。经常在一个难点中挣扎很久不得前进。&lt;/p&gt;&#xA;&lt;p&gt;当然，阅读源码也让我收获颇丰。它不仅让我知道了自己的设计与优良设计之间的差距，还让我学到了许多的架构技巧、编程知识。在源码阅读的过程我也总结出了许多的经验和方法。因此，我决定写这本书，将这些经验和方法分享出来，指引许多和我一样前行在源码阅读道路上的人。&lt;/p&gt;&#xA;&lt;p&gt;源码阅读首先要选定相应的源码作为材料。从项目的成熟度、涉及面、应用广度、项目规模等多方面考虑，本书最终选中MyBatis的源码。因此，本书将以阅读MyBatis源码为例，介绍源码阅读的经验和方法。&lt;/p&gt;&#xA;&lt;p&gt;在本书的写作中，我努力做到详尽而不罗嗦。本书以包为单位，对MyBatis源码中的300多个类都进行了介绍。在这个过程中，对于简单或重复的类一笔带过，但对于越复杂的类则越是逐方法、逐行地分析。力求让大家读的顺、读的懂、有收获。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;本书一共分为了五个模块，每个模块的主要内容如下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景介绍模块&#34;&gt;背景介绍模块：&lt;/h2&gt;&#xA;&lt;p&gt;第1章介绍了源码阅读的意义和方法。&lt;/p&gt;&#xA;&lt;p&gt;第2章对MyBatis的背景和快速上手方法进行了介绍。这一章的内容是简单但重要的。对于任何一个软件，其背景对应于软件的“设计需求”，其使用对应于软件的“主要功能”。把握了一个软件设计需求和主要功能对于阅读软件的源码很有帮助。&lt;/p&gt;&#xA;&lt;p&gt;第3章中使用断点调试方法对MyBatis的执行过程进行了追踪。该章节的内容有助于我们了解整个MyBatis的内部框架。&lt;/p&gt;&#xA;&lt;p&gt;第4章对MyBatis的源码结构进行了介绍，并根据源码包的功能对包进行了分类。&lt;/p&gt;&#xA;&lt;h2 id=&#34;基础功能包源码阅读模块&#34;&gt;基础功能包源码阅读模块：&lt;/h2&gt;&#xA;&lt;p&gt;在这一模块中，我们对5个基础功能包中的源码进行了阅读。基础功能包相对独立，与MyBatis的核心逻辑耦合小，比较适合作为我们源码阅读的切入点。在阅读这些源码时，我们也会逐步介绍一些阅读源码时常用的方法技巧。&lt;/p&gt;&#xA;&lt;p&gt;第5章介绍了exceptions包的源码。我们可以通过该包了解MyBatis的整个异常体系。&lt;/p&gt;&#xA;&lt;p&gt;第6章介绍了reflection包的源码。该包基于反射提供了创建对象、修改对象属性、调用对象方法等功能。这些功能在MyBatis的参数处理、结果处理等环节都发挥了重要的作用。&lt;/p&gt;&#xA;&lt;p&gt;第7章介绍了annotations包与lang包的源码。这两个包中全是注解类。我们将通过对Java注解的学习详细了解每个注解类的含义。最后，我们还通过源码分析了注解类如何在MyBatis的运行中发挥作用。&lt;/p&gt;&#xA;&lt;p&gt;第8章介绍了type包的源码。通过这一章我们将了解MyBatis如何组织和实现类型处理器，以完成对各种类型数据的处理。&lt;/p&gt;&#xA;&lt;p&gt;第9章介绍了io包的源码。通过该包我们将了解到MyBatis如何完成外部类的筛选和载入。&lt;/p&gt;&#xA;&lt;p&gt;第10章介绍了logging包的源码。logging包不仅为MyBatis提供了日志记录功能，还提供了获取和记录JDBC中日志的功能。通过这一章节，我们将了解这些功能的实现细节。&lt;/p&gt;&#xA;&lt;p&gt;第11章介绍了parsing包的源码。通过这一章，我们将了解MyBatis如何完成XML文件的解析。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置解析包源码阅读模块&#34;&gt;配置解析包源码阅读模块：&lt;/h2&gt;&#xA;&lt;p&gt;第12章介绍了配置解析相关类的分类方法。对于配置解析类相关的类可以按照类的功能将其划分为解析器类或解析实体类。&lt;/p&gt;&#xA;&lt;p&gt;第13章介绍了binding包的源码。该包负责将SQL语句接入到映射接口中。&lt;/p&gt;&#xA;&lt;p&gt;第14章介绍了builder包的源码。该包中的建造者基类和工具类为MyBatis基于建造者模式建造对象提供了基础。此外，该包还完成了映射文件和映射注解的解析工作。&lt;/p&gt;&#xA;&lt;p&gt;第15章介绍了mapping包的源码。该包完成了SQL语句的处理、输入参数的处理、输出结果的处理等功能，并为MyBatis提供了多数据库支持的能力。&lt;/p&gt;&#xA;&lt;p&gt;第16章介绍了scripting包的源码。就是在这个包中，复杂的SQL节点被逐步解析为纯粹的SQL语句。该章节将带我们详细了解这一解析过程。&lt;/p&gt;&#xA;&lt;p&gt;第17章介绍了datasource包的源码。该包包含了MyBatis中与数据源相关的类，包括非池化数据源、池化数据源、数据源工厂等。也正是通过该包，MyBatis完成了和数据库的对接。&lt;/p&gt;&#xA;&lt;h2 id=&#34;核心操作包源码阅读模块&#34;&gt;核心操作包源码阅读模块：&lt;/h2&gt;&#xA;&lt;p&gt;在这一模块中，我们将详细介绍MyBatis的核心操作包。&lt;/p&gt;&#xA;&lt;p&gt;第18章介绍jdbc包的源码。该包仅使用6个类便为MyBatis提供了运行SQL语句和脚本的能力。&lt;/p&gt;&#xA;&lt;p&gt;第19章介绍了cache包的源码。该包向我们展示了MyBatis如何使用装饰器模式为用户提供丰富的、可配置的缓存。并且该章节还从功能维度出发详细介绍了MyBatis的两级缓存机制。&lt;/p&gt;&#xA;&lt;p&gt;第20章介绍了transaction包的源码。该包为MyBatis提供了内部和外部的事务支持。&lt;/p&gt;&#xA;&lt;p&gt;第21章介绍了cursor包的源码。通过该包，MyBatis能将查询结果封装为游标形式返回。&lt;/p&gt;&#xA;&lt;p&gt;第22章介绍了executor包的源码。executor包是MyBatis中最为重要也是最复杂的包。在这一章中，我们以子包为单位分别介绍了MyBatis的主键自增功能、懒加载功能、语句处理功能、参数处理功能、结果处理功能、结果集处理功能。然后在此基础上对MyBatis中执行器的源码进行了阅读。最后，我们阅读了MyBatis中错误上下文的源码，了解MyBatis如何及时地保留错误发生时的现场环境。&lt;/p&gt;&#xA;&lt;p&gt;第23章介绍了session包的源码。session包是一个对外接口包，是用户在使用MyBatis时接触最多的包。&lt;/p&gt;&#xA;&lt;p&gt;第24章介绍了plugin包的源码。在该章节中我们编写了一个插件，然后通过源码详细了解了MyBatis插件的实现原理以及MyBatis插件平台的架构。&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结与展望模块&#34;&gt;总结与展望模块：&lt;/h2&gt;&#xA;&lt;p&gt;第25章对阅读MyBatis源码过程中的技巧方法进行了总结。&lt;/p&gt;&#xA;&lt;p&gt;第26章从项目的成熟度、涉及面、应用广度、规模等角度综合考量为大家推荐了一些优秀的开源项目。学习完本书后，大家可以从这些项目中挑选一些进行源码阅读。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;源码阅读毕竟是一个对知识广度和深度都有较高要求的工作。为了大家能够顺利地阅读MyBatis的源码，我们会在很多章节之前介绍该章节源码涉及的基础知识。先掌握这些基础知识后再阅读相关源码则会轻松很多。&lt;/p&gt;&#xA;&lt;p&gt;受篇幅所限，书中只能给出部分MyBatis源码。我们将完整的带中文注释的MyBatis源码整理成了开源项目供大家下载、参考。该项目的地址为：&lt;a href=&#34;https://github.com/yeecode/MyBatisCN&#34;&gt;https://github.com/yeecode/MyBatisCN&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;为了大家能更轻松地理解和掌握一些相对复杂的知识点，我们还准备了许多示例项目。该示例项目也开源供大家下载，地址为：&lt;a href=&#34;https://github.com/yeecode/MyBatisDemo&#34;&gt;https://github.com/yeecode/MyBatisDemo&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;受限于我的水平和时间，书中难免会有疏漏之处。您可以通过我的个人主页与我取得联系并与我交流。在那里也能看到我的最新项目。我的个人主页地址是：&lt;a href=&#34;https://yeecode.top&#34;&gt;https://yeecode.top&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;通过阅读本书，您将详细了解MyBatis中每一个类的结构、原理、细节。但要注意，这只是我们阅读本书的额外收获。掌握源码阅读的方法和技巧，并将这些方法技巧应用到其他项目的源码阅读工作、系统设计工作、软件开发工作中，这才是阅读本书的最终目的。&lt;/p&gt;&#xA;&lt;p&gt;源码阅读是一个过程艰苦而结果可观的工作。每一个潜心阅读源码的开发者都值的尊敬，也希望本书能够在您源码阅读的过程中为您提供一些帮助，让您多一些收获。&lt;/p&gt;&#xA;&lt;p&gt;加油！奋斗路上的你和我。&lt;/p&gt;</description>
			</item>
			<item>
				<title>为什么网上总有人说WEB开发没技术含量？</title>
				<link>https://yeecode.top/blog/38/</link>
				<pubDate>Sun, 19 Jul 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/38/</guid>
				<description>&lt;p&gt;确实，WEB开发毫无技术含量。&lt;/p&gt;&#xA;&lt;p&gt;早在十几年前，我就会WEB开发了。&lt;/p&gt;&#xA;&lt;p&gt;只不过，到现在，我还没学完……&lt;/p&gt;&#xA;&lt;p&gt;目前总结下来一共经历了下面几个阶段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;第一阶段：能跑就行、全面开花&#xA;第二阶段：全栈开发、整站落地&#xA;第三阶段：并发挑战、容量挑战&#xA;第四阶段：理论探究、行知结合&#xA;第五阶段：阅读源码、探求本源&#xA;第六阶段：构建地基、制造轮子&#xA;第七阶段：架构规划、协调开发&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同时本文也可以作为&lt;strong&gt;各位WEB开发者甚至软件开发者的进阶指南&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;不过我的水平有限，更高的阶段还未开启,仅供参考。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第一阶段能跑就行全面开花&#34;&gt;第一阶段：能跑就行、全面开花&lt;/h2&gt;&#xA;&lt;p&gt;我最早开始WEB开发的切入点是……是WEB页面设计。&lt;/p&gt;&#xA;&lt;p&gt;对的，你没有听错，页面设计！就是画WEB页面。当时加入了某校园网站。曾获教育部十佳网站，日访问在15万到30万之间。&lt;/p&gt;&#xA;&lt;p&gt;所以我熟练掌握各种PhotoShop技能。&lt;/p&gt;&#xA;&lt;p&gt;当时设计的很多网页的源文件也都还在。刚在自己找了下作品看了下，那些作品放在十年前倒也还凑活。但是，总让人觉着怪怪的。&lt;/p&gt;&#xA;&lt;p&gt;是的，当年的我也很快发现了这一点：&lt;strong&gt;技术还行，审美太差！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;我是我的业余职业生涯遇到了瓶颈。&lt;/p&gt;&#xA;&lt;p&gt;我这还没入行，就遇到了瓶颈！你能感受那种无助么。。。&lt;/p&gt;&#xA;&lt;p&gt;于是我，转行了！&lt;/p&gt;&#xA;&lt;p&gt;自此之后，我也会偶尔带带页面设计的新人，但是守住底线，只传授技术，绝不出作品。&lt;/p&gt;&#xA;&lt;p&gt;而后，我还是投入到新兴的前端开发工作中，并带起了一个前端团队。&lt;/p&gt;&#xA;&lt;p&gt;这方面的工作做了两三年，熟读《CSS权威指南》，导致我现在看到鲑鱼都觉着熟悉。&lt;/p&gt;&#xA;&lt;p&gt;各种嵌套、定位、JQuery、浮动……都不是问题。当时最大的挑战在于：浏览器兼容。&lt;/p&gt;&#xA;&lt;p&gt;有些老派的人在用IE6，而有些已经IE8\IE9，更大的挑战在于许多人用那时十分火爆的360浏览器、搜狗浏览器……各种浏览器对规范的支持各不相同，一片混乱。我们则是页面写一周，兼容调半月，苦不堪言。&lt;/p&gt;&#xA;&lt;p&gt;再后来，我学会了世界上最好的语言：PHP！&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;页面设计、前端开发、后端开发，我打通了！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;于是，我自己开发了一些小的站点，幸福感爆棚。&lt;/p&gt;&#xA;&lt;p&gt;这时的我，还会Flash呢，用ActionScript写点交互动画也不是问题。还做过小游戏，开心~&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;所以，那时的我自信地高呼：WEB开发没技术含量！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;对于用到的工具是什么原理，管它呢！我的站点能跑！那么多人用！都说我是大神！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;对了，在这一阶段，会CRUD+百度就足够了！多了没用！&lt;/p&gt;&#xA;&lt;h2 id=&#34;第二阶段全栈开发整站落地&#34;&gt;第二阶段：全栈开发、整站落地&lt;/h2&gt;&#xA;&lt;p&gt;页面设计、前端开发、后端开发，全都会了，那还得了？&lt;/p&gt;&#xA;&lt;p&gt;在学校么，闲着也是闲着！&lt;/p&gt;&#xA;&lt;p&gt;拉了一帮人接活了！&lt;/p&gt;&#xA;&lt;p&gt;不过，确切说是总有活找上来，有时候看着学期初没啥事，就接了。&lt;/p&gt;&#xA;&lt;p&gt;各个方向都找一个人，我做协调，四个人就能接手个项目。甚至，或者就某个方向的人不用找，我顶上，三个人也能开工。反正我也会。&lt;/p&gt;&#xA;&lt;p&gt;有些学院的网站开发之类的，直接接过来做掉！&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;这时遇到了服务器、域名、部署、升级、运维问题。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;没事，兵来将挡，水来土掩。有百度呢！&lt;/p&gt;&#xA;&lt;p&gt;曾经接过香港高校的单子，是个实验室的项目。赚的都是港币！不过当时真没经验，铆足了劲要价，要低了人家还给机会让我们再报一次，还是要低了……真是没见过世面，不会要太高。&lt;/p&gt;&#xA;&lt;p&gt;几个项目搞下来，发现技术毫无长进，就是不断重复。倒是团队磨合了不少，简直都快流水线作业了。几个人不用见面，都能把活干了！&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;技术没长进，就说明WEB开发的技术已经到头了，一定是这样……哈哈&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;所以，WEB开发不过如此。&lt;/p&gt;&#xA;&lt;p&gt;所以，&lt;strong&gt;那时的我会悄悄地说：WEB开发没技术含量！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;注意，要悄悄地！自己赚钱的东西，大声说，这不绝了自己的财路。&lt;/p&gt;&#xA;&lt;p&gt;不过在开发中，&lt;strong&gt;也遇到了一些算法问题。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;管他的，网上都能搜到！修改下，就能跑！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;又不是不能用！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;第三阶段并发挑战容量挑战&#34;&gt;第三阶段：并发挑战、容量挑战&lt;/h2&gt;&#xA;&lt;p&gt;之前做的项目都是能跑就行。简单来说，能跑就是成功，不能跑就再改！&lt;/p&gt;&#xA;&lt;p&gt;但是，进入公司正式工作开始面临一些新的问题：&lt;strong&gt;并发问题、容量问题&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;比如典型的，一个应用需要部署多个节点啊，多个应用的分布式节点之间互相依赖啊。依赖存在先后关系啊等等。&lt;/p&gt;&#xA;&lt;p&gt;于是乎，分布式登场了，携带着一众相关知识：分布式一致性、分布式存储、分布式计算、分布式锁、分库、分表、分流、读写分离……还附带了一众相关框架：Kafka\Rabbit\Zookeeper\RabbitMQ\RocketMq\Etcd……&lt;/p&gt;&#xA;&lt;p&gt;以上我就不列举了，大家耳熟能详。&lt;/p&gt;&#xA;&lt;p&gt;那段时间，我就主要在学习。&lt;/p&gt;&#xA;&lt;p&gt;当然学习不只是学会用，也要考虑其实现原理。可以动手自己实现下。&lt;/p&gt;&#xA;&lt;p&gt;例如下面是个RPC的最小实现，用来学习RPC就很好。&lt;/p&gt;&#xA;&lt;p&gt;用极少的类、方法演示了RPC的实现原理，是一个学习RPC工作原理的良好示例。&lt;/p&gt;&#xA;&lt;p&gt;​&#xA;&lt;a href=&#34;https://github.com/yeecode/EasyRPC&#34;&gt;https://github.com/yeecode/EasyRPC&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;而且那段时间我在参与一些集群部署的项目。就是通过网站来完成应用的部署、升级、配置等工作，涉及到制品管理、质量管理等各个环节……表面呈现是一个网页，后面东西一大堆……&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;但是，我知道，那些都是纸老虎，没什么难的！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;毕竟，WEB开发没技术含量，能有什么难的。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;第四阶段理论探究行知结合&#34;&gt;第四阶段：理论探究、行知结合&lt;/h2&gt;&#xA;&lt;p&gt;并发挑战、容量挑战遇到的多了，我也学的多了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;功夫不负有心人，脑袋里终于成了一锅浆糊……&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;于是，我开始走上另一条路：&lt;strong&gt;理论研究&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我开始直接研究分布式理论，还包括相关的论文啊，都掏出来读一读……&lt;/p&gt;</description>
			</item>
			<item>
				<title>怎样成为全栈工程师（Full Stack Developer）？</title>
				<link>https://yeecode.top/blog/36/</link>
				<pubDate>Sun, 17 May 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/36/</guid>
				<description>&lt;p&gt;看到很多答案都是采用意淫大法，揣测全栈工程师是怎样的。&lt;/p&gt;&#xA;&lt;p&gt;当然，很多思路也都是对的。&lt;/p&gt;&#xA;&lt;p&gt;我就不采用意淫大法了，用自己的实际经历介绍下如何成为全栈工程师。并且介绍成长路上和成为全栈工程师之后要注意的事情。&lt;/p&gt;&#xA;&lt;p&gt;开始了，小板凳搬好。&lt;/p&gt;&#xA;&lt;p&gt;本回答一共分为下面几个部分：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1、Web前端&#xA;2、后端&#xA;3、客户端&#xA;----------小节&#xA;4、算法&#xA;5、运维与脚本&#xA;----------小节&#xA;6、其他可有可无&#xA;7、现在在干吗&#xA;8、最后也是最重要的一点&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;人没在美国，也没坐飞机。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;为了说明一切都是真实的，不是意淫的，我会配上作品图。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;作品会涉及到页面，如果有人说丑（尤其是我的页面设计部分，因为是真丑），请将其转化为点赞抒发出来！！！当做对我勇气的鼓励，谢谢。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-前端&#34;&gt;1、 前端&lt;/h2&gt;&#xA;&lt;p&gt;我是从前端入手开始编程的。不，确切说是页面设计。&lt;/p&gt;&#xA;&lt;p&gt;是的，我最开始接触互联网开发的身份是：页面设计师。就是设计和绘制网页。&lt;/p&gt;&#xA;&lt;p&gt;那时，我大一。&lt;/p&gt;&#xA;&lt;p&gt;一天，我有了一个想法：做一个校车查询系统。&lt;/p&gt;&#xA;&lt;p&gt;那时候，我们学校六七个小区包围了省会。做实验、或者进城等，校车成了最好的途径。然而，学校网站提供的校车是个表是一个表格……巨难使用！&lt;/p&gt;&#xA;&lt;p&gt;你想想，当你太阳底下背着书包，用Nokia 6300的小屏幕（2010年，有个Nokia 6300就不错了）一边心疼流量（10元10M？贵的很）进入学校网站，曲曲折折找到那个表格，多麻烦！&lt;/p&gt;&#xA;&lt;p&gt;于是，我要做一个校车查询应用。&lt;/p&gt;&#xA;&lt;p&gt;设计出来下面的图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/36/pic/001_hu_faad6b4a59301d12.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;579&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;然后，会PS只是第一步。前端开发我也会，三下五除二写出了前端页面。&lt;/p&gt;&#xA;&lt;p&gt;完美。&lt;/p&gt;&#xA;&lt;p&gt;但是还有一个问题，应用场景！&lt;/p&gt;&#xA;&lt;p&gt;用户在查询校车时，往往是在路上。10年左右，流量那么贵，让大家访问这么漂亮（额，漂亮么？十年前的审美真是奇怪呢！）的界面浪费流量，而且那时的手机一般屏幕小，使用起来不方便。&lt;/p&gt;&#xA;&lt;p&gt;所以，我用WAP协议（上古协议？）写了一个手机版的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/36/pic/002_hu_9c28cb9ee01377db.webp&#34; alt=&#34;图片&#34; width=&#34;650&#34; height=&#34;510&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;每次查询不到5k，四舍五入就是不需要流量。&lt;/p&gt;&#xA;&lt;p&gt;对了，后来我不做页面了，也不做前端了。因为我觉着我审美太差，不合适。而且审美这东西又很难通过努力弥补。&lt;/p&gt;&#xA;&lt;p&gt;所以，&lt;strong&gt;没必要真的完全全栈，每个人都有自己的短板&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2后端&#34;&gt;2、后端&lt;/h2&gt;&#xA;&lt;p&gt;光写了前端没有用啊，得有后端支持啊！&lt;/p&gt;&#xA;&lt;p&gt;不要怕，PHP是世界上最好的语言，世界上所有的网站都运行在Apache上。其他网站就不配叫网站！&lt;/p&gt;&#xA;&lt;p&gt;PHP大法好，学起来。&lt;/p&gt;&#xA;&lt;p&gt;于是后端就有了啊。&lt;/p&gt;&#xA;&lt;p&gt;然后我就把它挂到了学校网站的服务器上（我是网站技术部门的成员），然后发了个QQ空间装逼。&lt;/p&gt;&#xA;&lt;p&gt;然后，就被疯狂转发。&lt;/p&gt;&#xA;&lt;p&gt;历史最高访问几千独立访客每天。&lt;/p&gt;&#xA;&lt;p&gt;对的，我在里面加了CNZZ的访问统计代码。&lt;/p&gt;&#xA;&lt;p&gt;那几天，我那个激动啊！！！&lt;/p&gt;&#xA;&lt;p&gt;所以，到这里，至少前后端通了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;3客户端&#34;&gt;3、客户端&lt;/h2&gt;&#xA;&lt;p&gt;但是！万一用户5K都不想用呢？&lt;/p&gt;&#xA;&lt;p&gt;或者，网络不好呢？&lt;/p&gt;&#xA;&lt;p&gt;再说了，校车信息表一般是一个学期更新一次，直接下载下来，用户一直用多好啊。&lt;/p&gt;&#xA;&lt;p&gt;于是，搞个客户端。&lt;/p&gt;&#xA;&lt;p&gt;不会没关系，学啊。&lt;/p&gt;&#xA;&lt;p&gt;Android，搞起啊。&lt;/p&gt;&#xA;&lt;p&gt;于是有了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/36/pic/003_hu_3e43d85e5828c87b.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;325&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;它的优点是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用内置数据库存储信息，没有网络也能查询，有网络则会校验数据后判断是不是要更新&lt;/li&gt;&#xA;&lt;li&gt;根据GPS信息自动判断你的出发校区&lt;/li&gt;&#xA;&lt;li&gt;根据你的历史记录，自动判断你的目的校区&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当然，那些自动判断逻辑都很弱智的，没什么AI算法。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;小节&#34;&gt;小节&lt;/h2&gt;&#xA;&lt;p&gt;好，这个时候告一段落，我们总结下。&lt;/p&gt;&#xA;&lt;p&gt;其实，从前端到后端到客户端，我就在做一件事情：校车查询。就这一个最简单的事情，一直做。&lt;/p&gt;&#xA;&lt;p&gt;除了说到的这些，还有数据库、应用部署、访问统计、应用发布等等。只要盯着一件事情从头到尾做下来，都会涉及到。&lt;/p&gt;&#xA;&lt;p&gt;所以，如果要想成为全栈工程师，你可以选择一个有意义的事情，一直做。有以下几个好处：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;做一个实在的东西出来，有成就感。我看到QQ空间都在转发我的网页我就特别有成就感，有动力。&lt;/li&gt;&#xA;&lt;li&gt;有连贯性。前后都在做一个事情，你会意识到之前做的哪些地方可以改进，这样很有连贯性，利于进步。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;好了，接下来进入新的阶段。&lt;/p&gt;</description>
			</item>
			<item>
				<title>如何入门Python爬虫？</title>
				<link>https://yeecode.top/blog/35/</link>
				<pubDate>Sun, 19 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/35/</guid>
				<description>&lt;p&gt;今天我们就从&lt;strong&gt;最基本和最本质的途径去编写一个爬虫&lt;/strong&gt;，让大家真正&lt;strong&gt;了解爬虫的工作原理&lt;/strong&gt;。并且，能够&lt;strong&gt;在此基础上根据自身需求改造出需要的爬虫&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;绝对基础、绝对易懂、绝对能上手。如果看完还不会写，我给你表演100个俯卧撑！&lt;/p&gt;&#xA;&lt;p&gt;主要内容分为以下几个部分：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1、被爬取对象&#xA;2、当前对象的爬取&#xA;3、顺藤摸瓜的实现&#xA;4、取来即用的最简单框架&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;1被爬取对象&#34;&gt;1、被爬取对象&lt;/h2&gt;&#xA;&lt;p&gt;爬虫是在从网络上爬取内容，常见的爬取的内容由：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;网页本身&lt;/li&gt;&#xA;&lt;li&gt;网站接口给出的数据&lt;/li&gt;&#xA;&lt;li&gt;网站中的图片、视频等特定资源&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其中最基本最原始的就是爬取网页本身。如果我们会爬取网页，那接口的数据也会被带出来，特定的资源也可以被筛选出来。因此，我们以爬取网页为例进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;那我们先了解什么是网页。例如，下面就是一个网页的截图。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/001_hu_d6069a688f7fa239.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;832&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;那这个网页是怎样构成的呢？&lt;/p&gt;&#xA;&lt;p&gt;我们在网页上点击右键，选择“查看网页源代码”。&lt;/p&gt;&#xA;&lt;p&gt;就看到了下面的内容，乱糟糟的一片。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/002_hu_166571f52d326882.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;341&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;正是这乱糟糟的一片，经过浏览器渲染后，便成了眼前的页面。这东西就叫做网页源代码，是HTML文件。&lt;/p&gt;&#xA;&lt;p&gt;我们可以在其中找到很多的元素。&lt;/p&gt;&#xA;&lt;p&gt;例如，下面的是该网页的主旨，主要是给搜索引擎看的：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/003_hu_5ab4e7e49ca31392.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;132&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面这段则指向了一张图片的地址，渲染时浏览器会去下载和展示这张图片：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/004_hu_a381689a970e778f.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;196&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面这个则指向了一个后缀为css的文件。CSS文件是网页的样式文件，负责修饰网页上内容的样式（长宽高、间距、背景颜色等）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/005_hu_a6f18848aa3630b8.webp&#34; alt=&#34;图片&#34; width=&#34;831&#34; height=&#34;213&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面这个则指向了一个后缀为js的文件。JS文件即javascript文件，负责为网页提供一些动态的响应功能、逻辑处理功能。例如一些点击后的操作逻辑都是由它实现的：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/006_hu_ea0017d43c7bb258.webp&#34; alt=&#34;图片&#34; width=&#34;872&#34; height=&#34;207&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;还有非常重要的一部分，就是超链接。它指向了另外一个网页的地址。我们通过它，可以跳转到另外一个页面。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/007_hu_299c42f35b82f664.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;204&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;另外还有很多元素，都是界面上会显示的内容。&lt;/p&gt;&#xA;&lt;p&gt;可见，HTML文件很重要，它包含了：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;当前页面要显示的内容&lt;/li&gt;&#xA;&lt;li&gt;修饰当前页面样式的CSS文件的地址&lt;/li&gt;&#xA;&lt;li&gt;为当前页面提供逻辑处理功能的JS文件的地址&lt;/li&gt;&#xA;&lt;li&gt;当前页面中图片视频等资源的地址&lt;/li&gt;&#xA;&lt;li&gt;通过当前页面能够跳转到的其他页面的地址&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;可见它十分重要。&lt;/p&gt;&#xA;&lt;p&gt;浏览器在工作时就是先下载指定地址的HTML文件，然后再根据HTML文件中给出的CSS、JS等资源连接去下载相关资源。可见，HTML文件是核心。&lt;/p&gt;&#xA;&lt;p&gt;而一个网页的组成部分我们也理清楚了，如下图所示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/35/pic/web_hu_6489ec69144981a9.webp&#34; alt=&#34;图片&#34; width=&#34;494&#34; height=&#34;186&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们在爬取时，会根据不同部分进行不同处理：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;HTML文件：因为其中包含有网页上要显示的内容，因此这是爬虫爬取的重点内容。&lt;/li&gt;&#xA;&lt;li&gt;CSS文件：用来修饰样式，一般没什么具体信息，不去爬取&lt;/li&gt;&#xA;&lt;li&gt;Javascript：也没什么信息，不去爬取&lt;/li&gt;&#xA;&lt;li&gt;图片、视频等：如果我们是爬文字，则忽略他们。如果我们想专门爬取图片，则要爬取这些内容。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;好，对被爬取对象的分析就到这里。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2当前对象的爬取&#34;&gt;2、当前对象的爬取&lt;/h2&gt;&#xA;&lt;p&gt;假如我们已经有了某个页面的地址，怎么爬取其中的内容呢？&lt;/p&gt;&#xA;&lt;p&gt;其实很简单，我们将Python程序伪装为一个浏览器，向网站请求数据。那网站自然就会将HTML信息发送给我们。我们可以将其保存在一个文本文件中。&lt;/p&gt;&#xA;&lt;p&gt;下面的代码就可以实现。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;htmlFile=open(&amp;#39;./output/&amp;#39;+(str(pageId)+&amp;#39;.txt&amp;#39;),&amp;#39;w&amp;#39;)&#xA;htmlFile.write(urllib.urlopen(url).read())&#xA;htmlFile.close()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;是不是很简单！&lt;/p&gt;&#xA;&lt;h2 id=&#34;3顺藤摸瓜的实现&#34;&gt;3、顺藤摸瓜的实现&lt;/h2&gt;&#xA;&lt;p&gt;爬虫，有一个重要的点是“爬”。能顺藤摸瓜地爬到下一个地方，继续下载。怎么实现？&lt;/p&gt;&#xA;&lt;p&gt;还记得么，我们已经在第二步中下载了当前页面的HTML文件。而在第一步中我们说过，HTML文件中有到其他页面的链接！&lt;/p&gt;&#xA;&lt;p&gt;那我们要做的就是将这些到其他页面的链接找出来，然后到对应的页面下载相关内容。简单！&lt;/p&gt;&#xA;&lt;p&gt;怎么找出来呢？正则表达式！简单来说，就是按照一定的格式在文本中寻找。&lt;/p&gt;&#xA;&lt;p&gt;在HTML文件中，指向其它网页的地址是放在”href=“后面的，而且我们也说过，网页的地址一定不是css、js等结尾的文件，也不是图片（ico、jpg等结尾的就是图片）。&lt;/p&gt;&#xA;&lt;p&gt;所以，我们可以粗略地使用下面的表达式将链接过滤出来。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;pattern=re.compile(&amp;#39;href=&amp;#34;[^(javascript)]\S*[^(#)(css)(js)(ico)]\&amp;#34;&amp;#39;)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后我们就可以将过滤出来的链接内容下载下来（即再次执行第二步），然后继续分析（再次执行第三步）……然后一直爬呀爬……&lt;/p&gt;&#xA;&lt;p&gt;这时我们可以增加一些新的规则，例如，不仅仅下载HTML文件，顺便现在其中的图片等。做到爬图功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;4整体流程&#34;&gt;4、整体流程&lt;/h2&gt;&#xA;&lt;p&gt;好了，爬虫已经不难了。&lt;/p&gt;&#xA;&lt;p&gt;简单来说就是下面的步骤：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;爬取函数（a）&#xA;  下载网页a的内容&#xA;  分析网页a中的链接，对得到的每一个链接b调用  爬取函数（b）&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然，这个过程中也要处理一些小的细节。例如：&lt;/p&gt;</description>
			</item>
			<item>
				<title>WEB前端是不是没有前景了？</title>
				<link>https://yeecode.top/blog/34/</link>
				<pubDate>Sun, 12 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/34/</guid>
				<description>&lt;p&gt;我最开始接触前端开发是在十年前，然后还带出了一个前端团队。&lt;/p&gt;&#xA;&lt;p&gt;到现在，也一直关注前端的进展。&lt;/p&gt;&#xA;&lt;p&gt;可即使这样，我也&lt;strong&gt;无法给出前景好坏的明确回答&lt;/strong&gt;。也绝不能为了骗赞，乱答一个。&lt;/p&gt;&#xA;&lt;p&gt;接下来我会从&lt;strong&gt;软件宏观发展&lt;/strong&gt;和&lt;strong&gt;前端自身发展&lt;/strong&gt;两个角度分析前端的前景。具体结论，还希望读者自行总结。&lt;/p&gt;&#xA;&lt;p&gt;当然，我会在最后给出一些建议。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;    &lt;p&gt;还要说明一下，本回答说的前端是指大前端，不仅仅包括Web前端，也包括客户端、H5、几近消亡的Flash等等。它们只是所处的硬件载体不同。并且按照趋势，他们将来也会被统一起来，例如，现在HTML已经可以在大多数载体上运行。&lt;/p&gt;&#xA;&#xA;  &lt;/blockquote&gt;&lt;h2 id=&#34;软件宏观发展&#34;&gt;软件宏观发展&lt;/h2&gt;&#xA;&lt;p&gt;同许多行业一样，软件行业的发展也在经历一个从&lt;strong&gt;功能到体验&lt;/strong&gt;的过程。&lt;/p&gt;&#xA;&lt;p&gt;早期的软件编程主要指完成功能，至于表现形式则并不重要。在那个时代中，命令行是最常见的交互形式，简单、明确。当然，主要是简单。&lt;/p&gt;&#xA;&lt;p&gt;甚至，在二十年前，网游还是文字版本的呢。&lt;/p&gt;&#xA;&lt;p&gt;“你对对方发起了普通攻击，对方血量-5%！”&lt;/p&gt;&#xA;&lt;p&gt;结果那时照样玩的很嗨！&lt;/p&gt;&#xA;&lt;p&gt;渐渐地，核心需求被满足了，软件开始面向大众。&lt;strong&gt;对于大众而已，复杂的功能他们感受不到，漂亮的界面他们却可以感受到&lt;/strong&gt;。于是软件便开始追求体验，这是前端才诞生，并开始发展。&lt;/p&gt;&#xA;&lt;p&gt;早期的界面也是丑的可怜，以表达信息为主。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/34/pic/001_hu_854963e83a70faaa.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;529&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而后，早期的客户也被收割完毕。只有更好的体验才能吸引更多的用户，&lt;strong&gt;体验变得越来越重要，前端也变得越来越重要&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;美观上。从文字到图片到视频。&lt;/p&gt;&#xA;&lt;p&gt;载体上。从电脑到手机，甚至到手表。&lt;/p&gt;&#xA;&lt;p&gt;用户在哪里，界面就出现在哪里。&lt;/p&gt;&#xA;&lt;p&gt;于是渐渐地，功能倒没那么重要，前端带来的体验才最重要。说个大家都知道的例子：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;a href=&amp;#34;javascript: alert(&amp;#34;缓存清除成功!&amp;#34;)&amp;#34; &amp;gt;清空缓存&amp;lt;/a&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要啥功能啊，只要用户觉着爽就好了！&lt;/p&gt;&#xA;&lt;p&gt;而这个趋势，会一直发展下去。其实，我们近些年常提的供给侧改革也是由于这样的原因产生的。&lt;strong&gt;即随着行业的发展，其相关需求基本被满足后，行业的重心会从功能转为体验&lt;/strong&gt;。这个过程中，得用户者得未来。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;从软件宏观发展分析，前端就是软件系统最贴近用户的部分。大有未来！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;前端自身发展&#34;&gt;前端自身发展&lt;/h2&gt;&#xA;&lt;p&gt;在09年左右，我刚开始做前端时，常戏称自己是“切图工”。很大一部分工作就是在切图……然后更大的工作比重在调试配。&lt;/p&gt;&#xA;&lt;p&gt;IE6\IE7\IE8\搜狗浏览器\360浏览器\傲游浏览器……那是一个浏览器遍地开花的时代。每个浏览器对标准的支持不同，适配起来难度极大。尤其是IE6，经历过的前端们应该还能回想起那时的痛苦。&lt;/p&gt;&#xA;&lt;p&gt;但是要说前端的自身发展，还要从更早说起。在JavaScript诞生的年代，那时，前端语言都没有统一。&lt;/p&gt;&#xA;&lt;p&gt;所以，前端的发展&lt;strong&gt;本可以&lt;/strong&gt;用下面的图表示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/34/pic/002_hu_2ce2dc86b0e92da3.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;152&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;首先，&lt;strong&gt;实现规范的统一&lt;/strong&gt;。这一点上，前端做的非常好，比后端好很多。&lt;/p&gt;&#xA;&lt;p&gt;后端什么Restful、微服务之类，也都只是停留在概念层次，然后以尚不清晰的概念去指导后端发展。（你不信啊，随便拽几个后端的人出来，对这些概念，每个人都有每个人的理解，还特有理！）但是前段的主体可是W3C制定的准确的规范。&lt;/p&gt;&#xA;&lt;p&gt;可见，W3C具有很强的掌控能力，也具有极佳的技术引导力。牛逼！&lt;/p&gt;&#xA;&lt;p&gt;然后，&lt;strong&gt;就是框架的统一&lt;/strong&gt;。本来，这一点可以在十年以内迅速完成，然后形成一套最为大众和成熟的框架。就像后端的Spring框架一样，慢慢地成为共识。&lt;/p&gt;&#xA;&lt;p&gt;但是，还没来得及完成，就受到了硬件高速发展的冲击。成了下面的图。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/34/pic/002_hu_2ce2dc86b0e92da3.webp&#34; alt=&#34;图片&#34; width=&#34;900&#34; height=&#34;152&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;PC端、手机浏览器、Android客户端、IOS客户端……众多的客户端瞬间袭来，也在各自的领域孕育了自己的框架。然后，任何一个框架，可能在某些领域表现的好，在某些领域表现的不好……框架的优劣变得难以比较，统一的过程也便被拉长。&lt;/p&gt;&#xA;&lt;p&gt;当然，框架的统一过程也在进行中，例如，ActionScript不就消失了么（心痛，我第一个学的语言实际是ActionScript），JQuery不也渐渐远去了么。现在，Angular\Vue\React等等众多框架开始争斗中，当然，也渐渐有了优劣之分（我不做一家之言的判断，留给大家自己判断）。重点，这就是现在的形势。&lt;/p&gt;&#xA;&lt;p&gt;然后，在经过足够长的时间。前端的框架还是会统一起来。用一套框架编写各个端的界面，这绝对是趋势。例如，Electron就很好啊。&lt;/p&gt;&#xA;&lt;p&gt;等框架统一结束后，也会有新的客户端类型产生。但是那时的新客户端也会使用统一后的规范和框架进行编程，毕竟开发者在那里。&lt;/p&gt;&#xA;&lt;p&gt;一个框架，一份代码，多端运行，自然不需要太多的前端开发者。&lt;strong&gt;因此，从前端自身发展分析，前端会渐渐实现统一。这个过程中，需要的从业者是减少的。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;&#xA;&lt;p&gt;汇总一下上面的两点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;从软件宏观发展分析，前端就是软件系统最贴近用户的部分。大有未来！&lt;/li&gt;&#xA;&lt;li&gt;从前端自身发展分析，前端会渐渐实现统一。这个过程中，需要的从业者是减少的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;宏观和微观的结论是相悖的，所以，我不能给出确切的结论&lt;/strong&gt;。接下来前端的从业者人数会怎样，会兴起还是衰落，很难说。&lt;/p&gt;&#xA;&lt;p&gt;但是，我们现在处在框架争斗合并的过程中，可以得出几点建议：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;前端开发&lt;strong&gt;一定要选好框架，站好队！如果有一天，你选择的框架失势了，那你掌握的技能毫无价值！而如果你选择的框架得势了，你将成为行业专家&lt;/strong&gt;。这一点十分重要。因此，选框架时一定要根据当&lt;strong&gt;前开发活跃度（汇总国内外，别只看国内）、框架支持方实力、发展趋势、优势劣势&lt;/strong&gt;等综合判断。再说一遍，非常重要。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;善于学习新技术&lt;/strong&gt;。如果你觉着你无法一下就选中未来的框架，那就多学。出现新的框架，多看看，多试试。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;发现哪个框架有未来之后，深入学习&lt;/strong&gt;！因为框架的大一统结束后，&amp;ldquo;一份代码多端运行&amp;quot;是必然。那会导致前端开发者需求的减少。深入学习，成为行业大牛不仅不会让你失业，还会让你大有前途。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;最后，在前端框架迭起的现在。学习前端实属不易。&lt;/p&gt;&#xA;&lt;p&gt;加油！&lt;/p&gt;</description>
			</item>
			<item>
				<title>作为一名程序员，最大的成就感来自哪里？</title>
				<link>https://yeecode.top/blog/32/</link>
				<pubDate>Sun, 08 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/32/</guid>
				<description>&lt;p&gt;如果你还没有入门编程就不要阅读本文了。&lt;strong&gt;否则读完会让你爱上编程不能自拔&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;那麻烦可就大了！！！&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;事情发生在10年前。我那时读大二，风华正茂，正在忙着发誓。&lt;/p&gt;&#xA;&lt;p&gt;我发誓——&lt;strong&gt;再也不能丢U盘了！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这已经是我丢的第二个U盘了。&lt;/p&gt;&#xA;&lt;p&gt;U盘里有我课程课件、从同学那拷贝来的考试题库、一些没啥用的代码、几个软件安装包，还有最重要的，一些来自岛国的室内动作电影。那些电影被我放在了一个隐藏的分区中，曾陪伴我度过很多安静的夜，它们的存在使得这个U盘意义更为重大。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/001_hu_4755eb5a8676b00d.webp&#34; alt=&#34;图片&#34; width=&#34;255&#34; height=&#34;255&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;然而，所有的一切都丢了。&lt;/p&gt;&#xA;&lt;p&gt;我等了三天，不见有人还。于是我开始从怨恨自己的粗心变为怨恨捡到U盘人的素质低下。&lt;/p&gt;&#xA;&lt;p&gt;再一再二不再三，&lt;strong&gt;我不允许自己再丢U盘了&lt;/strong&gt;。这关系到我心爱的电影和一个&lt;strong&gt;编程爱好者的尊严&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;我有全校同学的学号信息，对应每个人的姓名、学院、专业，甚至每个人的高考考号。得到这些信息并不难，且合理合法，毕竟学校某些部门的隐私意识啊，真是一言难尽。&lt;/p&gt;&#xA;&lt;p&gt;嘿嘿，真棒！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/002_hu_c831244c6eee178c.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;459&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;如果我再丢U盘，一定从名单中把捡到我U盘的人找出来。&lt;/p&gt;&#xA;&lt;p&gt;很难，因为我并不知道U盘离我而去之后，&lt;strong&gt;插在了谁的电脑上&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;但并不是不可能，因为学校的IP是固定分配的，和每个人的学号绑定。只要知道U盘所在电脑的IP，就还有希望。&lt;/p&gt;&#xA;&lt;p&gt;我需要得到学校所有人的&lt;strong&gt;IP地址和学号的对应关系表&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我成功了，过程就不详述了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/003_hu_6924698810216e1b.webp&#34; alt=&#34;图片&#34; width=&#34;255&#34; height=&#34;255&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;接下来要做的就明确了：&lt;strong&gt;我需要U盘自动告诉我它现在所处的电脑的IP地址&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我要编程，让我的U盘具有找回功能——现在的年轻人可以参照自己iphone的找回功能。&lt;/p&gt;&#xA;&lt;p&gt;是的，两者的功能几乎一样，&lt;strong&gt;有理由怀疑，苹果可能抄袭我&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;于是我打开了Visual Basic——现在的年轻人可能不熟悉，这是一个上古编程语言，配有一个高贵前卫的编辑器。就像下面这样，高贵吧，前卫吧！&lt;/p&gt;&#xA;&lt;p&gt;别抱怨，那是你自己审美不行！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/004_hu_75e8370b41ae8f24.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;513&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在前卫的编辑器前，我写下了第一个功能模块，它能获取U盘所在电脑的IP。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/005_hu_429cae0b56cf64f7.webp&#34; alt=&#34;图片&#34; width=&#34;537&#34; height=&#34;76&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;然后，我需要程序能够将&lt;strong&gt;读取到的IP发送给我&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;最简单的方法是在服务器上暴露一个接口，让U盘找回软件把IP信息发送到接口。&lt;/p&gt;&#xA;&lt;p&gt;而我，确实掌握着学校网站和多个学院网站的服务器（正规且合法，我是学校多个网站的开发者维护者）。但是，权利越大，责任越大，我受过的教育不允许我利用公家的服务器做私事。&lt;/p&gt;&#xA;&lt;p&gt;我想到了邮箱。免费的邮箱干嘛不用。于是我申请了一个专门的邮箱用来发送信息。就通过下面的代码。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/006_hu_5db25344670c491c.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;333&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这样，当U盘插到电脑上时，它会自动通过这个邮箱给我发送一个邮件，邮件中包含了当前电脑的IP地址。&lt;/p&gt;&#xA;&lt;p&gt;当然，我也不想U盘每次被插上电脑就给我的邮箱发邮件，这不成了给自己制造垃圾邮件。于是，我申请了一个专门的邮箱来接收这个邮件。&lt;/p&gt;&#xA;&lt;p&gt;最终，我使用上古神器编译出来了一个上古运行软件——U盘找回软件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/007_hu_f09614a9d7a61563.webp&#34; alt=&#34;图片&#34; width=&#34;690&#34; height=&#34;225&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;看看文件后面的修改日期，这足以证明它们诞生在我青葱帅气的年代。&lt;/p&gt;&#xA;&lt;p&gt;别问我那些奇怪的后缀名都是什么文件类型，我都忘了！！&lt;/p&gt;&#xA;&lt;p&gt;这些古董语言编译出来的古董程序，我现在那还认识啊！！！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/008_hu_4cee5ff3ecf001a3.webp&#34; alt=&#34;图片&#34; width=&#34;250&#34; height=&#34;261&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;接下来，还有重要的事情要做——&lt;strong&gt;让找回软件在U盘插入电脑后自动运行&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这一步的设置不难，只要新建一个txt文本文档输入下面内容保存为autorun.inf文件 放到U盘中即可。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; [autorun]&#xA;open=U盘找回程序.exe&#xA;icon=UDiskFinder.ico&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但是，这样的假设太过理想。谁能保证捡到U盘的人是不是安装了什么毫无卵用但是又能阻止我好事的杀毒软件呢。&lt;/p&gt;&#xA;&lt;p&gt;杀毒软件可是会阻止U盘中的软件自动运行。&lt;/p&gt;&#xA;&lt;p&gt;于是，这个软件要伪装！&lt;/p&gt;&#xA;&lt;p&gt;**杀毒软件能防病毒，但是不能防脑残。**如果电脑主人想要作，杀毒软件可是拦不住的。&lt;/p&gt;&#xA;&lt;p&gt;于是，我把改了软件的名称——U盘解压软件。然后再放入一个起着诱人名字的加密压缩包——“隐私文件”，平时存放文件时都加密压缩有放入U盘。&lt;/p&gt;&#xA;&lt;p&gt;我还给它设计了一个图标。看它的图标，谁不认为这是一个解压软件？？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/009_hu_5eb5f5321098ea19.webp&#34; alt=&#34;图片&#34; width=&#34;500&#34; height=&#34;300&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而它的界面，也是难辨真假！&lt;/p&gt;&#xA;&lt;p&gt;请忽略左下角的logo，那是我曾经的网名。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/010_hu_4069b18d4d9724ee.webp&#34; alt=&#34;图片&#34; width=&#34;493&#34; height=&#34;351&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;甚至点开“说明”还有解压操作提示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/011_hu_90282ea0950de44f.webp&#34; alt=&#34;图片&#34; width=&#34;495&#34; height=&#34;354&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;点开“关于”还能看到软件信息：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/32/pic/012_hu_f6f05a1d64bd617d.webp&#34; alt=&#34;图片&#34; width=&#34;495&#34; height=&#34;353&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;毫无破绽，毫无破绽！&lt;/p&gt;&#xA;&lt;p&gt;而整个界面，都是用来麻痹敌人的伪装！&lt;/p&gt;&#xA;&lt;p&gt;它的唯一功能，就是把当前IP发送给我的邮箱！！！！&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;这样的伪装，参透了人性！！！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;可以设想这么一幕：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;小木捡到了U盘，回到了宿舍&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;好奇心驱使下，小木把U盘插入了电脑&lt;/li&gt;&#xA;&lt;li&gt;U盘找回软件自动给我发送了小木的IP。如果有杀毒软件，那这步计划取消，执行下一步。&lt;/li&gt;&#xA;&lt;li&gt;小木看到了U盘中多个压缩包，名字实在诱人。可是却不知如何打开。于是点击了“U盘解压软件”。&lt;/li&gt;&#xA;&lt;li&gt;软件将小木的IP地址发送到了我的邮箱。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;于是，知道IP，我就找到学号；知道学号，我就能知道学院、专业、姓名；通过我广阔的人脉打听打听，我就能找到宿舍。&lt;/p&gt;</description>
			</item>
			<item>
				<title>为什么大学老师教编程上课都不敲代码?</title>
				<link>https://yeecode.top/blog/37/</link>
				<pubDate>Sun, 16 Feb 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/37/</guid>
				<description>&lt;p&gt;如果你的大学老师上课不敲代码，那他并不一定是一个坏老师。当然，也有可能是。说不定他编程水平真的很烂。&lt;strong&gt;说不定，还是一个极好的老师&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;来，我们细细分析。&lt;/p&gt;&#xA;&lt;p&gt;我的分析将会按照下面的结构展开：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;一、  软件开发的层级划分&#xA;二、  技（技术）&#xA;三、  术（架构）&#xA;四、  道（理念）&#xA;五、  老师要不要写代码&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;一-软件开发的层级划分&#34;&gt;一、 软件开发的层级划分&lt;/h2&gt;&#xA;&lt;p&gt;软件开发是一个庞大的系统。我们可以类比传统工程设计领域的概念，将软件系统领域的研究由上到下地分为三层：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;理念层面：研究软件系统开发中的理念和思想，例如研究软件的开发模型、评价指标、架构风格等。类比于传统工程领域研究建筑质量标准、研究商业区与居住区的分布关系等。&lt;/li&gt;&#xA;&lt;li&gt;架构层面：研究如何协调和组织软件系统、子系统、模块之间的关系，从而指导系统实现并提升各类质量指标。类比于规划和设计建筑物的承重结构、功能结构等，并协调各结构的关系等。&lt;/li&gt;&#xA;&lt;li&gt;技术层面：研究如何高效、可靠、经济地实现软件系统、子系统、模块等。类比于搭建建筑物中的楼梯、墙体、阳台等。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以上三个层面，&lt;strong&gt;层次逐渐降低，且上层为下层提供指导、下层为上层提供基础&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;来，让我用并不优美的笔触做个板书，如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/37/pic/001_hu_51f22839a0618d2e.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;399&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这其实就是我们常说的&lt;strong&gt;道&lt;/strong&gt;、&lt;strong&gt;术&lt;/strong&gt;、&lt;strong&gt;技&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;接下来我们分别讨论三个层级。&lt;/p&gt;&#xA;&lt;h2 id=&#34;二-技技术&#34;&gt;二、 技（技术）&lt;/h2&gt;&#xA;&lt;p&gt;对于“技”这一层级，我们平时接触到的最多。在学生阶段，说一个人是大牛也多指其“技”高一筹。而且，技是上面各个层级的基础。&lt;/p&gt;&#xA;&lt;p&gt;这一层级有以下几个特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;上手快：学习一门编程语言是不难的，尤其是你掌握几门之后，再去掌握一门新语言，那是很轻松的事情。&lt;/li&gt;&#xA;&lt;li&gt;基础依赖少：无需太多其他基础就可以。这就是为什么培训班爆发，培训班里培训的都是“技”。如果真要说基础，可能就英文不要太差吧。例如变量命名param最好不要写成canshu。&lt;/li&gt;&#xA;&lt;li&gt;面很广：技术层面包含的语言十分众多，例如Java\C++\C#\Python\Lua\PHP\JavaScript\Shell……数不胜数。因此，这里的知识面极为广。&lt;/li&gt;&#xA;&lt;li&gt;实在：指的是会就是会，不会就是不会，糊弄不了人。你看谁吹厉害了，就让他手写个代码出来，一下就露馅。&lt;/li&gt;&#xA;&lt;li&gt;受重视：因为它实在，不虚，所以大家会拼命提升这方面的能力。因此大受重视，无论是高校学生、程序员、培训班……因为面试多会考察它，不重视不行。&#xA;一般情况在学生阶段和工作几年的程序员就处于提升“技”的阶段，可以认为是“技”崇拜阶段。谁的“技”高一筹谁就是大牛，毋庸置疑。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;三-术架构&#34;&gt;三、 术（架构）&lt;/h2&gt;&#xA;&lt;p&gt;这一层级大家接触的相对少一些，尤其是学生可能接触不到。工作几年后的软件开发者会接触到这些，但也不会太多。毕竟，相对于开发者而言，成为架构师的总是少数。&lt;/p&gt;&#xA;&lt;p&gt;这一层级有以下几个特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;需要技术基础：“技”是“术”的基础，毋庸置疑。因为“术”本身就是为了指导“技”而产生的。如果连被指导的对象都不了解，那还扯个啥啊？&lt;/li&gt;&#xA;&lt;li&gt;需要理论知识：纯技术的积累已经不能够胜任架构工作，必须了解相关的理论知识。这些理论包括纯理论、也有一些实践经验。&lt;/li&gt;&#xA;&lt;li&gt;相对虚：因为不是直接的写代码，因此相对虚一些，容易出现水货，不太容易考察。但也不是完全不能考察。&lt;/li&gt;&#xA;&lt;li&gt;面更广：所需要的知识面更广。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;有必要再说一下相对虚和需要技术基础这两点。几年前听说某个创业公司的CTO作为首席架构师，竟然不会写代码，还将其作为自己的特色。这种，绝对水货，都不会写代码你架构啥啊，最终东西怎么实施的自己都搞不清楚，那哪是架构啊，坑人啊。&lt;/p&gt;&#xA;&lt;p&gt;如果感觉一个人侃侃而谈“术”，想考察他是不是真本事，而又没时间让他架构个实在的项目。那就让他写代码！**一个优秀的“术人”（架构师），必定是一个卓越的码农！**或许细节只是有些淡忘，但是，在编辑器的提示下，代码能力比大多数程序员厉害才对。&lt;/p&gt;&#xA;&lt;h2 id=&#34;四-道理念&#34;&gt;四、 道（理念）&lt;/h2&gt;&#xA;&lt;p&gt;谈到这一块，我接触的也比较少了，还触及不到。谁让我科研阶段也是偏实践的方向呢。当然，真正做这方面研究的人确实少，而且都是赫赫有名的大牛。&lt;/p&gt;&#xA;&lt;p&gt;这一块的内容主要以论文或者会议演讲的形式对外输出。例如，哪个大神又写了什么牛逼的论文（说到这我怎么总是想起谷歌这个大神级公司），或者又在某个会议上提出了新的思路。&lt;/p&gt;&#xA;&lt;p&gt;这一层级提出的思想往往会在两年左右落实到“术”上，进而影响整个软件领域的发展。&lt;/p&gt;&#xA;&lt;h2 id=&#34;五-老师要不要写代码&#34;&gt;五、 老师要不要写代码&lt;/h2&gt;&#xA;&lt;p&gt;讨论完“技”“术”“道”，我们再来回答这个问题。&lt;/p&gt;&#xA;&lt;p&gt;我们知道，大学里有很多代码课，例如Java\C等等。但是，&lt;strong&gt;大学这些课程本质上是在教你“技”“术”“道”的结合，而不是“技”本身&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;因为，“技”很简单，你下课自己看看书就能学会。作为一个大学生，真的不难。&lt;/p&gt;&#xA;&lt;p&gt;也因为，“技”涉及的面很广，各种语言Java\C++\C#\Python\Lua\PHP\JavaScript\Shell……所以，老师PPT上第15页第4行代码最后面是不是少了一个分号真的不重要。&lt;/p&gt;&#xA;&lt;p&gt;以Java为例，上课老师天天写代码，也顶多只能教会你“技术”层级的“Java”中的橙色的那一小块知识。（而且我觉着我画的太大了……毕竟板书能力有限。）&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/37/pic/002_hu_77fadeebd681dbf.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;397&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而等你工作的时候，可能进入了腾讯，然后用的是C++。&lt;strong&gt;那橙色小块的知识迁移性太差了，对你的工作用处不大&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;因此，&lt;strong&gt;老师极力要教会你的，是蓝色的竖线：“技”“术”“道”的结合&lt;/strong&gt;。在这个目的下，老师写不写代码，不重要。甚至，写代码都有些浪费课堂时间。&lt;/p&gt;&#xA;&lt;p&gt;当然，还有一个原因。老师教授的目的是“技”“术”“道”的结合，因此，可能“技”的能力不是太高。学生中可能有技高一筹的人。那老师写段代码如果出点问题，脸面也不好放啊。毕竟处在“技”崇拜阶段的学生，不太会感知到老师“术”“道”的高超。所以，有时候，不出手，更保险。&lt;/p&gt;&#xA;&lt;p&gt;当然，以上我说的是高校。如果你参加了一个Java的培训班，就是来学“技”的，结果老师一行代码都不写，和你扯写高层级的乱七八糟，不用怀疑。那人不会写代码，退钱，走人。&lt;/p&gt;&#xA;&lt;p&gt;好了，就讲这么多。&lt;/p&gt;&#xA;&lt;p&gt;希望大家以更高的视角来看大学老师的授课，来看软件开发这一领域。&lt;/p&gt;</description>
			</item>
			<item>
				<title>你的编程能力从什么时候开始突飞猛进？</title>
				<link>https://yeecode.top/blog/41/</link>
				<pubDate>Sun, 26 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/41/</guid>
				<description>&lt;p&gt;首先我们要明白一个道理：&lt;strong&gt;编程没有什么特殊的，它是&amp;quot;科学技术-&amp;gt;技术-&amp;gt;工程技术&amp;quot;中的一个小的类别。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;明白了这一点，如何提升编程能力便变得显而易见了。因为，**关于学习科学和技术，我们经历过十几二十年的训练。**而且，这一训练是极有成效的（相比于国外的一些欢乐的训练方法，这里仅作提及，不展开争论）。&lt;/p&gt;&#xA;&lt;p&gt;这时你可以回顾自己学习某一门课时，在什么时候有突飞猛进的感觉。&lt;/p&gt;&#xA;&lt;p&gt;主要有两个阶段：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;初学阶段&lt;/strong&gt;。对，就是上课听讲。这时我们通过课本学习基本的知识，经历从无到有的质的变化，每天都能学到大量的新知识，进步神速。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;训练阶段&lt;/strong&gt;。对，就是课后练习、以考代练。这时我们主要是通过做题，或者工程实训，将学到的基本知识用到实践中，并不断地反馈纠正自身的知识，最终建立知识体系和经验。这时你会常常有恍然大悟和醍醐灌顶的感觉，“原来这定理这么用，妙啊！”&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;而其他的一些复习阶段、熟练阶段，则进步较小。常常许久感觉不到什么进步。&lt;/p&gt;&#xA;&lt;p&gt;反映到编程上，也是一样的。一个人编程能力突飞猛进的阶段主要有两个：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;学习基本编程知识、环境&lt;/strong&gt;。这一阶段是一个纯粹学习的过程，例如你在学习一门编程语言的语法，或者在学习一种算法。这个阶段重在学习的知识是正确的、成体系的。这点是容易实现的，只要确保自己使用了正规的业界认可的教科书，而不是什么《二十一天学会XXX》之流，应该问题不大。这个阶段你自己也能感受到自己的进步。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;不断训练纠正提升&lt;/strong&gt;。这一阶段又可以拆分为两部分：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;第一部分：&lt;strong&gt;不断训练&lt;/strong&gt;。相信这一点很容易实现，毕竟有很多程序员都昼夜兼程，急速狂奔，把头发都甩在脑后了。相信这个训练量是足够的。&lt;/li&gt;&#xA;&lt;li&gt;第二部分：&lt;strong&gt;收集反馈，不断改进&lt;/strong&gt;。这一点对于许多程序员而言是极为欠缺的。**试想，你做完哪个项目后，会有专家告诉你哪个地方设计的不好，更好的设计方案是什么；你写完哪段代码后，会有大神告诉你最好是怎么写，可以获得哪些提升。**以上的这些机会是进步的机会，但是，我相信是极少的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以，&lt;strong&gt;程序员进行了大量的编程作业，却没法收集到足够的反馈。&lt;strong&gt;这就像写完了作业，考完了试，但是没人老师给你批改，也没人告诉你正确答案。那你是很难进步的，因为&lt;/strong&gt;你不知道自己做的对不对！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;于是只能在莽撞的试错中前进，这就是成长缓慢的原因。&lt;/p&gt;&#xA;&lt;p&gt;然而，各种原因，例如“教会徒弟饿死师傅”等，外加码农领域本来就是“年轻更吃香，年老被裁员”，所以，想获得前人的反馈难上加难。&lt;/p&gt;&#xA;&lt;p&gt;但是，有一种反馈是存在的，或者，&lt;strong&gt;有一种标准答案可以被你拿来作为反馈&lt;/strong&gt;。这种答案极为标准，比你周围大神写出的代码还要优秀！&lt;/p&gt;&#xA;&lt;p&gt;对的，我说的是开源项目的源码。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;优秀开源项目的源码经过了几千人的上万次修改，极为经典。这是极好的“标准答案”，就和课后习题的标准答案一样。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;你要用这些优秀的开源源码作为答案去校准自己写的代码：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;源码的包是如何划分的，你是怎么划分的？&lt;/li&gt;&#xA;&lt;li&gt;源码的类是怎么定义的，你是怎么定义的？&lt;/li&gt;&#xA;&lt;li&gt;源码的分支是如何拆分的，你是怎么拆分的？&lt;/li&gt;&#xA;&lt;li&gt;源码的架构是怎么规划的，你是怎么规划的？&lt;/li&gt;&#xA;&lt;li&gt;源码的异常是怎么处理的，你是怎么处理的？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当你阅读源码时，你会不自觉地和自己的代码对比。在这个过程中，你就进步了。&lt;/p&gt;&#xA;&lt;p&gt;好了，&lt;strong&gt;除了“学习基本编程知识、环境”外，另一个让自己编程能力突飞猛进的途径你已经知道了——阅读和学习优秀开源源码&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;或许，&lt;strong&gt;你早就知道了&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;只是，你难以坚持去读一份源码。&lt;/p&gt;&#xA;&lt;p&gt;因为很难！真的很难。&lt;/p&gt;&#xA;&lt;p&gt;一下面对那么多的代码，一团乱麻。&lt;/p&gt;&#xA;&lt;p&gt;我曾经也站在这困难之前。&lt;/p&gt;&#xA;&lt;p&gt;那时我已经是一名高级架构师，做过网站的技术负责人，也规划实现过很多系统。然后内心一直想知道自己的架构设计、编程实现和世界上最优良的架构设计、编程实现之间的距离有多大！&lt;/p&gt;&#xA;&lt;p&gt;可是我知道，&lt;strong&gt;除了读源码，我找不到其他进步的路线了&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;于是我开始沉下心来，一个包一个包的拆解、一个类一个类的阅读、一行一行的分析。&lt;/p&gt;&#xA;&lt;p&gt;最终，我收获极大，真的极大！&lt;/p&gt;&#xA;&lt;p&gt;然后也总结了很多源码阅读的技巧、经验。&lt;/p&gt;&#xA;&lt;p&gt;而后，出版社找到了我。之后我将这些经验技巧，都被汇聚成了一本书：&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;p=JF8BAMYJK1olXDYCV1ZeCU4UCl9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksUC2wJHlgcQl9HCANtb1FqVSleXj1wFXRcAC4CXAlkWTFyXVcZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCkMTBGcBGVkWXzYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAKDRtHUTgNHF4VVVMHAV5YAEhAAWsLHFkXCQEDXVcOXXsVAm4MEms&#34;&gt;&lt;img src=&#34;https://yeecode.top/img/promo/mb.jpg&#34; width=&#34;450&#34; height=&#34;348&#34; loading=&#34;lazy&#34;  alt=&#34;通用源码阅读指导书-京东自营&#34; /&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://union-click.jd.com/jdc?e=&amp;amp;p=JF8BAMYJK1olXDYCV1ZeCU4UCl9MRANLAjZbERscSkAJHTdNTwcKBlMdBgABFksUC2wJHlgcQl9HCANtb1FqVSleXj1wFXRcAC4CXAlkWTFyXVcZbQcyVF9cCE8eBWcKG2slXQEyAjBdCUoWAm4NG14WbQcyVFlYCkMTBGcBGVkWXzYFVFdtUx55BWdbSV9AVQEBVl9fCnsnM2w4K2sVbQUyFjAKDRtHUTgNHF4VVVMHAV5YAEhAAWsLHFkXCQEDXVcOXXsVAm4MEms&#34;&gt;《通用源码阅读指导书》&lt;/a&gt;&#xA;​&#xA;一本教你如何阅读源码，并从源码中吸取架构、编程知识的书籍。&lt;/p&gt;&#xA;&lt;p&gt;自吹自擂的话都掠过吧，大家可以自行去看书籍介绍或者目录了解更多。&lt;/p&gt;&#xA;&lt;p&gt;最后以书中前言的一段话结尾，共勉！&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/41/pic/002_hu_1ada5a55f97cc284.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;262&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;所以，编程的进步之道就是：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;多学，多练，但千万别忘了对答案！&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;对了，这本书也受到外方出版社的好评，并被台湾地区购买版权。接下来，将会在台湾等地发行繁体版。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/41/pic/003_hu_d75a756b3d10c58b.webp&#34; alt=&#34;图片&#34; width=&#34;720&#34; height=&#34;450&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;当然，我也在想。如果有一天，国内的计算机书籍能够发行英文版，就算是反向文化输出了，那应该厉害了。&lt;/p&gt;&#xA;&lt;p&gt;这靠我们每位从业者的努力！&lt;/p&gt;&#xA;&lt;p&gt;加油！&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
