技术岗转管理岗会面临哪些问题?

这是之前我写的一篇知乎回答,先后获得知乎圆桌精选,日报收录和编辑推荐,起因是有人再问:

实在是对管理团队提不起兴趣,也不愿意离开现在的职位,但不这么做一方面会被后来的年轻人赶上,另一方面薪酬也提不起来。看了一些这方面的书,觉得没什么收获。

程序员从技术岗被提拔进入管理角色,常常面临几个不容易发觉的误区,处理得好能否让自己职业生涯更进一步,而忽略了却容易让自己掉坑里。

误区1:不要对立 【管理岗】和【技术岗】

有人是转了【管理岗】就把技术丢掉,觉得终于可以摆脱码农身份,希望做纯粹的管理,进而今后向中层,高层发展。须知到处都不缺纯粹的管理人员,技术丢掉了,哪天项目变动,不一定就需要你去做管理了,退回技术岗很不适应,恐怕就只有离职的分了;纯粹的管理人员需求量并不是那么高,一般都喜欢内部提拔信任的人,哪天你换个工作了,新公司看你初来咋到,人家凭啥信任你?顶多也只能给你个骨干或者副手的机会,以观后效。见过不少转纯粹管理的,除了一直高升的极少数几个外,大部分一旦项目变动或者换工作,基本就挂了。

还有人喜欢纯粹技术,有机会转管理岗的时候不去争取,觉得只有纯粹技术岗才能将技术做好。其实大可不必这么顾虑,管理岗的非技术事情是比较多,但工作分配相对自由,管理之余你可以静心研究一些对项目比较有用的核心问题。

我见过优秀的技术管理人员,本身技术能力很强,管理能力照样很强,某同事本身在原有行业管理近 400人的研发团队,切换行业后,从基层程序员做起,并没有谋求在新公司一定就要做管理岗,凭着扎实的基础,很主动卖力的在新岗位上工作,很快成为骨干,对整个项目做出了突出贡献,开始逐步分担一些招聘和带人性质的工作,凭借先前出众的管理能力,很快被重视起来,机会一来,立马得到提拔。

能力是你自己的,职位和机会是别人给的,你真有能力,谁也很难埋没你;你德不配位,即是机缘凑巧走上了管理岗,有点变动你也就废了。真正牛逼的人,放在哪里都能闪光,没人埋没得了你。

误区2:主次颠倒:

技术管理的终极目标是【搞定问题】,把你找来是要让你搞定一个个项目的,不是吃干饭的。管理本身的目的就是在有限的资源下达到既定目标。时间、人力都是有限的,如果资源无限那要你何用呢?即,大家搞不定了,时间紧了,需要你上的时候,你得二话不说顶上去,别想当什么甩手展柜,你又不是老板,你是管理者,没有哪里需要甩手掌柜,以为【分配别人工作】就得了;硬件一分钟买不回来,没有条件,短缺这样短缺那样,你得想办法解决;另一方面,该拼命时你得下得了决心鼓励团队向前冲,比如加班。

三观正的管理者,立场肯定要站在公司一边,该对大家有所要求的时候就要能对大家有所要求,谁都想做老好人,这个说多了,可能有些人又不爱听了,问题是你管理者不是基层员工。你只有对自己和团队严格一点把一个个问题搞定了,大家的收入才能往上提升,职业才能有所发展,这才是真正的对大家好;平时大家一团和气,每个人都过的舒服自在,如果最终问题搞不定,大家收入和职位上不去,那你是在害大家。

误区3:不能严格要求

团队的战斗力从哪里来的?严格的要求,统一目标。太抽象?我解释一下:

Continue reading

Loading

Posted in 大浪淘沙 | Tagged , | Leave a comment

用 Vim 被人说装逼,怎么办?

从没见过 Vim 的用户神经病跑到 IDE / 大JB / sublime / vscode / atom … 话题下去砸场,让他们来用 Vim;反而天天看到 IDE / 大JB / sublime / vscode / atom 的用户天天跑到 Vim 话题板块下来劝退,骂装逼,骂程序写不好用编辑器找存在感,我就有点奇怪了。

究竟是谁在这里找存在啊?为何哪些板块下有些人天生就有那么大的优越感,觉得用 Vim 的人都是程序写的差的,不如他们的人呢?甚至因为写程序主要实在思考,其次才是在编辑,所以就觉得程序写的好的人编辑速度或者打字速度很慢居然是一种光荣。

