回顾2020:一年的点点滴滴与收获
今年做了什么
Flag 验收
看回 2019年总结,又啪啪打脸了。。。果然计划赶不上变化,以后立 Flag 还是要慎重!
-
编制并出版一本书
-
设计并发布一个网站平台
-
做一个电台节目
-
去菲律宾读语言学校进修英语
-
考个无人机驾驶证(极飞农业无人机操作员考试)
不过倒是因为参与了《开源指北》的编写计划,算是共同协作出了一本电子书 (・-・*)
网站的话目前主要在维护两个,一个科技类的,一个人文类的。因为近期还要改版,所以暂时先不在这里公布了,等合适的时机再给大家宣传。
我自己喜欢听播客,所以老早就想我能不能做个电台节目给大家分享一下。但是由于懒… 内容定位也还没想好,所以迟迟没有落实下来,估计 2021 年也看不到了。不过因为参加硬禾学堂的 Funpack 活动,亲自出演拍了几个短视频,也算是在 B 站出道了~
然后因为疫情嘛,本来计划找时间去菲律宾语言学校进修一下,也被推迟了,2021 年再看看情况。不过今年一直有坚持在开言英语 App 上练习,也把抖音 App 训练成了英语学习神器,可以看到世界各地的情况,还蛮有用的。
无人机驾驶证这个被忽略了,之前想玩这个是因为家里是山区,想看看能不能将无人机跟当地的农业结合起来,促进当地经济发展,目前这个计划还得再搁置一下。
(  ̄ー ̄)
工作回顾
好啦!给自己挖的坑汇报完了,接下来讲讲其他事。
先说工作吧,今年在公司维护几套老旧代码,改得也是没脾气,然后参与了基于 RK3399 的通信终端,整合了一套 Linux 系统,增加了软件包管理和升级功能,还把 RT-Thread 引入到公司产品中,然后终于在 2020 年最后一个月离职了。。。
因为各方面都遇到了瓶颈,也学不到新的东西了,对我来说这真是太可怕了。所以决定换个环境,给自己一个短 gap,希望未来的路走得更坚实。
另外,今年参加了两个比赛,一个是 RT-Thread 应用创新设计大赛,基于国产 AT32 芯片做了个空气质量监测系统,拿了个三等奖;另一个是 STM32 创客秀,基于 STM32 NUCLEO 板做了几个节点,组成了一个分布式空气质量监测系统(fctc-air.cn),拿了个二等奖。可以看到,两个参赛作品其实是基于不同硬件平台的同一套系统,所以业余时间参加两个比赛也可以应付过来。这个项目的初衷,是因为我本人对空气质量非常敏感,环境湿度太高、粉尘太多、二氧化碳浓度过高都会影响我的状态,所以我想做一个设备来实时监测环境中的空气质量,帮助我改善空气。后来觉得这个项目其实还是蛮有用的,就把它开源出来,搭建了后台服务器和微信小程序,希望可以变成一个民间的空气质量监测系统,帮助每一个了解当地的空气质量,提醒大家要保护环境。
RT-Thread
今年在 RT-Thread 社区留下了浓重的一笔,首先是因为参加比赛嘛,用的系统平台就是 RT-Thread。以前做产品是基于某个 release 版本来增加自己的业务代码,改完就作为公司内部的代码来管理了,并不会与 RT-Thread 社区有过多接触。但是作为个人项目,我想着开发者还是应该用 master 分支跟社区保持同步,也在这个过程中慢慢地把自己修改的 BSP、组件和软件包提交给 RT-Thread 社区。当然在这个过程中会遇到很多问题,所以为了更方便与 RT-Thread 开发团队沟通,五月份的时候我就申请加入了 RT-Thread 社区工作小组。
后来因为贡献值较高,受邀参加了九月份 RT-Thread 的团建,在三亚浪了几天,体验了一直心心念念的潜水运动。同时也认识了 RT-Thread 的创始团队(熊大、邱祎、aozima、Leo、龙哥)和许多优秀的 RT-Thread 小伙伴,近距离了解到 RT-Thread 的团队氛围、社区运营、商业模式和发展规划。还是挺让人激动的!
十一月去上海参加 STM32 创客秀决赛,顺路去 RT-Thread 总部拜访了,跟龙哥、海靖聊了挺久的,学到很多东西。包括 RT-Thread 技术路线、行业发展方向、职业规划等等,这真是一个充满机遇与挑战的时代!我们要做的就是敢想敢干,保持前进!
2020 RT-Thread 年度开发者大会在深圳举行,我也受邀参加了,有幸跟各位大佬聚餐交流。和满老师、涛哥一起荣获 2020 RT-Thread 社区杰出贡献奖,非常开心~ 我知道社区里有许许多多优秀的开发者,也知道自己还有很多需要提升的地方,所以真的非常感谢社区伙伴的支持和 RT-Thread 团队的肯定。我会继续加油的,在为中国基础软件产业做贡献的同时提升自己,成就彼此。
生活
这几年其实一直在寻找工作和生活之间的平衡,因为现在还没成家嘛,所以经常把工作和生活搅在一起,感觉每天都在工作学习的状态。跟家人团聚的时间蛮少的,也很少陪表弟表妹外甥侄女,成长阶段还是需要多点关心。所以还是蛮想让自己尽快成长起来,摆脱地理位置的约束,能够在发展事业的同时兼顾生活。
我的生活其实挺单调的,对我来说,打球、游泳、做家务就是休息。工作之余,其实我就是个体育迷,周末能看场球赛就很开心得不得了,不过有时候又觉得挺浪费时间的,毕竟自己已经离开体育圈了,还是要专注一点。不过今年学会了*泳和棒球,也是很开心,以后有机会再慢慢解锁新运动技能吧。
今年疫情对普通老百姓的冲击挺大的,吸取前几年投资失败的教训,今年自己开始好好学习理财知识。不管广告做得多好,或者亲戚朋友推荐,都不要乱投资,不懂不投,钱的事情还是要自己看紧一点。跳出理工科的思维,发现从经济的角度看这个世界其实是挺有趣,可以看到一个更真实的世界。
还有,值得一提的是十月份参加了为其八周的 GoGreen! 可持续生活创变营,还参加了地球妈妈工作坊。认识了很多新朋友,学习了很多 IT 圈里没有的东西,也看到了许多不同的生活方式。所以,我想一定会有一种生活方式适合我,能够释放创造力、创造社会价值的同时让自己和家人好好生活。嗯,我要多点尝试,多点走出去寻找。
感觉 2020 年做了挺多事情的但是总结起来又好像没做什么......还有很大进步空间!明年还要做什么
FCTC-Air
完善 FCTC-Air 分布式空气质量监测系统。让它变成一个可以学习物联网相关技术知识,同时也能真正帮助大家关注空气质量的开源项目。
开源
今年参与编写《开源指北》其实也让我对开源软件有了更深入的理解,尤其是在充满变局的国际环境中,开源会给中国产业发展带来很大帮助。所以我也会继续关注开源项目,包括 RISC-V、RT-Thread 以及鸿蒙生态。另外,有一些之前使用过的开源项目停止维护了,感觉有点可惜,考虑接手过来维护。
创客
我真的很想成为一名真正的 Maker/Hacker,这将是我在技术道路上追求的目标,我希望自己很快能拥有将奇思妙想变成现实的能力。所以在 2021 年我还要加把劲,多折腾,补充数学、硬件、结构设计方面的短板,同时在嵌入式系统设计和物联网架构方面也要保持进步!
对了,2021年我要搭建一个创客空间,放飞自我。
学习
技术栈方面,2021年计划好好研究下 Rust 语言、数据分析和 AI 在端侧的实现。另外我会把过去工作、学习中的积累整理成一个技术类网站,作为个人总结,同时也分享给大家。具体是哪个网站我是不会告诉你们的 <(ˉ^ˉ)>
还有呀,之前囤了好多书还没来得及看,2021年安排一下,尽量写写读后感。
领导力
当然啦,总不能一直沉浸在学习的海洋里,不能为了学习而学习,所以我还需要多关注现实需求,从解决问题出发,学习相关的技术并将其应用起来。所以如果我真的想解决一些问题,除了掌握技能,还需要提升我的 leadership,搭建团队,联合各方资源才能做更大的事业。希望在 2021 年能多做一些尝试,提升一下表达能力和领导力。
健康
由于以前运动训练不当,加上这些年当程序员的劳累,以及不良的生活习惯(熬夜、久坐等等),这些年除了掉发之外还是有些小毛病。希望 2021 年能够好好调整一下,坚持锻炼身体,做好康复训练。为社会、为祖国、为全人类再战 50 年!
事业
前几年和朋友尝试创业,多少是因为焦虑,因为年少无知。经过几年的沉淀,现在已经想通了,如果不能年轻有为,那就大器晚成呗!
当然肯定会保留创业的想法,但是不着急。可能是很多年以后,也可能是明年。但一定是因为我们特别想解决某个社会问题,而我们刚好能够解决。
因为我之前在环保 NGO 工作过,所以一直有关注环保圈的动态。今年因为疫情,其实很多 NGO 都过得很艰难,所以 2021 年我会尝试将自己懂的技能和掌握的资源跟环保结合起来,做些有意思的事情。
还有… 大概就是这样了,2021年见。
图片来自:站酷 AJIU
寄语
去年的标题是——努力成为我认为我可以成为的人。虽然现在还没有达到我想要的状态,还没成为我想成为的人,但我会继续前进的!感谢过往许多失败的经历,因为它帮我鼓起勇气丢掉那些不必要的东西,不再伪装自己,成为真正的我,让我把所有精力放在对我来说最重要的事情上。如果我以前在其他地方成功了,那我就不会有这样的决心,你们也不会看到这篇文章。
谢谢您看到末尾!
无论成败,我都会保持热爱,热爱科学技术,热爱这个世界。我将投身到那真正属于我的领域,用双手创造价值。左手科技,右手人文;左手工作,右手生活。坚定信念,坚持学习,保持进步。新的一年,遇见更好的自己。
图片来自网络
Never give up on what you really want to do. The person with big dreams is more powerful than the one with all the facts.The future belongs to those who believe in the beauty of their dreams.
上一篇: 理解流程审批动作的简易指南
下一篇: 万亿垂直社交在微信之外突然崛起
推荐阅读
-
一年回顾与读吴军有感 - 来自硅谷的信
-
一年里的痛与挑战:分手、中介骗局、健康危机、亲人的离世、心爱物品遗失与被边缘化——2023年终回顾
-
2020回顾:神奇的一年,神奇的我:年终总结
-
回顾2020:一年的点点滴滴与收获
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面
-
2023年末回顾:一个23岁毕业生的求职挑战与收获——生活就像一盒五彩斑斓的巧克力,你永远无法预知下一个会是什么味道
-
我的终端组织与技术架构思考:一年来的探索与收获【专家分享】
-
回顾2020:DayDayUp,感慨良多的一年,激发了我珍惜生活的觉悟,揭示了努力与幸运的紧密联系