0%

从Python转向Java的一些感想

最近从Python转到了Java,写了一个多月,帮公司写了一个项目,谈谈感想。

主要分两方面,一个是Java本身,一个是spring全家桶。

首先谈谈从python切换到Java的一些感受。
这两门语言都是面向对象的,Java基础很快就上手了,学起来并不会觉得很困难,一开始也没觉得有什么很大的差异。到实际开始写项目的时候,差异就体现出来了,感受最明显的果然还是静态类型和动态类型的差别。

这里得先声明一点,我知道python也有一些类型检查的工具,大公司可能也有相应的规范,但至少我所在的公司没有,所以我也不知道这些工具能起到多大的作用。本文也只是以我个人的开发经验做的一些总结,并不是以踩python为目的。

我们知道函数是代码中非常重要的单元,理想的代码在高层次的逻辑中应当是以函数作为组织单位,同一个函数中应当只有一个抽象层级的逻辑。低层次的逻辑封装在更底层的函数内部,调用者只需要传参和获取结果,不需要关注具体实现细节。
而python的动态语言性质,会很容易诱导新手(比如我)写出破坏这种低耦合特性的代码。
一方面是类型的不确定性,不论参数还是结果,都有可能传个八竿子打不着关系的对象过来。这一点在python推出typing后稍微有所改善,但也只是起到提示作用,并没有约束效果。
如果接口处理的都是些基本类型或者封装好的类型还好,更要命的是,如果函数接收的是个字典、元组之类的,然后字典里嵌套了各种结构(就像我们Web API返回的复杂结构的JSON那样),或者元组里包含了不同类型的变量,然后用下标去取,这种情况下的代码可维护性基本为0了,鬼知道你会传个什么结构进来。事实上,我也确实在几个同事的项目里看过这种代码了,一个多层嵌套结构的字典或者数组,在几个函数内传了三四层,边传边改,而且变量名还一直变,到里头早就忘了这是个啥了(神奇的是其中一位同事以前还写过一两年的Java),幸好项目不大,如果是个大项目,不敢想象维护起来会是什么后果。

并且这种情况下,函数内外部都只能靠约定和信任来传参和接收结果,这样的话还谈何低耦合呢?不要拆分出一个函数可能还好点。我不知道有多少新手会犯这种错误,但是语言层面缺乏限制,又没有好的团队规范的情况下,必然会导致这种低可读性代码出现的可能性相对高很多,有了类型约束可以较为有效的减少这种情况发生的几率(但架不住有些人代码烂,静态语言也能给你写得跟动态的一样)

接着说说静态类型带来的麻烦,这个麻烦主要集中在无类型到有类型的转换上,具体场景通常为各种IO数据的处理,比如json,或者从数据库拿到的数据列表,这些用于传输的数据格式都是天生动态的。要在Java中使用,必然得想办法转化成有类型的,比如处理成POJO等等,通常会需要相应的数据解析工具(但是无论用什么工具,这个转换过程本质上都是基于传输双方的约定去进行的)。而在编写业务过程中,还需要用到不同框架与库来进行网络通信,每次需要处理序列化/反序列化的时候,都要去翻找对应框架的API,有些要配合Spring来使用还需要进行一堆繁琐的配置,相当麻烦。当然这方面主要还是Java这边的框架我不熟悉,写多了应该还是能克服的,不过相比动态类型要耗费更多时间是肯定的。

说完类型约束,在讨论spring全家桶之前,先说说我这两天接手一个离职同事的(Java Web)项目的经历。我上面一直在说静态类型的好处,结果把我同事的代码拉下来一看,看得我脑壳疼。好好一个Java,写得跟动态语言一样,满天飞的Object和Map。除此之外,到处是缺乏语义的命名,一堆list、entity、temp、map、xx1、xx2这种看不出是什么的名字,看几行就得回去确认下这个变量指代的是什么。而且不同抽象层级的代码也混在一起,业务层和表现层不分开来,写了一大段你以为他在处理什么复杂逻辑,其实他就是在拼装JSON。也算是另一种意义上的“事在人为”了。
后来我又回顾了自己的一些项目,虽然没他那么糟糕(真的没有),但类似的错误我代码里好像也有一些,但是自己写的时候并没有注意到这些问题。
由此我又得出另一个初步的结论,稍微读点别人的烂代码对提升自己代码质量还是有一定帮助的。如果光看自己代码,所有逻辑是自己写的,自然不会觉得难懂,也就很容易忽视很多缺陷。所以想要保证团队项目的代码质量与可维护性的话,我觉得Code Review应该是很有必要的。

好了,回头说说spring全家桶。这东西一开始真的把我搞得一脸懵逼(现在依旧懵逼)。
后来直接从spring boot上手,啃了好几天官方的文档,包括spring,springmvc,spring data这些,都简单过了一遍,才大致弄明白一些概念。随后又看了不少demo和开源项目,才磕磕碰碰地把之前一个python小项目用Java重新实现了一遍。
老实说,我还是没太明白spring这个IOC到底起到了什么实质作用,我知道是控制反转/依赖注入,把对象的生命周期和控制权交给spring来处理,我们负责接收就行了。但是我并没有直接感受到这样跟自己new一个会有多大的差别,带来了什么好处,是性能上的?还是扩展性上的?不知道,学的很浅,惭愧。

在项目开发过程中,接触到了分层架构的思想。这个要说是从spring学到的好像又不是很严谨,毕竟架构和设计模式这些东西是不局限于语言的。但比较奇怪的是我在写python web的时候,很少看到别人python项目也很少看到有按这个去设计的,而后来看过的Java项目代码,或多或少都是按这个结构来的。不过虽说大多数Java web项目都按照三层架构来设计的,但就像上面我提到的,同事项目的表现层和业务层逻辑界限模糊不清,比如在业务层拼装json等等。所以这东西还是看人。
总之,不管是不是从spring上学到的,但至少是我在这段时间写Java吸收到的一个设计思路。并且也可以应用到python web这边,让项目结构清晰很多。重新看了自己过去写的一些项目,发现很多地方也没做好逻辑的划分,便重新调整了代码布局,定制了一些规范,之后在网上搜索时看到这篇文章,发现里头很多规范和我做法几乎是一致的,可见我的思路多半是没有问题的。

以上就是我在过去一个多月以来,从python转到Java的一些感想和收获了,才疏学浅,若有不对的地方,欢迎指正。