按这种神逻辑, 写中文文章大部分也是思考,是不是要建议大家把联想输入法关闭,倒退到全拼时代才满意啊?不是还有文学大师至今不会打字全靠手写么,想学吗?这就叫反智,vim提高效率以后正是帮你解放大脑去思考,编辑工作直接小脑加脊柱反射就完成了,根本不需要把大脑费在编辑上。

我看很多 IDE 重度用户也很喜欢用 vscode / sublime 的嘛,为何不准别人 Vim 了呢? vscode / sublime 出来前觉得 IDE天下第一,vscode / sublime 出来后又觉得快速开发真方便;觉得 vscode/ sublime 配置性强,扩展丰富跨平台,集成 git 方便。我就奇怪了,这是在夸 Vim 么?这些点上 Vim 可以甩前两者十条街啊,只不过上手难点而已。

再说 IDE 板块有些用户,过来砸场也就砸了,根本砸不到点上,什么 Vim 不支持带上下文语义的智能补全的说法都出来了。jedi / deoplete / YCM / clang completor 等插件,都被吃了?

Loading

Posted in 未分类 | Tagged | Leave a comment

如何看待五年后产品经理职位将消亡的观点

消亡肯定不会,但是心态需要调整一下。

产品经理们的焦虑还要考虑历史进程和大背景,即行业主导权正在从产品向运营和营销转移。产品创新的空白点已经被密密麻麻的填满后,整个互联网正在由产品创新向运营创新和营销创新转变,在这个大进程中,有些缘来习惯了产品主导的从业者们一分钟变得不是那么习惯了。

有公司做了一个麻将游戏,一开始因为某大型麻将游戏开房间玩要买5元一张的房卡(可以玩个十多分钟),该公司第一个版本是房卡免费,开房间不需要钱,想以此去竞品那争取用户,结果没人玩,后来他们变聪明了,将房卡涨价到4元,然后诚招代理,以3元的价格给代理房卡,于是代理把身边的朋友都拉过来了,“XX麻将房卡要5元,我认识一个新麻将,和它差不多,房卡只要4元,我们去那里玩吧,你们如果找我买房卡,我还可以拿到3.5元的房卡,比官方更便宜点”。于是朋友纷纷跟着代理转投新游戏,利用这种多级代理模式,那个新麻将一夜间火了。

人家这是靠营销模式成功了,这样大大小小导致成功的例子,大到前几年的充值返利,游戏首充帐号,工会,小到个体产品的流量获取模式,这两年这样的例子可以数出几十条来,而大部分都是集中在运营层面的创新和营销层面的创新。产品创新的空白点,这几年被填的差不多了,因为产品大家都差不多,而运营和营销还有大量空白点需要填充,所以产品人员感到自身的价值在下降。

Continue reading

Loading

Posted in 大浪淘沙 | Tagged , | Leave a comment

如何实现一个真正高性能的spin_lock?

应用层用spinlock的最大问题是不能跟kernel一样的关中断(cli/sti),假设并发稍微多点,线程1在lock之后unlock之前发生了时钟中断,一段时间后才会被切回来调用unlock,那么这段时间中另一个调用lock的线程不就得空跑while了?这才是最浪费cpu时间的地方。所以不能关中断就只能sleep了,怎么着都存在巨大的冲突代价。

尤其是多核的时候,假设 Kernel 中任务1跑在 cpu1上,任务 2跑在 cpu2上,任务1进入lock之前就把中断关闭了,不会被切走,调用unlock的时候,不会花费多少时间,cpu2上的任务2在那循环也只会空跑几个指令周期。

看看 Kernel 的 spinlock:

#define _spin_lock_irq(lock) \
do { \
    local_irq_disable(); \
    preempt_disable(); \
    _raw_spin_lock(lock); \
    __acquire(lock); \
} while (0)

看到里面的 local_irq_disable() 了么?实现如下:

#define local_irq_disable() \
    __asm__ __volatile__("cli": : :"memory") 

倘若不关闭中断,任务1在进入临界区的时候被切换走了,50ms以后才能被切换回来,即使原来临界区的代码只需要0.001ms就跑完了,可cpu2上的任务2还会在while那里干耗50ms,所以不能禁止中断的话只能用 sleep来避免空跑while浪费性能。

所以不能关闭中断的应用层 spinlock 是残废的,nop都没大用。

不要觉得mutex有多慢,现在的 mutex实现,都带 CAS,首先会在应用层检测冲突,没冲突的话根本不会不会切换到内核态,直接用户态就搞定了,即时有冲突也会先尝试spinlock一样的 try 几次(有限次数),不行再进入休眠队列。比傻傻 while 下去强多了。

