精华内容
下载资源
问答
  • 说在前面:有粉丝提问说自己并不确定学前端,因为自己还没有工作,想做程序员,想问问做哪个方向比较有前途; 有两三个小伙伴这么问的,感觉很有意义,拿出来单独说说比较好。 目录 程序员有哪些选择? 选择...

    说在前面:有粉丝提问说自己并不确定学前端,因为自己还没有工作,想做程序员,想问问做哪个方向比较有前途;

    有两三个小伙伴这么问的,感觉很有意义,拿出来单独说说比较好。

    目录

     

    程序员有哪些选择?

    选择前端的弊端

    为什么学校普遍教后端?

    安卓开发/苹果开发的暗淡前景

    任何技术都很难吃一辈子啦

    哪些人不适合做前端?

    1.智商不能太笨

    2.不喜欢写程序的人

    3.不喜欢持续学习的人

    哪些人适合做WEB前端开发

    1.脾气好的人

    2.能够静下心学习的人

    3.坚定信心要转程序员,但是不知道什么方向的人

    4.设计/产品经验的人

    最后:拥有持续学习心态的人最适合


    程序员有哪些选择?

    一般来说,作为初级的程序员,可以选择前端开发,后端开发,安卓开发,ios开发开发测试这几个方面。如何要找到一个适合自己的,这个首先要根据的情况来;

    如果是科班出身还是比较对口的,科班出身,主要是指计算机相关专业的毕业的小伙伴;因为学校的教案和课程都是计算机基础和后端语言的,所以做程序员本身就有非常大的优势(无论是什么方向的程序员);虽然是科班出身,还要区分学习的好不好的情况。毕竟现在很多大学生喜欢打游戏,认真学习的并不是很多。

    如果你是学霸或者专业学的还可以,那么非常推荐你从事后端的岗位;因为掌握的好,自己学习了好多年,你面试的时候,基础牢固,比那些培训班出来的基础还要给力;优势很大!

    如果你专业知识学习的不怎么样的,那么后端可能不是一个好的选择;因为面试的时候,初级程序员,对基础类的面试非常看重;你的对手的学习情况和掌握都比你好;你本身的优势相对不好的;但是如果选择面试前端/移动端/测试的时候,因为是科班出身,还是比其他人有很大优势的!如果你是科班出身,学习不怎么好,还是想做后端工作,那么你可以通过报培训班,强化学习,那么你的优势比普通的人又会有很大优势!

    推荐非科班的小伙伴做前端开发

    科班做前端相对的不多,相对来说更偏向于后端,而且一般会心理看轻前端,所以前端的竞争相对小;如果你是一个非科班出身的,如果你选择后端,需要与科班出生的人竞争,你相对就比较弱势;但是你如果选择前端;

    • 一是这行的科班出身少
    • 二是科班出身的人,对前端接触的也不多,学校基本不教

    所以起跑线差不多;你的投入产出比会更好;从快速就业角度说:投入相同的精力,做前端比做后端收获更多;

    选择前端的弊端

    • 纯前端的做技术部老大非常少的
      • 基本做到前端组的小组长就算到头了;
    • 容易被怼
      • 客户出现什么问题都是来找你,你是离用户最近的程序员
      • 频繁修改界面
      • 后端不像前端,经常改界面,很烦人,纯搬砖;
      • 所见即所得
      • 每个人都可以来指点你一下
      • 后端的接口稳定就行,别人看不到,相对被怼的少

    为什么学校普遍教后端?

    • 成熟
    • 更容易吃老本;
    • 计算机底层更加重要

    前端技术更新换代太快太辛苦,后端更容易吃老本。

    安卓开发/苹果开发的暗淡前景

    非常不推荐现在新人进坑安卓和苹果开发;大部分公司因为业务的情况不继续做APP了,大环境的需求少了;很多转向web移动端,公众号,小程序这些了;现在手机端是寡头垄断和断层的情况,小公司很少需要客户端的;大公司需要,但是要求高;对新人相当不友好了;主要是小公司养不起,也推不动,很多小公司因为业务迭代少,做出来就不怎么修改了,很多转外包或者考虑前端做,或者公众号,小程序代替了小程序,公众号这些都是前端的工作范围;但基本所有互联网公司都需要后端和前端,前端和后端似乎都比 Android/iOS 有前途。如果前端想搞客户端 react native/flutter 都是很优秀的开源项目;

    任何技术都很难吃一辈子啦

    不要前途寄托在任何 XX 端上,要跟随时代的脚步学习和进步;各种技术和领域可能都难吃一辈子;不然就不会有人吐槽996,35岁的程序员该何去何从啦等大家都关注的热点,自己能产生价值才是最重要的,每天忙碌奔波就为了那几两碎银,偏偏那几两碎银能解万千慌张!

    当前企业不同岗位职能现状如下:

    哪些人不适合做前端?

    1.智商不能太笨

    如果你身边有认识程序员,你可以发现他们有些人可能口才不怎么好;

    有的人可能情商很低;但是大部分的人,智商和逻辑思维都超过大众水平;

    这个群体的逻辑思维会相对比较高;

    如果你的逻辑思维非常差,我觉得可能并不怎么适合这门职业

    2.不喜欢写程序的人

    这类人,不仅不适合做前端,也不适合做程序员;

    可能是因为工资待遇比较好,所以想做前端开发;

    因为反感,所以技术提升有限;

    这类人在前端领域一般不会走的很深,很容易过早的就被淘汰;

    3.不喜欢持续学习的人

    无论是前端还是后端,都是需要持续学习的;

    一招吃遍天下的路子在这里走不通的,这里也不是看工龄的,并不是越老越值钱;

    如果一名前端开发,没有持续学习的欲望,很容易直接下滑到初级程序员的行列。


    然后我们再聊下,哪些人适合做前端开发

    哪些人适合做WEB前端开发

    1.脾气好的人

    因为前端在公司中,对内连接的是后端/UI设计/产品,对外连接的是用户;

    是一个介于代码和用户之间的工种,这样就导致自己的作品,被更多的人直接看到;

    因为所见即所得的情况;,普通人很容易看到效果;然后每个人的喜好和体验都千差万别;

    这样就导致谁都可以过来批评你一下;(当然不止是前端,设计师,产品人员也经常被这样怼)

    后端大爷的作品,只需要稳定运行就好;别人又看不到,只要能稳定跑就好,你不是专业的后端,你都不好批评他的;

    而且领导有时候自己也不清楚产品方向,经常会频繁修改文案,甚至导致产品推倒重写;

    如果你是一个脾气暴躁的老哥,在这种被怼的场景下写代码,可能就像吃了一个苍蝇一样难受,特别反感,会慢慢讨厌自己的工作。

    2.能够静下心学习的人

    学习技术,不需要有搞摇滚,搞音乐那样的激情四射;

    大多数的时候,学习技术,都是深夜中coding,debug,慢慢的感悟出来;

    如果你不能连续做几个小时安心研究东西,可能会走的比较艰难;

    如果能静心研究的人,会更适应这种岗位;

    3.坚定信心要转程序员,但是不知道什么方向的人

    如果坚定信心要转程序员,但是不知道什么方向的人,web前端是最佳选择之一。

    现在很多传统行业的小伙伴想转行的话,因为前端入门容易,所见即所得;

    且薪资不错,招聘量大,即使是在二三线城市,也有不错的薪资。

    所以如果你是已经坚定信心要做程序员了,又不知道什么方向,那么前端开发可能是你一个不错的选择;

    4.设计/产品经验的人

    这类人因为工作的原因,经常接触前端,或者工作角色类似前端(就是容易受气 — —!,容易被怼);

    属于连接用户和内部领导的群人,对前端的氛围更熟悉;

    这类人如果想转程序员,选择前端,基本是大多数的选择;

    我本人就是从Java开发转向的前端开发;

    不过如果你是一名测试人员,那么要看你的工作性质偏向哪里了;

    你偏向哪里就选择哪个方向;

    最后:拥有持续学习心态的人最适合

    如果你有一颗持续学习的心,并且想做前端,那么上面所说的对你来讲都是废话;

    如果你能持续学习,做前端,你可以比大多数人走的更远;

    有人说感兴趣是最适合来做的,我觉得不是这样的;

    很多人说的感兴趣,只是一时兴趣,而且真正学习的时候,并不是你感兴趣,就能比别人学的好,学的块;

    你需要耐得住寂寞,经过无数个苦逼的敲代码和调试才能有所成就;

    真正学习的时候,大多数所谓的兴趣就是扯淡;

    只有那种遇到难题就兴奋,敲代码时候,越挫越勇的人,才叫感兴趣;

    真正的感兴趣是让你学的久,学的不累;

     

     

    展开全文
  • 盘点:中国“颜值+才华”的几位知名女程序员,如何看待女生当程序员。 毫无疑问,世人对程序员行业普遍存在的误区:1.程序员都是男性。2.程序员都是邋里邋遢,不修边幅,整天就穿一套衣服,一年都不会换一双鞋子……...

    盘点:中国“颜值+才华”的几位知名女程序员,如何看待女生当程序员。

    毫无疑问,世人对程序员行业普遍存在的误区:1.程序员都是男性。2.程序员都是邋里邋遢,不修边幅,整天就穿一套衣服,一年都不会换一双鞋子……其实,我们的阵营里也有很多女孩纸,她们人品、衣品各个一流!今天就为大家盘点中国“颜值+才华”的几位知名美女程序员!

    一、俞淑婷(清宵)
    在这里插入图片描述
    清宵是阿里“飞天”技术部的资深开发工程师,在高手云集的飞天技术团队,除了努力、积极、细心、敢于担当、靠谱,这些技术人的优点之外,更重要的是,她还具备了男工程师们没有的独特标签:美丽、长腿。在那次阿里年会上,清宵也开启自己的“维密之旅”。有这样的女同事为伴,就算加班到凌晨都谋闷台啊!

    二、张功
    在这里插入图片描述
    曾经因为和雷军的一张合照,引来大量吃瓜群众的围观。后来才知道这位员工原来在小米从事前端开发。雷老板平时对公司的男程序员一直很严厉,对张功却处处晓之以理,这就是所谓的异性相吸吧!

    三、三娘
    在这里插入图片描述
    “三娘”本是程序员,戴上假发,化妆后立马成“女神”。连360CEO 周鸿祎都不禁感叹:“这就是360屌丝的逆袭啊!!”你们自己体会一下。

    四、语希范
    在这里插入图片描述
    语希范毕业于哈尔滨工业大学计算机系,“手机 baidu”团队研制工程师之一,由于超高的颜值,被称为新一代“度娘”。不过,据说现在已入职阿里巴巴旗下的菜鸟网络。

    其实,无论是男性还是女性,程序员只需拿能力和代码来说话。硬核的技术世界也因为女程序员的存在,而变得姹紫嫣红!对此,你的看法呢?

    其实做为一个编程学习者,有一个学习的氛围跟一个交流圈子特别重要。希望大家能加我QQ2956807116,不管你是小白还是大佬都欢迎,大家一起交流成长。

    展开全文
  • 说到薪资,你知道国外的程序员薪资如何吗? 如果汇率不换算的话,国外的软件工程师薪资在10万美元~30万美元不等,与国内的薪资在数字上相差不大(考虑消费水平)。 AI工程师,月薪60k~140k。 软件工程师,月薪69k...

    最近,有人称程序员最高年薪可达218万,而我们打开社交网络平台,在搜索框上输入程序员三个字,出来的除了关于“头发”的那些事儿,其他比较多的讨论也是关于程序员的高薪资。

     

    说到薪资,你知道国外的程序员薪资如何吗?

    如果汇率不换算的话,国外的软件工程师薪资在10万美元~30万美元不等,与国内的薪资在数字上相差不大(考虑消费水平)。

    AI工程师,月薪60k~140k。

    软件工程师,月薪69k~183k。

    数据科学家,月薪43k~131k。

    前端工程师,月薪82k~122k。

    这是Business Insider曝光的12家最大明星“独角兽”薪资水平,定义域是成立不到10年、估值超过10亿美元,还未上市的创业公司。

    这2家明星创业公司主要包括了以下几个公司:

    Airbnb,Asana,Doordash,Epic Games,Instacart,Magic Leap,Palantir,Robinhood,Snowflake,Stripe,UiPath和Unity Technologies。

     

    国内的薪资水平对应的大公司薪资又是如何的呢?

    根据拉勾网的岗位薪资数据(截至2020年9月11日),字节、滴滴、大疆以及商汤的薪酬(月薪)大致如下:

    字节跳动:

    基础架构工程师:30k~60k;

    软件工程师(iOS、android):30k~60k;

    数据科学家:30k~60k;

    前端工程师:15~50k;

    滴滴:

    AI工程师(自动驾驶):30k~60k,15薪;

    软件开发工程师:30k~60k;

    数据科学家:20k~100k;

    前端工程师:30k~70k;

    大疆:

    机器学习算法工程师(智能驾驶方向):25k~50k;

    前端工程师:12k~40k,部分岗位15薪;

    后台开发工程师:15k~25k;

    信息安全专家:40k~70k,15薪;

    商汤:

    前端架构师:35k~60k,15薪;

    高级系统开发工程师:30k~70k;

    前端开发工程师:15k~35k,15薪;

    后端开发工程师:20k~40k,15薪;

    事实上,如果汇率不换算的话,国外的软件工程师薪资在10万美元~30万美元不等,与国内的薪资在数字上相差不大(考虑消费水平)。而国外机器学习工程师相关的年薪,则在11万~21万美元之间,数字上甚至会比国内的普遍更低。

     

    那么程序员的薪资水平到底有多高?

    根据相关资料显示:

    目前程序员的薪资水平(年薪)主要集中在 5-25 万之间,占比高达 67.2%。

    年薪在 5-10 万的程序员占比为 19.4%,

    年薪在 10-15 万的程序员占比为 21.6%。

    年薪在 15-20 万的程序员占比为 15.8%。

    年薪在 20-25 万的程序员占比为 10.4%。

    年薪在 25-30 万的程序员占比为 7.6%。

    此外,年薪在 30 万及以上的程序员占比为 15.2%,年薪在 5 万以下的占比仅为 10.1%。

     

    从资料来看,程序员的薪资水平跟很多其他行业相比确实是高薪行业,目前其平均年薪已经达到了15万以上,但殊不知与高薪相对应的是工作成本问题。

    比如说马云曾经在阿里内部的交流活动上提出的996(9点钟上班,9点钟下班,一周工作6天),其实是很多互联网公司程序员的工作现状,还有更甚者是“007”的工作状态,而且这种状态目前来看是很普遍的存在。

     

    大概就是这么个情况吧,看到这里你是不是对“程序员”又有了一点新的认知呢~

    如果你对互联网行业感兴趣,或有兴趣成为一名软件工程师,想改变目前的工作状态,想月薪过万,大门随时为你敞开,我们在这里等你们来学习哦!“点击链接”加入C语言/C++企鹅圈,这里还有一些你可能不知道的趣事分享哟。

    展开全文
  • 当程序员具备了抽象思维

    万次阅读 2021-03-22 14:32:46
    简介: 若想捉大鱼,就得潜入深渊。深渊里的鱼更有力,也更纯净。硕大而抽象,且非常美丽。 ...但我们即看不到程序如何被执行,也看不到 0101 是如何被 CPU 处理的。 我们工程师每天都要动用...

    简介: 若想捉大鱼,就得潜入深渊。深渊里的鱼更有力,也更纯净。硕大而抽象,且非常美丽。

    作者:张建飞

     

    若想捉大鱼,就得潜入深渊。深渊里的鱼更有力,也更纯净。硕大而抽象,且非常美丽。——大卫·林奇

     

     

    前言

     

    抽象思维是我们工程师最重要的思维能力。因为软件技术 本质上就是一门抽象的艺术。我们的工作是存思维的“游戏”,虽然我们在使用键盘、显示器,打开电脑可以看到主板、硬盘等硬件。但我们即看不到程序如何被执行,也看不到 0101 是如何被 CPU 处理的。

     

    我们工程师每天都要动用抽象思维,对问题域进行分析、归纳、综合、判断、推理。从而抽象出各种概念,挖掘概念和概念之间的关系,对问题域进行建模,然后通过编程语言实现业务功能。所以,我们大部分的时间并不是在写代码,而是在梳理需求,理清概念。当然,也包括尝试看懂那些“该死的、别人写的”代码。

     

    在我接触的工程师中,能深入理解抽象概念的并不多,能把抽象和面向对象、架构设计进行有机结合,能用抽象思维进行问题分析、化繁为简的同学更是凤毛麟角。

     

    对于我本人而言,每当我对抽象有进一步的理解和认知,我都能切身感受到它给我在编码和设计上带来的质的变化。同时,感慨之前对抽象的理解为什么如此肤浅。如果时间可以倒流的话,我希望我在我职业生涯的早期,就能充分意识到抽象的重要性,能多花时间认真的研究它,深刻的理解它,这样应该可以少走很多弯路。

     

    什么是抽象

     

    关于抽象的定义,百度百科是这样说的:

     

    抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程。具体地说,抽象就是人们在实践的基础上,对于丰富的感性材料通过去粗取精、去伪存真、由此及彼、由表及里的加工制作,形成概念、判断、推理等思维形式,以反映事物的本质和规律的方法。实际上,抽象是与具体相对应的概念,具体是事物的多种属性的总和,因而抽象亦可理解为由具体事物的多种属性中舍弃了若干属性而固定了另一些属性的思维活动。[1]

     

    Wikipedia 的解释是:

     

    抽象是指为了某种目的,对一个概念或一种现象包含的信息进行过滤,移除不相关的信息,只保留与某种最终目的相关的信息。例如,一个皮质的足球,我们可以过滤它的质料等信息,得到更一般性的概念,也就是球。从另外一个角度看,抽象就是简化事物,抓住事物本质的过程。[2]

     

    简单而言,“抽”就是抽离,“象”就是具象,字面上理解抽象,抽象的过程就是从“具象”事物中归纳出共同特征,“抽取”得到一般化(Generalization)的概念的过程。英文的抽象——abstract 来自拉丁文 abstractio,它的原意是排除、抽出。

     

    为了更好的方便你理解抽象,让我们先来看一幅毕加索的画,如下图所示,图的左边是一头水牛,是具象的;右边是毕加索画,是抽象的。怎么样,是不是感觉自己一下子理解了抽象画的含义。

    image.png

     

    可以看到,抽象牛只有几根线条,不过这几根线条是做了高度抽象之后的线条,过滤了水牛的绝大部分细节,保留了牛最本质特征,比如牛角,牛头,牛鞭、牛尾巴等等。这种对细节的舍弃使得“抽象牛”具有更好的泛化(Generalization)能力。

     

    可以说,抽象更接近问题的本质,也就是说所有的牛都逃不过这几根线条。

     

    抽象和语言是一体的

     

    关于抽象思维,我们在百度百科上可以看到如下的定义:

     

    抽象思维,又称词(概念)的思维或者逻辑思维,是指用词(概念)进行判断、推理并得出结论的过程。抽象思维以词(概念)为中介来反映现实。这是思维的最本质特征,也是人的思维和动物心理的根本区别。[3]

     

    之所以把抽象思维称为词思维或者概念思维,是因为语言和抽象是一体的。当我们说“牛”的时候,说的就是“牛”的抽象,他代表了所有牛共有的特征。同样,当你在程序中创建 Cow 这个类的时候,道理也是一样。在生活中,我们只见过一头一头具象的牛,“牛”作为抽象的存在,即看不见也摸不着。

     

    这种把抽象概念作为世界本真的看法,也是古希腊哲学家柏拉图的最重要哲学思想。柏拉图认为,我们所有用感觉感知到的事物,都源于相应的理念。他认为具体事物的“名”,也就是他说的“理念世界”才是本真的东西,具体的一头牛,有大有小,有公有母,颜色、性情、外形各自不同。因此我们不好用个体感觉加以概括,但是这些牛既然都被统称为“牛”,则说明它们必然都源于同一个“理念”,即所谓“牛的理念”或者“理念的牛”,所以它们可以用“牛”加以概括。尚且不论“理念世界”是否真的存在,这是一个哲学问题,但有一点可以确定,我们的思考和对概念的表达都离不开语言。[4]

     

    这也是为什么,我在做设计和代码审查(Code Review)的时候,会特别关注命名是否合理的原因。因为命名的好坏,在很大程度上反映了我们对一个概念的思考是否清晰,我们的抽象是否合理,反应在代码上就是,代码的可读性、可理解性是不是良好,以及我们的设计是不是到位。

     

    有人做过一个调查,问程序员最头痛的事情是什么,通过 Quora 和 Ubuntu Forum 的调查结果显示,程序员最头疼的事情是命名。如果你曾经为了一个命名而绞尽脑汁,就不会对这个结果感到意外。

     

    就像 Stack Overflow 的创始人 Joel Spolsky 所说的:“起一个好名字应该很难,因为,一个好名字需要把要义浓缩在一到两个词。(Creating good names is hard, but it should be hard, because a great name captures essential meaning in just one or two words)。”

     

    是的,这个浓缩的过程就是抽象的过程。我不止一次的发现,当我觉得一个地方的命名有些别扭的时候,往往就意味着要么这个地方我没有思考清楚,要么是我的抽象弄错了。

     

    关于如何命名,我在《代码精进之路》里已经有比较详尽的阐述,这里就不赘述了。

     

    我想强调的是,语言是明晰概念的基础,也是抽象思维的基础,在构建一个系统时,值得我们花很多时间去斟酌、去推敲语言。在我做过的一个项目中,就曾为一个关键实体讨论了两天,因为那是一个新概念,尝试了很多名字,始终感觉到别扭、不好理解。随着我们讨论的深入,对问题域理解的深入,我们最终找到了一个相对比较合适的名字,才肯罢休。

     

    这样的斟酌是有意义的,因为明晰关键概念,是我们设计中的重要工作。虽然不合理的命名、不合理的抽象也能实现业务功能。但其代价就是维护系统时需要极高的认知负荷。随着时间的推移,就没人能搞懂系统的设计了。

     

    抽象的层次性

     

    回到毕加索的抽象画,如下图所示,如果映射到面向对象编程,抽象牛就是抽象类(Abstract Class),代表了所有牛的抽象。抽象牛可以泛化成更多的牛,比如水牛、奶牛、牦牛等。每一种牛都代表了一类(Class)牛,对于每一类牛,我们可以通过实例化,得到一头具体的牛实例(Instance)。

     

    image.png

     

    从这个简单的案例中,我们可以到抽象的三个特点:

     

    1. 抽象是忽略细节的。抽象类是最抽象的,忽略的细节也最多,就像抽象牛,只是几根线条而已。在代码中,这种抽象可以是 Abstract Class,也可以是 Interface。

     

    2. 抽象代表了共同性质。类(Class)代表了一组实例(Instance)的共同性质,抽象类(Abstract Class)代表了一组类的共同性质。对于我们上面的案例来说,这些共同性质就是抽象牛的那几根线条。

     

    3. 抽象具有层次性。抽象层次越高,内涵越小,外延越大,也就是说它的涵义越小,泛化能力越强。比如,牛就要比水牛更抽象,因为它可以表达所有的牛,水牛只是牛的一个种类(Class)。

     

    抽象的这种层次性,是除了抽象概念之外,另一个我们必须要深入理解的概念,因为小到一个方法要怎么写,大到 一个系统要如何架构,以及我们后面第三章要介绍的结构化思维,都离不开抽象层次的概念。

     

    在进一步介绍抽象层次之前,我们先来理解一下外延和内涵的意思:

     

    抽象是以概念(词语)来反映现实的过程,每一个概念都有一定的外延和内涵。概念的外延就是适合这个概念的一切对象的范围,而概念的内涵就是这个概念所反映的对象的本质属性的总和。例如“平行四边形”这个概念,它的外延包含着一切正方形、菱形、矩形以及一般的平行四边形,而它的内涵包含着一切平行四边形所共有的“有四条边,两组对边互相平行”这两个本质属性。

     

    一个概念的内涵愈广,则其外延愈狭;反之,内涵愈狭,则其外延愈广。例如,“平行四边形”的内涵是“有四条边,两组对边互相平行”,而“菱形”的内涵除了这两条本质属性外,还包含着“四边相等”这一本质属性。“菱形”的内涵比“平行四边形”的内涵广,而“菱形”的外延要比“平行四边形”的外延狭。

     

    所谓的抽象层次就体现在概念的外延和内涵上,这种层次性,基本可以体现在任何事物上,比如一份报纸就存在多个层次上的抽象,“出版品”最抽象,其内涵最小,但外延最大,“出版品”可以是报纸也可以是期刊杂志等。

     

    1. 一个出版品
    2. 一份报纸
    3. 《旧金山纪事报》
    4. 5 月 18 日的《旧金山纪事报》

     

    当我要统计美国有多少个出版品,那么就要用到最上面第一层“出版品”的抽象,如果我要查询旧金山 5月18日当天的新闻,就要用到最下面第四层的抽象。

     

    每一个抽象层次都有它的用途,对于我们工程师来说,如何拿捏这个抽象层次是对我们设计能力的考验,抽象层次太高和太低都不行。

     

    比如,现在要写一个水果程序,我们需要对水果进行抽象,因为水果里面有红色的苹果,我们当然可以建一个 RedApple 的类,但是这个抽象层次有点低,只能用来表达“红色的苹果”。来一个绿色的苹果,你还得新建一个 GreenApple 类。

     

    为了提升抽象层次,我们可以把 RedApple 类改成 Apple 类,让颜色变成 Apple 的属性,这样红色和绿色的苹果就都能表达了。再继续往上抽象,我们还可以得到水果类、植物类等。再往上抽象就是生物、物质了。

     

    你可以看到,抽象层次越高,内涵越小,外延越大,泛化能力越强。然而,其代价就是业务语义表达能力越弱。

     

    image.png

     

    具体要抽象到哪个层次,要视具体的情况而定了,比如这个程序是专门研究苹果的可能到 Apple 就够了,如果是卖水果的可能需要到 Fruit,如果是植物研究的可能要到 Plant,但很少需要到 Object。

     

    我经常开玩笑说,你把所有的类都叫 Object,把所有的参数都叫 Map 的系统最通用,因为 Object 和 Map 的内涵最小,其延展性最强,可以适配所有的扩展。从原理上来说,这种抽象也是对的,万物皆对象嘛。但是这种抽象又有什么意义呢?它没有表达出任何想表达的东西,只是一句正确的废话而已。

     

    越抽象,越通用,可扩展性越强,然而其语义的表达能力越弱。越具体,越不好延展,然而其语义表达能力很强。所以,对于抽象层次的权衡,是我们系统设计的关键所在,也是区分普通程序员和优秀程序员的关键所在。

     

    软件中的分层抽象无处不在

     

    越是复杂的问题越需要分层抽象,分层是分而治之,抽象是问题域的合理划分和概念语义的表达。不同层次提供不同的抽象,下层对上层隐藏实现细节,通过这种层次结构,我们才有可能应对像网络通信、云计算等超级复杂的问题。

     

    网络通信是互联网最重要的基础实施,但同时它又是一个很复杂的过程,你要知道把数据包传给谁——IP协议,你要知道在这个不可靠的网络上出现状况要怎么办——TCP 协议。有这么多的事情需要处理,我们可不可以在一个层次中都做掉呢?当然是可以的,但显然不科学。因此,ISO制定了网络通信的七层参考模型,每一层只处理一件事情,低层为上层提供服务,直到应用层把HTTP、FTP等方便理解和使用的协议暴露给用户。

     

    image.png

     

    编程语言的发展史也是一个典型的分层抽象的演化史。

     

    机器能理解的只有机器语言,即各种二进制的 01 指令。如果我们采用 01 的输入方式,其编程效率极低(学过数字电路的同学,体会下用开关实现加减法)。所以我们用汇编语言抽象了二进制指令。

     

    然而汇编还是很底层,于是我们用 C 语言抽象了汇编语言。而高级语言 Java 是类似于 C 这样低级语言的进一步抽象,这种逐层抽象极大的提升了我们的编程效率。

     

    image.png

     

    重复代码是抽象的缺失

     

    如果说抽象的本质是共性的话,那么我们代码中的重复代码,是不是就意味着抽象的缺失呢?

    //取默认搜索条件
    List<String> defaultConditions = searchConditionCacheTunnel.getJsonQueryByLabelKey(labelKey);
    for(String jsonQuery : defaultConditions){
      jsonQuery = jsonQuery.replaceAll(SearchConstants.SEARCH_DEFAULT_PUBLICSEA_ENABLE_TIME, String.valueOf(System.currentTimeMillis() / 1000));
      jsonQueryList.add(jsonQuery);
    }
    //取主搜索框的搜索条件
    if(StringUtils.isNotEmpty(cmd.getContent())){
        List<String> jsonValues = searchConditionCacheTunnel.getJsonQueryByLabelKey(SearchConstants.ICBU_SALES_MAIN_SEARCH);
        for (String value : jsonValues) {
        String content = StringUtil.transferQuotation(cmd.getContent());
        value = StringUtil.replaceAll(value, SearchConstants.SEARCH_DEFAULT_MAIN, content);
          jsonQueryList.add(value);
      }
    }

     

    是这样的,重复代码是典型的代码坏味道,其本质问题就是抽象的缺失。因为我们 Ctrl+C 加 Ctrl+V 的工作习惯,导致没有对共性代码进行抽取;或者虽然抽取了,只是简单的用了一个 Util 名字,没有给到一个合适的名字,没有正确的反应这段代码所体现的抽象概念,都属于抽象不到位。

     

    有一次,我在 Review 团队代码的时候,发现有一段组装搜索条件的代码,在几十个地方都有重复。这个搜索条件还比较复杂,是以元数据的形式存在数据库中,因此组装的过程是这样的:

     

    • 首先,我们要从缓存中把搜索条件列表取出来;
    • 然后,遍历这些条件,将搜索的值填充进去;

     

     

    简单的重构无外乎就是把这段代码提取出来,放到一个Util类里面给大家复用。然而我认为这样的重构只是完成了工作的一半,我们只是做了简单的归类,并没有做抽象提炼。

     

    简单分析,不难发现,此处我们是缺失了两个概念:一个是用来表达搜索条件的类——SearchCondition;另一个是用来组装搜索条件的类——SearchConditionAssembler。只有配合命名,显性化的将这两个概念表达出来,才是一个完整的重构。

     

    重构后,搜索条件的组装会变成一种非常简洁的形式,几十处的复用只需要引用SearchConditionAssembler就好了。

    public class SearchConditionAssembler {
        public static SearchCondition assemble(String labelKey){
            String jsonSearchCondition =  getJsonSearchConditionFromCache(labelKey);
            SearchCondition sc = assembleSearchCondition(jsonSearchCondition);
            return sc;
        }
    }

     

    由此可见,提取重复代码只是我们重构工作的第一步。对重复代码进行概念抽象,寻找有意义的命名才是我们工作的重点。

     

    因此,每一次遇到重复代码的时候,你都应该感到兴奋,想着这是一次锻炼抽象能力的绝佳机会,当然,测试代码除外。

     

    强制类型转换是抽象层次有问题

     

    面向对象设计里面有一个著名的 SOLID 原则是由 Bob 大叔(Robert Martin)提出来的,其中的 L 代表 LSP,就是 Liskov Substitution Principle(里氏替换原则)。简单来说,里氏替换原则就是子类应该可以替换任何父类能够出现的地方,并且经过替换以后,代码还能正常工作。

     

    思考一下,我们在写代码的过程中,什么时候会用到强制类型转换呢?当然是 LSP 不能被满足的时候,也就是说子类的方法超出了父类的类型定义范围,为了能使用到子类的方法,只能使用类型强制转换将类型转成子类类型。

     

    举个例子,在苹果(Apple)类上,有一个 isSweet() 方法是用来判断水果甜不甜的;西瓜(Watermelon)类上,有一个 isJuicy() 是来判断水分是否充足的;同时,它们都共同继承一个水果(Fruit)类。

     

    此时,我们需要挑选出甜的水果和有水分的习惯,我们会写一个如下的程序:

     

    public class FruitPicker {
    ​
        public List<Fruit> pickGood(List<Fruit> fruits){
            return fruits.stream().filter(e -> check(e)).
                    collect(Collectors.toList());
        }
    ​
        private boolean check(Fruit e) {
            if(e instanceof Apple){
                if(((Apple) e).isSweet()){
                    return true;
                }
            }
            if(e instanceof Watermelon){
                if(((Watermelon) e).isJuicy()){
                    return true;
                }
            }
            return false;
        }
    }

     

    因为pick方法的入参的类型是 Fruit,所以为了获得 Apple 和 Watermelon 上的特有方法,我们不得不使用 instanceof 做一个类型判断,然后使用强制类型转换转成子类类型,以便获得他们的专有方法,很显然,这是违背了里式替换原则的。

     

    这里问题出在哪里?对于这样的代码我们要如何去优化呢?仔细分析一下,我们可以发现,根本原因是因为 isSweet 和 isJuicy 的抽象层次不够,站在更高抽象层次也就是 Fruit 的视角看,我们挑选的就是可口的水果,只是具体到苹果我们看甜度,具体到西瓜我们看水分而已。

     

    因此,解决方法就是对 isSweet 和 isJuicy 进行抽象,并提升一个层次,在 Fruit 上创建一个 isTasty() 的抽象方法,然后让苹果和西瓜类分别去实现这个抽象方法就好了。

     

    image.png

     

    下面是重构后的代码,通过抽象层次的提升我们消除了 instanceof 判断和强制类型转换,让代码重新满足了里式替换原则。抽象层次的提升使得代码重新变得优雅了。

     

    public class FruitPicker {    
    public List<Fruit> pickGood(List<Fruit> fruits){        
    return fruits.stream().filter(e -> check(e)).                collect(Collectors.toList());    }    
    //不再需要instanceof和强制类型转换    p
    rivate boolean check(Fruit e) {        
    return e.isTasty();    }}

     

    所以,每当我们在程序中准备使用 instanceof 做类型判断,或者用 cast 做强制类型转换的时候。每当我们的程序不满足 LSP 的时候。你都应该警醒一下,好家伙,这又是一次锻炼抽象能力的绝佳机会。

     

    如何提升抽象思维能力

     

    抽象思维能力是我们人类特有的、与生俱来的能力,除了上面说的在编码过程中可以锻炼抽象能力之外,我们还可以通过一些其他的练习,不断的提升我们的抽象能力。

     

    多阅读

     

    为什么阅读书籍比看电视更好呢?因为图像比文字更加具象,阅读的过程可以锻炼我们的抽象能力、想象能力,而看画面的时候会将你的大脑铺满,较少需要抽象和想象。

    这也是为什么我们不提倡让小孩子过多的暴露在电视或手机屏幕前的原因,因为这样不利于他抽象思维的锻炼。

     

    抽象思维的差别让孩子们的学习成绩从初中开始分化,许多不能适应这种抽象层面训练的,就去读技校了,因为技校比大学会更加具象:车铣刨磨、零部件都能看得见摸得着。体力劳动要比脑力劳动来的简单。

    多总结沉淀

     

    小时候不理解,语文老师为什么总是要求我们总结段落大意、中心思想什么的。现在回想起来,这种思维训练在基础教育中是非常必要的,其实质就是帮助学生提升抽象思维能力。

     

    记录也是很好的总结习惯。就拿读书笔记来说,最好不要原文摘录书中的内容,而是要用自己的话总结归纳书中的内容,这样不仅可以加深理解,而且还可以提升自己的抽象思维能力。

     

    我从四年前开始系统的记录笔记,做总结沉淀,构建自己的知识体系。这种思维训练的好处显而易见,可以说我之前写的《从码农到工匠》和现在正在写的《程序员必备的思维能力》都离不开我总结沉淀的习惯。

    命名训练

     

    每一次的变量命名、方法命名、类命名都是一次难得的抽象思维训练机会,前面已经说过了,语言和抽象是一体的,命名的好坏直接反应了我们的问题域思考的是否清晰,反映了我们抽象的是否合理。

     

    现实情况是,我们很多的工程师常常忽略了命名的重要性,只要能实现业务功能,名字从来就不是重点。

     

    实际上,这是对系统的不负责任,也是对自己的不负责任,更是对后期维护系统的人不负责任。写程序和写文章有很大的相似性,本质上都是在用语言阐述一件事情。试想下,如果文章中用的都是些词不达意的句子,这样的文章谁能看得懂,谁又愿意去看呢。

     

    同样,我一直强调代码要显性化的表达业务语义,其中命名在这个过程中扮演了极其重要的角色。为了代码的可读性,为了系统的长期可维护性,为了我们自身抽象思维的训练,我们都不应该放过任何一个带有歧义、表达模糊、意不清的命名。

     

    领域建模训练

     

    对于技术同学,我们还有一个非常好的提升抽象能力的手段——领域建模。当我们对问题域进行分析、整理和抽象的时候,当我们对领域进行划分和建模的时候,实际上也是在锻炼我们的抽象能力。

     

    我们可以对自己工作中的问题域进行建模,当然也可以通过阅读一些优秀源码背后的模型设计来学习如何抽象、如何建模。比如,我们知道 Spring 的核心功能是 Bean 容器,那么在看Spring源码的时候,我们可以着重去看它是如何进行Bean管理的?它使用的核心抽象是什么?不难发现,Spring 是使用了 BeanDefinition、BeanFactory、BeanDefinitionRegistry、BeanDefinitionReader 等核心抽象实现了 Bean 的定义、获取和创建。抓住了这些核心抽象,我们就抓住了 Spring 设计主脉。

     

    除此之外,我们还可以进一步深入思考,它为什么要这么抽象?这样抽象的好处是什么?以及它是如何支持 XML 和 Annotation(注解)这两种关于 Bean 的定义的。

    这样的抽象思维锻炼和思考,对提升我们的抽象能力和建模能力非常重要。关于这一点,我深有感触,初入职场的时候,当我尝试对问题域进行抽象和建模的时候,会觉得无从下手,建出来的模型也感觉很别扭。

     

    然而,经过长期的、刻意的学习和锻炼之后,很明显可以感觉到我的建模能力和抽象能力都有很大的提升。不但分析问题的速度更快了,而且建出来的模型也更加优雅了。

     

    小结

     

    • 抽象思维是程序员最重要的思维能力,抽象的过程就是寻找共性、归纳总结、综合分析,提炼出相关概念的过程。

     

    • 语言和抽象是一体的,抽象思维也叫词思维,因为抽象的概念只能通过语言才能表达出来。

     

    • 抽象是有层次性的,抽象层次越高,内涵越小,外延越大,扩展性越好;反之,抽象层次越低,内涵越大,外延越小,扩展性越差,但语义表达能力越强。

     

    • 对抽象层次的拿捏,体现了我们的设计功力,视具体情况而定,抽象层次既不能太高,也不能太低。

     

    • 重复代码意味着抽象缺失,强制类型转换意味着抽象层次有问题,我们可以利用这些信号来重构代码,让代码重新变的优雅。

     

    • 我们可以通过刻意练习来提升抽象能力,这些练习包括阅读、总结、命名训练、建模训练等。

    原文链接

    本文为阿里云原创内容,未经允许不得转载。

    展开全文
  • 程序员这个工作对智商有要求,但是对基础知识和学历背景要求不那么高。如果你智商够用,无所谓你...直接去编写代码示例,而不阅读有关代码是如何工作的解释,这是一个失败的方法。你购买一本计算机图书的理由应该...
  • 打算当程序员↓ 程序员新手↓ 程序员初级水平↓ 程序员中等水平↓ 程序员高等水平↓ 程序员特等水平↓ 神↓
  • 毫无疑问,世人对程序员行业普遍存在的误区:1.程序员都是男性。2.程序员都是邋里邋遢,不修边幅,整天就穿一套衣服,一年都不会换一双鞋子……其实,我们的阵营里也有很多女孩纸,她们人品、衣品各个一流!今天就为...
  • 程序员如何当好面试者 如何当好面试者 经过对一些面试者的观察,如果有些方面做的更好一点,会大大增加面试的效率,提升通过面试的概率。希望即将参加面试的同学,能够从以下这些点得到帮助。 明确...
  • 程序员项目 本月在The Queue上 ,LinuxQuestions.org的josephj问: 我如何程序员加入我们的项目? 原始开发人员退出并且没有其他人上前时,我继承了一个用$ programming_language编码的项目。 它目前托管在...
  • 程序员如何当好面试官 今年面试的人比较多,加起来快一百人了。由于面试任务比较多,也有越来越多的小伙伴加入了面试官的行列。 总结一些面试相关的方法论,希望新晋面试官有些帮助,最终能高效面试...
  • 个中缘由大约为,对程序员来说,键盘的一大功能是为编码提供必要帮助,而编码为某一项目服务,编写的代码对该项目非常合适时,会有较大效率。 如何提高程序员的键盘使用效率呢?本文中从内部、外...
  • 如何当一个程序员

    2008-01-09 08:16:00
    [align=center]如何成为一名优秀的程序员?[/align] (一) 一位仁兄说的“程序员写的程序不是算法+语法 ,而是要能够满足用户需求的工 具”我非常赞同,要想达到用户需求就必须从各个方面来考虑如业务、人机交互 、...
  • 哪些人不适合当程序员

    千次阅读 2018-02-22 00:00:00
    所以人人都想当程序员。但是并不是每个人都能当好程序员。在你做出决定前还是先看看自己能不能当好程序员吧。可是什么样的人不适合当程序员呢?不要喝鸡汤,我们看看 Quora 上面是如何回答的。在全栈开发者 Ada
  • 所以人人都想当程序员。但是并不是每个人都能当好程序员。在你做出决定前还是先看看自己能不能当好程序员吧。可是什么样的人不适合当程序员呢?不要喝鸡汤,我们看看 Quora 上面是如何回答的。 什么样的人不适合...
  • 你预期的那一天,也许是害怕的那一天,终于来到了:从工程师的队伍里你被提拔到了软件项目领导或者团队领导的位置。这也许就是你选择的职业道路,或许你不太情愿,将就尝试一下。无论在哪种情况下,你都可能缺少...
  • 那么现在,中国的程序员们,总体收入水平如何呢?首先我们看程序员们对薪资水平的满意 度。 我们发现绝大多数 程序员 (近73%)对自己的薪资并不满意,这种普遍不满意的情绪有多少是主观预期过高,多少是客观...
  • 你预期的那一天,也许是你害怕的那一天,终于来到了:从工程师的队伍里,你被提拔到了软件项目领导或者团队领导即项目经理的位置。这也许就是你选择的职业道路,或许你不太情愿,将就尝试一下。无论在哪种情况下,...
  • 如何当好一个程序员

    2009-03-21 23:17:59
    《走出软件作坊》在《四套马车》一章中是这样描写程序员的: "程序员就是自我管理自己的任务、自己的进度、自己的质量,如果非要有人逼着提交文档,程序员还得自己写设计文档和帮助文档。软件因为没有说明文档,也...
  • 我从 11 岁开始就梦想成为一名黑客,一名真正的黑客,但那时我并没有非常高端的电脑,也没有电影里面出现的那种非常炫酷的...因为我想成为一名黑客,而不是只会敲代码的程序员。 我的黑客之旅启蒙于一本非常糟糕的书
  • 如何做好程序员

    2007-01-15 11:14:00
    你自己想出来再参考别人的提示,你就知道自己和别人思路的差异。 2. 初学者请不要看太多太多的书那会误人子弟的,先找本系统的学,很多人用了很久都是只对部分功能熟悉而已,不系统还是不够的。 3. 看帮助,不要...
  • 大家都知道我们程序员是一个长时间在电脑旁边的人类,我们的业余时间不多,周六日可能还加班。但是我们一定要抽出时间来维护自己的人脉管理。不是有那么一话嘛,天时 地利 人和 这三个在一起跳舞时,你就成功了!...
  • 因为是看的别人的,自己又懒就放上链接吧。 http://blog.csdn.net/csdnnews/article/details/78787775

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,778
精华内容 2,311
关键字:

如何当程序员