<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[liminyu的专栏]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/liminyu</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; liminyu]]></copyright><item><title><![CDATA[PyTorch环境搭建]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/124902353</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/124902353</guid><author>liminyu</author><pubDate>Sat, 21 May 2022 20:15:01 +0800</pubDate><description><![CDATA[基于Python 3.10.4搭建PyTorch开发环境]]></description><category></category></item><item><title><![CDATA[做个广告-新书优惠]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/120925530</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/120925530</guid><author>liminyu</author><pubDate>Sat, 23 Oct 2021 20:16:40 +0800</pubDate><description><![CDATA[本人新书《码农修行》目前当当正在五折优惠。《码农修行：编写优雅代码的32条法则》(林文 著)【简介_书评_在线阅读】 - 当当图书

]]></description><category></category></item><item><title><![CDATA[这条编程规范如何？——条件分支超过6个时必须改为接口]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/118948215</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/118948215</guid><author>liminyu</author><pubDate>Wed, 21 Jul 2021 00:39:00 +0800</pubDate><description><![CDATA[前面举过一个面向接口编程的例子。在系统中写日志有3种不同的实现：

写到日志文件。
	写到数据库。
	写到本地的一个日志服务的UDP端口。
按照常规的思维逻辑，可以用一种最直接的写法。如下方案一。

方案一


public class LogController {
	private LogService logservice;
	void writeLog(SysLogInfo logInfo){
		switch(logType){
		case LT_FILE:
			logservice.writ]]></description><category></category></item><item><title><![CDATA[别把Java写成C++的样子。你真的在正确运用依赖注入吗？]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/116568933</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/116568933</guid><author>liminyu</author><pubDate>Sun, 09 May 2021 20:53:39 +0800</pubDate><description><![CDATA[最近发现很多使用Spring框架的Java代码存在依赖注入方式的误用，甚至是滥用。因此整理了这篇文章，欢迎大家一起探讨。先举个例子，从C++说起……

C++的诟病

C++最遭人诟病的地方就是定义一个类需要写两个文件，一个.h文件和一个.cpp文件。例如定义一个CMainFrame类，mainframe.h内容如下：


class CMainFrame : public CFrameWndEx
{
protected:
	CMainFrame();
public:
	virtual ~CMainFram]]></description><category></category></item><item><title><![CDATA[寻找编程的乐趣]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/113029224</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/113029224</guid><author>liminyu</author><pubDate>Sat, 23 Jan 2021 09:41:45 +0800</pubDate><description><![CDATA[内容简介：

1.寻找编程的乐趣

2.正确理解面向对象设计

寻找编程的乐趣



]]></description><category></category></item><item><title><![CDATA[《码农修行》法则07：避免过度防御]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/113004955</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/113004955</guid><author>liminyu</author><pubDate>Fri, 22 Jan 2021 22:46:53 +0800</pubDate><description><![CDATA[《码农修行》法则07：避免过度防御

非法指针是C/C++程序中最令人头痛的问题之一。你也许会有类似的习惯，在函数入口即对指针的合法性进行检查。代码如下。



即使在调用该函数前已经做过一次检查。代码如下。



这两处检查都属于过度防御，完全没有必要。首先，参数的合法性应该由调用者保证。可以参考一些参数为指针的API，比如strncpy，当对其强制传入一个空指针时，程序并不会悄无声息，而是会抛出异常。



因为这样的参数已经违反了接口的规约，函数内部不知道该如何处理，只能抛出异常让程序崩溃。

此外，]]></description><category></category></item><item><title><![CDATA[留意编译告警]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/102760637</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/102760637</guid><author>liminyu</author><pubDate>Sat, 26 Oct 2019 20:17:44 +0800</pubDate><description><![CDATA[Java编程不涉及本节内容，因为它在编译时语法检查更加严格，要么出错要么成功。C/C++也许是太过于灵活，或者由于历史原因，编译时除了产生错误还会产生告警。同时程序中编译告警容易被忽视，但其中往往隐含着一些潜在的问题。

我曾经参与过的一个项目中增加了PcLint检查，但由于规则设置的缘故，有一个bug没有产生PcLint告警。在最终定位问题后，才留意到它其实已经导致了一个编译告警但被忽视了，因为...]]></description><category></category></item><item><title><![CDATA[善始善终]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/100778835</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/100778835</guid><author>liminyu</author><pubDate>Thu, 12 Sep 2019 17:49:58 +0800</pubDate><description><![CDATA[互斥锁的加锁解锁，动态内存的申请释放，都较难驾驭且容易出错。所幸我在Z和H公司所写的代码都有意或无意的避免了这两个问题。当时所涉及的是基于VxWorks的嵌入式编程，在进程调度方面系统控制层做了限制，每个进程处理完自己的消息任务后才会调度另一个进程运行，因此避免了进程并发的情况，也就无需对临界资源进行加锁。另一方面，嵌入式系统对实时性要求很高，系统中所需要的内存都在初始化时全部申请完成，并且一直不...]]></description><category></category></item><item><title><![CDATA[命名]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/100134917</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/100134917</guid><author>liminyu</author><pubDate>Thu, 29 Aug 2019 11:50:13 +0800</pubDate><description><![CDATA[如果你准备花一小时写代码，那么其中半小时得用于起名字。这句话虽然有些夸张，但体现出命名的重要性。的确，类名、函数名、变量名、文件名等等如果含混晦涩，会给维护工作造成麻烦。

命名时把握一个原则：对于函数说明其在“做什么”，对于类或变量说明其“是什么”。言简意赅是一种理想状态。首先要用词准确，特别是对英语没把握的人，请随时查一下字典。然后把这些词拼成一个短语或短句。最后，如果名字太长，再做一些简化。...]]></description><category></category></item><item><title><![CDATA[可读性]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/100134887</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/100134887</guid><author>liminyu</author><pubDate>Thu, 29 Aug 2019 11:48:21 +0800</pubDate><description><![CDATA[如何提高代码的可读性是一个永恒的话题。

通常认为程序员需要具备较高的“数学”功底。毕竟要掌握各类模式和算法都依赖很强的逻辑思维能力。然而在经历了一段职业生涯后，我发现程序员的“语文”能力也同样重要。《重构》一书中就提出：唯有优秀的程序员能够写出人类能理解的代码。软件的规模越来越大，一个系统通常需要几代程序员来开发维护。然而这些程序员们往往都素未谋面，只能“神交”于代码的字里行间。

提到可读性，...]]></description><category></category></item><item><title><![CDATA[性能]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/100116100</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/100116100</guid><author>liminyu</author><pubDate>Wed, 28 Aug 2019 12:02:58 +0800</pubDate><description><![CDATA[做人不要斤斤计较，但写代码一定要斤斤计较！
来看一个Linux-2.4内核中的例子，学习世界顶尖高手的做法。内核中经常要访问进程控制块（PCB），其在内核中定义为task_struct结构。为此在include\asm-i386\current.h中定义了一个宏current，提供指向当前进程的task_strcut结构的指针。
static inline struct task_struct *...]]></description><category></category></item><item><title><![CDATA[用表驱动消除冗余代码]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/77453785</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/77453785</guid><author>liminyu</author><pubDate>Mon, 21 Aug 2017 18:23:38 +0800</pubDate><description><![CDATA[表驱动法最常用的一种场景是用其替代if和case语句，使用查表的方式实现代码逻辑，其可以以使代码更为简单明了，同时可以获得更优的执行效率。但其还有一种运用场景：可以消除冗余代码，使得代码更灵活，方便应对将来需求的变化。
假设下面一段代码需要初始化一些ICON图标：
	m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON1)));
	m]]></description><category></category></item><item><title><![CDATA[写日志]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/76071707</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/76071707</guid><author>liminyu</author><pubDate>Tue, 25 Jul 2017 15:13:15 +0800</pubDate><description><![CDATA[为什么记日志
日志记录是否完备，直接影响到软件产品维护和问题定位的难易程度。这主要源自以下几个因素：
第一、开发人员自己的环境无法覆盖100%的应用场景，某项功能在开发者的机器上一切正常，但是到了测试人员或用户的机器上就不能满足预期。
第二、当在用户现场出现问题时，往往无法再单步调试。如果要到用户现场架设一套开发环境成本太高。
第三、有些问题存在一定概率，并不能100%复现。而日志可以记录]]></description><category></category></item><item><title><![CDATA[关于软件工程的类比]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/75433938</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/75433938</guid><author>liminyu</author><pubDate>Wed, 19 Jul 2017 18:21:22 +0800</pubDate><description><![CDATA[我不喜欢“码农”“码工”“程序猿”这类自贬身价的词语。
我的爷爷是一名裁缝，在我的记忆里他靠在家里给别人定做衣服谋生，算是一个手艺人。我的职业生涯一直和代码打交道，靠写代码谋生，也算是一个手艺人。当然手艺好的人应该能称得上是代码工匠吧！
我喜欢把这群代码工匠称为软件设计师。为什么是软件设计师而不是软件工程师，这源自于我对软件工程的不同理解。


建筑工程大致可以分为两个阶段，设计阶段和施]]></description><category></category></item><item><title><![CDATA[避免堆栈溢出]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/71638243</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/71638243</guid><author>liminyu</author><pubDate>Thu, 11 May 2017 16:11:14 +0800</pubDate><description><![CDATA[案例
最近在做一个Windows程序，其中有个消息处理函数，大概是这样的：
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
	ON_MESSAGE(WM_MY_MESSAGE, &CMainFrame::OnMyMessage)
END_MESSAGE_MAP()
LRESULT CMainFrame::OnMyMessage(WPARAM wp, LPA]]></description><category></category></item><item><title><![CDATA[透过现象看本质：共享单车之摩拜和ofo的工作原理分析]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/71131413</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/71131413</guid><author>liminyu</author><pubDate>Wed, 03 May 2017 17:51:37 +0800</pubDate><description><![CDATA[开锁方式
摩拜用app扫码成功后，锁会自动打开，无需人工对单车进行干预。这说明摩拜单车内部有联网装置，app扫码成功后，服务器后台发送指令，单车自动开锁。
ofo需要输入单车的ID号码，随后程序给出一个开锁密码，需人工旋转开锁密码后，方能开锁。因此ofo单车没有联网装置。其内部的开锁原理类似银行的U盾密码卡，其密码每分钟变换一次，输入单车ID后，程序后台会计算其密码。在实际使用中也会碰到旋转密]]></description><category></category></item><item><title><![CDATA[写代码的目的]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/69568213</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/69568213</guid><author>liminyu</author><pubDate>Fri, 07 Apr 2017 15:57:20 +0800</pubDate><description><![CDATA[写了那么多年代码，突然想自问一下：写代码的目的到底是什么？
在回答这个问题之前，我想先归纳一下软件开发者的职业生涯，总体说来可以分为这么几个阶段：
初级阶段：仅仅是简单的完成上级分配的任务。上级让做什么就只做什么，甚至对代码的性能，可靠性，可扩展性，可维护性都不加考虑。此时开发者最需要的是一份详细设计文档，并按照文档进行开发。这个阶段的人对需求变更相当排斥，甚至会因此频繁跳槽。绝大多数开发者的]]></description><category></category></item><item><title><![CDATA[Linux 3.x 内核学习笔记——页面的周转]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/12909217</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/12909217</guid><author>liminyu</author><pubDate>Mon, 21 Oct 2013 13:31:14 +0800</pubDate><description><![CDATA[页面周转
本文以Linux-3.11.0为例。
内核中所有物理内存都有其对应的page结构，这些page在整个系统的运行中，会处于下图的5个状态中。

Freeze Page：并非所有内存都可以用于分配，有些内存被内核所保留使用，例如：内核映像本身所处的内存空间、一些硬件要求需要保留的地址区间、内核中一些固有的数据结构（如page结构本身）等。系统在初始化阶段将这些内存所对应的地址标识为r]]></description><category></category></item><item><title><![CDATA[Linux 3.x 内核学习笔记——x86 64位内存管理]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/12519729</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/12519729</guid><author>liminyu</author><pubDate>Wed, 09 Oct 2013 18:17:30 +0800</pubDate><description><![CDATA[地址映射
64位地址采用4层地址映射，如下图：


pgd、pud、pmd、pte各占了9位，加上12位的页内index，共用了48位。即可管理的地址空间为2^48=256T。而在32位地址模式时，该值仅为2^32=4G。
另外64位地址时支持的物理内存最大为64T，见e820.c中MAX_ARCH_PFN的定义：
# define MAX_ARCH_PFN MAXMEM>>PAGE_]]></description><category></category></item><item><title><![CDATA[一种大文件的排序方法]]></title><link>https://blog.youkuaiyun.com/liminyu/article/details/8271193</link><guid>https://blog.youkuaiyun.com/liminyu/article/details/8271193</guid><author>liminyu</author><pubDate>Fri, 07 Dec 2012 22:44:54 +0800</pubDate><description><![CDATA[要求：一个文件中存有若干单词，每行一个，要求将文件中的单词按字典序排序。
分析：由于一个文件的大小可能超过内存大小，因此想要一次将整个文件全部读入内存后再进行排序是不现实的。当然，处理此问题可以采用归并法：把大文件拆分成多个可以一次读入内存的小文件，再对小文件进行排序后再归并。不过在此介绍另一种方法：以“磁盘空间”换内存空间，在文件内部进行冒泡排序。
算法思路：读取文件中的第1、2两个单词，若]]></description><category></category></item></channel></rss>