Loading

Posted in 编程技术 | Tagged , | Leave a comment

游戏机模拟器的具体原理是什么?

“游戏机模拟器” 注重的是 “严格模拟硬件”,要精确,可以对照 MAME代码,所有问题都能在里面找到对应答案:

第一:模拟 CPU

MAME里实现了各种 68000, z80,mips, sparc, arm,pic16c5x,nec, alpha,等 100 多款你见过的或者没见过的主从协处理器的模拟,虽然都是 switch case opcode,但是不像 lua虚拟机。MAME的 CPU模拟重点在 “精确实现硬件”,除了指令集实现外,还有各种软硬终端/trap/异常处理/IO实现。举个简单例子,一个游戏主机需要 4MHz 的 z80芯片,你就得给我真的按照 4Mhz来跑,每条指令计算周期,不能多也不能少,你要把 4Mhz跑成 8Mhz,游戏玩起来节奏就不一样了。比如以前老游戏机上敌人一多,就会慢下来,你实现模拟器,也得把这种慢下来给实现了。另外很多街机是双处理器,比如一块 68000 + z80,你不能复原老主机的运行速度,一些写的粗糙的游戏 ROM可能会出错。

模拟 CPU重点是 “精细”,比如浮点数误差最好一致,比如中断优先级你得模拟出来,模拟器由于按照 interval 来运行,更容易产生同时多个硬件中断被触发,比如 “手柄按键” ,多核通信之类各种东西加在一起,某个核满负荷运行的情况下,优先级低的可能永远得不到处理,弄错了可能游戏就没法玩了。

第二:模拟总线

总线也有好多规格需要实现,不同基板的总线链接不同cpu 和外设的方式都不一样,还是需要 “精确模拟”,比如 ROM /RAM / IO 地址映射,一些大容量游戏需要 ROM 的 BANK 切换,还有一些游戏会在卡带上带有扩展内存,除此之外还要正确模拟各种异常,比如某些 RAM,读写奇数地址会出错,要给对应 CPU发送异常信号,某些老点的 RAM只能读写 16bit的 WORD,不能读写 DWORD或者 BYTE,否则都无效。这些你都得模拟到位了,有些有 BUG的游戏,错误的写了内存,在真实主机上,写操作直接被硬件忽略掉了,没有损伤,但软件模拟不注意执行了那条指令结果就不一致了。

第三:外设模拟

音频芯片,I/O,图形加速芯片,随机数发生器,音视频输出,摇杆,时钟等。有些外设是有bug的,你也要把这些历史上的硬件bug给模拟进去,不然游戏可能行为不一致。

第四:调试系统

提供终端和接口可以内存 DUMP,反汇编,修改指令和数据,保存现场之类的。

有史以来出现过的游戏机硬件数不胜数,但是他们用到的芯片或者硬件是有限的,比如z80和 68000这类流行的芯片,具体每台主机其实就是一份配置文件,包含使用那种总线,哪些cpu,分别按照什么速度来运行,内存I/O布局,关联哪些外设,BIOS和启动加载等信息。

总之是个辛苦活,你需要一本硬件手册,然后边查边弄。

如果你嫌 MAME太复杂庞大,再推荐一个 gens 的代码,只针对世嘉16位机的 Windows实现,条理很清晰,很多比世嘉简单的 FC模拟器写的都没有 gens那么结构清晰,简单易读。它就不像MAME那么大而全,很多步骤实现的很直接不需要配置那么多,代码量也不大。

现在新进的模拟器很多,没机会逐一查看他们的实现细节,只记得有几款比较新的模拟器都是直接裁剪 MAME的部分代码来弄的,因为 MAME里面几乎实现了所有游戏能用的芯片了,拿出来改改参数加点指令集就可以用,比如 MAME里面模拟了 mips,我们裁剪出来实现 PSP模拟器,个别指令有些区别需要改一下,然后我们着重自己实现 PSP里面 MAME没有的硬件部分。

Loading

Posted in 游戏开发 | Tagged | 1 Comment

为何很多 C++开源库都爱自己实现 string?

C++ 不是号称不限制你的开发方式么,每个库想怎么搞就怎么搞,这明明就是 C++的优势,不知道大家抱怨个啥?哈哈

接着说 std::string 的性能问题,举个具体例子吧,之前接手过一个项目,别的部门同事自己撸的一套 DirectUI 系统,用 tinyxml 解析界面节点,项目简单的时候没啥,随着ui越来越复杂,数千个节点,每个xml节点若干属性,每个属性就是一个字符串,我记得好像有500+ KB的 xml要解析,而且这部分界面还没法延迟初始化,必须启动加载时做完,启动十分慢。profile下来,很多时间卡在 tinyxml上,整个过程接近 3秒,费时最前的操作卡在处理各种字符串的操作上。

把 tinyxml 换成其他 xml库 ?没那么容易,项目各处模块都在依赖 tinyxml的各种接口和类。一开始觉得内部的 TiXmlString 实现有问题,换成 std::string,vc 2012下时间从3秒增加到4秒,更不靠谱(vs2012应该已经有所谓SSO了),所以人家 tinyxml 这里用自己的 TiXmlString 肯定也是比较过的,不然干嘛不用 std::string 。

Continue reading

Loading

Posted in 编程技术 | Tagged | Leave a comment

软件公司说开发一个拍卖 app 要15万元,真的有这么贵吗?

有些人欺负外行,漫天要价,你找个牛人,给他1万,再找两个学生,每人给他们3千,然后再花4千元买一年腾讯云服务器。合计成本:
10000 + 3000 x 2 + 4000 = 20000
不认识牛人?没关系,预算3万,找个老师,老师帮你搞定一切(牛人+学生)。
不认识老师?没关系,身边没有本地读书的同事朋友么?他们肯定有很多留校的同学啊。
简单点的话1个月就足够出活,慢点一个半月,如果这个方案比较接近您心理预期的话可以试试。

———-
有人对 3000元是否能请到学生,1万元能否请到牛人的疑问,看你怎么说了:

学生嫌便宜的话,要告诉他们跟着牛人学东西,机会难得,跟他们说学校里学的都是死知识,你实际做一做才知道哪些知识怎么用,同时这个牛人如何如何牛,之类。不能光读书,有这个项目的经历和历练,明年他们再去一些大厂找实习,都是比较容易的,人生就像上楼梯,你要先把这一级踩踏实了,才能去够下一级,然后再下一级,如果他们简历上一穷二白,只有考试分数,谁要你啊?你朋友就是XX公司XX总,前两天还打电话给你找你推荐实习生呢,你觉得年轻人最重要的就是学习新东西的能力,是激情和执着,等等。

牛人嫌便宜的话,你可以找学校里面没出校门的牛人,他们技术一样牛,有厉害的学生技术比很多工作4,5年的人都强,却没沾染不良社会风气,不会跟你乱要价,再说如果一个牛人真的很在乎这点眼前利益,那他也不是什么真正的牛人。

你要跟他强调,不是找他做打工,是邀约他一起创业,共同成长,饿了么,课程表不都是学生创业的成功典范?人生重要的不是能力,而是选择是魄力,1万也不算低了,很多工作几年年的月薪也就这个数,除此之外这里还包饭包夜宵,团队气氛十分融洽,大家都崇尚工匠精神,这个是市里xx部门牵头的大项目,xx书记亲自过问,希望他目光长远点,不要在乎眼前小利,成功了大家一起分钱,视情况可以给他签一份他拥有本公司值人民币 10万元的股权的,云云。

我看有些app也并没有想的那么复杂嘛,找几个真正想做事情的年轻人,有激情能出活。

Loading

Posted in 大浪淘沙 | Tagged | Leave a comment

Emacs/Vim 深度比较

生命在于折腾,折腾完了 Atom Editor,开始跟着陈斌大婶和 purcell的配置折腾 Emacs,比较下。很多人都在比较键位,比较插件,这是十分肤浅的,我们比较点深入的东西:

代码结构

  • Emacs 源代码:eLisp 79%, C 21%
  • Vim 源代码:C 52%, VimScript 48%

从代码结构上来讲,Emacs的代码最多的是 elisp,C代码只是一个微内核,Vim 里C代码还是大头。当然不排除 24.X, 25.X以后 Emacs源代码里带了好几个重量级的包,而 Vim向来比较精简一些,官方没带啥大点的插件有关。去除自带插件后,Emacs的 elisp代码比例应该会下降很多,不过总体来说,Emacs有更多组件使用 elisp开发而成,也就是说可以被用户修改或者替换的地方比 Vim要多,当然速度也会相应慢一点(比如 Emacs新打开上万行的文件连续按住PageDown时cpu 100%占满),不过比较大 JB,Atom Editor来说,还是快不少。

系统接口

大框架基本类似:

  • Vim 可以操作: buffer, window, tabpage, 光标,marker, region 跳转表等等。
  • Emacs 可以操作:buffer, window, frame, 光标,marker,region 异步进程 等等。

Vim 有 local,Emacs有 mode,Vim有事件触发,Emacs有各种钩子,基本大框架类似的。

键位设置也都很灵活,会配置的话,可以把 Emacs键位全部弄成 Vim的,比如 Evil,或者Vim里面也可以配制成进去就自动进入插入模式,全部用 Emacs键位。

具体到比如 buffer 或者窗口里面,Emacs的窗口或者 buffer /window 属性更多一些,Vim也有一些 Emacs没有的基础设施,比如 jumplist, quickfix之类的,不过 Emacs也可以用插件实现,实现 jumplist没问题,比较独立,但每个插件实现一个类似的 quickfix的东西,实在是比较蛋疼。

脚本语言

VimScript 类似 Lua,但更啰嗦些,没啥好说的,要上手可能就是2-3天的样子,主要是实际编写中熟悉各种 Vim内部结构体系,以及api。

EmacsLisp 类似 clisp,稍微有些区别而已。clisp中的向量: (vector 1 2 3 4) 在 elisp中可以用中括号来表示:[1 2 3 4] 这样对减少小括号数量有一些帮助,代码读起来没那么拗口,可惜实际写 elisp的过程中,向量用的并不多,各种插件用的最多的还是 list,alist,plist 几种容器,小括号还是满天飞,如果不借助编辑器的匹配,缩进,还有彩虹括号(不同层次的括号用不同颜色的小插件)代码很难阅读,自己写好写点,看别人代码要对括号对半天(特别是他们把很多写一行的话)。

Lisp变量可视范围比较好用,局部变量可以 “遮盖住” 全局变量,比如你在 VimScript里面要临时跳转到一个新目录需要这么写:

let cd = haslocaldir()? "cd" : "lcd"
let saved = getcwd()
silent! exec cd "my new directory"
......
silent! exec cd saved

而 elisp里面,利用局部变量遮盖特性,简单的:

(let ((default-directory "my new directory"))
  .....
  )

在这个 let的作用范围内,buffer的全局变量 default-directory 被新定义的同名局部变量给遮盖住了,里面的代码(包括调用外面定义的函数)取这个名字的变量,都会取到你新定义的变量,作用范围结束就恢复了,这样比 vimscript方便不少,类似的用法还有 (with-selected-window new-window...) 把当前窗口设置成 new-window并做一些事情,当离开代码作用域以后,自动恢复成先前的窗口,如果VimScript来做这事情,又需要保存前窗口,然后跳转,最后又恢复。

VimScript在 vim6.0及以前的时代里比 EmacsLisp弱很多,连个 List,HashTable之类的容器都没有,怎么写复杂的程序嘛,Vim7.0以后补充了字典和列表还有三元式,简单面向对象等,终于可以写点复杂的东西了,而 Vim下很多传奇性的插件,其实也正是 7.0以后才出现的。Vim8.0以后又进一步补充了匿名函数和 partial function (类似简陋版的 curry 函数)等等特性,除了啰嗦外,写点复杂东西问题不大,比如前久有人用 VimScript写了一个 C编译器,可以在Vim里跑 C脚本。

Lisp里面的宏类似C++模版加强版,C++模版只有一层,定义好模版,然后生成代码。Lisp的宏可以先用程序生成模版,再由模版生成代码,类似模版的模版。不过实际使用中,为了不让自己的代码飞的太远,难以维护,大部分插件开发者在 elisp里面最多就是 require一下 common lisp的兼容包,用一些 common lisp里面诸如 loop, for, incf, case 之类的通用宏,自己定义也限于定义一些小工具,没有人丧心病狂的搞一些影响程序结构的东西,定义成另外一门语言。

大部分插件开发者实际上还是把它当作充满括号的 lua 来用,除去一些便利性外,麻烦也还是挺多的。

异步进程

早期的 Vim没有异步进程操作,导致很多插件没有 Emacs那么顺畅,比如生成 tag或者编译,Vim只有傻等着,Emacs可以同时做其他事情,Vim8.0以后异步接口和后台时钟等也比较完善了,假以时日各大常见插件能逐步发挥 8.0特性的时候,相信也能带来一致的体验,包括纯vimscript实现的 shell,以及 gdb集成,发邮件等,问题不大。

Continue reading

Loading

Posted in 随笔 | Tagged | 2 Comments