J2EE是Java程序员从新手进阶的一个必经之路。要体会所谓的工业级代码,就必须要融入和经历更为复杂的开发、部署环境,需要同更多的模块、组件做信息流交换,比较和使用不同的框架,逐一去琢磨和考察它们的必要性及优缺点。
这样一种进阶,注定了其过程必然是痛苦的。这不仅是因为你要掌控和关注的细节、模块一下子陡然攀升,更因为这些增加的细节和模块背后都蕴含着各种复杂的理论知识:网络、web、程序构建。如果再考虑到你要使用的计算机,从一台PC变成多台服务器的交互,而部署环境从一直使用的eclipse自动化,变成多台Linux的部署,各种不适合不理解一下子都全部爆发,实在是巨大的挑战。
还记得当初最开始学习J2EE的时候,没用到一个月时间,就从入门走向了放弃。太多繁杂的部署和配置文件,理论知识又弄得来似是而非,更为要命的是当初根本没有什么软件工程的思想和意识,就简单粗暴地把这些繁琐工作扣上了一个“苦力”的帽子。并且自我安慰道:这么多复杂的零碎,不就是农民工搬砖么,果然是码农,我才不走这样的路。而完全没有意识到,这正是软件工程思想的匮乏所导致的。
正是因为事务性的东西太多,所以你才需要有出色的工程能力,运用你的谋篇布局将复杂的管理任务,通过各种工具、技巧和构架,把它们逐一消磨,从而让所有的细节都在自己的掌控之中,有条不紊地把一项浩繁的工程管理好。
我想,这一思想是一名优秀的软件工程师,也是J2EE入门所必备的 ,那就是控制复杂度是所有工程师最本质的任务。如果出现了细节太过繁杂,让自己深陷其中而无法解脱时,就一定要停下来跳出去思考,自己的整个工作流程应该做怎样的优化和改进,应该如何重构自己的流程和组织,从而把整个团队和工作流程理顺,发挥出他们应有的实力。
也即是,当你面对复杂问题的时候,你不会用消极的放弃或者粗暴的贬低来逃避复杂度失控的现实,而是会更加积极地去寻求改进方案,让自己更有条理更高效地完成任务。
怀揣着这一思想,就可以更为深入地探讨J2EE对新人的挑战和隐藏的深坑。在我看来学习Java,对新手来讲有这么几个坑:
1、不关注Java命令的运行
因为Eclipse的大而全,从而完全不会使用java的命令行,更不知道Java参数是些什么鬼。
或许一般的教科书会谈到一点如何通过命令行去运行Java,但紧接着,后面会补充道,有了Eclipse我们就不需要关注这些繁琐的细节。然后把Java命令行的东西永远地抛到脑后。
话是没错,有了Eclipse,谁还会去关注那堆交互极差的命令行?
可正如我在前面所说,当你运行的机器,从个人PC变成了远程端的Linux Server,你还能不关注命令行吗?甚至,让我问一个更为傻气但往往却能戳中新手痛点的一个问题:你使用的Linux Server端,很可能连图形界面都没有,请问如何使用你熟悉而又引以为傲的Eclipse呢?进一步,Eclipse都没有,请问你如何debug呢?又如何加断点,做你习以为常的单步调试,看着一条条的黄色加亮行debug?
从这个角度讲,你或许就能够理解:为什么单步调试并不总是一个好的方法。同样地,为什么你需要学习不同的调试技术,为什么需要学会怎么写log又如何依靠log来做debug。种种这些说法和论调,都会因为你使用工具、计算机的环境的改变而改变。
为什么你以前无法理解这些东西?
因为你以前只会使用一台PC,不会同远程端的Server打交道。更没有什么严肃的工作和需求,逼迫你同Server打交道。即便是在PC上安装了Linux,你或许也会困惑,为什么要用这堆东西呢?都说Linux好,可为什么自己感觉不到呢?原因就在于,Linux的通常使用环境,并不是作为个人PC来用的。它更多的是被当做Server端的操作系统来使用。你连使用场景都弄错了,那又怎么可能理解和体会Linux的好处?
回到我文章开头的那句话,我说“J2EE是Java程序员从新手进阶的一个必经之路”。那么现在,我能更好地给出这个论断的理由:因为有了J2EE相关项目的介入,你终于可以在一个真实需求的情境下,开始逐一发现你使用计算机的不同情况,进而真正去体会不同的论断和说法。例如,这个部分我提到的关于Eclipse的那些问题。
所以,所谓的为什么软件工程师需要实操、需要有真实的工作经验,为什么它们有时候比学校的理论来得重要。这就是因为,“工作”本身会为你提供一个真实的需求,而不是学校书本里自己臆想的一个伪需求,来让你一个个地去体会真实世界中的限制,进而再看到那些曾经在书本上但却不以为意的解决方案或工具时,便会有一种大梦初醒的感觉。
2、不知道Java运行的是什么
同样是因为过于依赖大而全的Eclipse,你逐渐会“忘记”,你运行Java的时候,到底在运行什么。或许,你早已在书本上看过,Java源代码需要经过编译变成class字节码,再由JVM把这堆字节码变成所在平台的机器码,进而这堆机械码被加载进内存运行。
可一旦要在Server端部署代码,新手的第一反应很可能就是我上面提到的:我的Eclipse在哪里?没有了Eclipse,我的Java怎么运行?
这其实就是完全没有真正理解上面说的Java运行机制。要运行起来Java,有了JVM、有了class文件就够了啊,你要Eclipse干嘛?
更进一步:OK,就算有class,我不需要通过Eclipse来做编译,可那些jar
包的依赖怎么玩儿?每次的jar
的依赖都是靠Eclipse来做的连接,没有了它,依赖关系怎么做?
这就又回到了第一部分提到的,根本不懂如何使用Java的命令行,更加不知道Java参数是些神马鬼。更本质来讲,你并不清楚Eclipse为你封装、简化的服务是些什么。你不了解,在Eclipse的背后,到底调动了那些命令来指挥你程序的运行,而这些调动的东西,如果不通过Eclipse又该通过什么方式被实现?
或许你可以辩解道,我曾经的编程工作确实不需要了解这些底层啊,因为了解了也没用,我还是会用Eclipse来简化我的工作。
所以咯,这就是学习J2EE的价值,强迫你弄懂这些细节,并且真的会在Server端的部署和开发中运用到。你不得不关注这些Java的依赖和build,从而更深入地理解Java的运行方式,进而才可以体会到为什么需要所谓的部署工具,从最简单的makefile,到比较流行的Ant、Maven等。
3、服务器端的Java入口在那儿
这是另一个有点玄乎的问题,但同样是因为长期在Eclipse环境下做开发导致的。要开发、测试你的程序,那么第一步,你至少要让它运行起来。那么,通常的做法是什么呢?
那当然是在Eclipse中点开某个具有main函数的java文件,然后点击Eclipse的运行按钮。
等到了J2EE的环境下,你会惊讶地发现,你竟然不知道如何将自己写的这堆代码给跑起来。一来当然是因为那个老问题,Server端没有Eclipse,我如何点击运行按钮?
再来,就算我知道可以通过Java命令行来开启一个Java程序的运行,可是,随便拿来一套J2EE的源代码,你竟然找不到一个类是有main函数的!
这可一下子就傻眼了,main函数都没有,你让我如何使用Java命令行把整个代码启动起来?
且等后面再回答这个问题,让我们再提一个有着相同理由的另一个问题。
4、数量繁多的配置文件和互补相关的源代码
让J2EE从新手走向放弃的另一大关键,就是“数量繁多的配置文件”和看起来“互不相关的源代码”。随便拿到一个J2EE的项目,就会发现各种xml和独特格式的文件满天飞。而随便找一个java文件读一段,就更加莫名其妙,似乎这个文件就是独立存在的,没有和别的java类的交互,声明自己有哪些变量、提供好自己的setter/getter,然后,就TM没有然后了!或许你以为这只是个特殊的文件,又接连抓过几个java文件来看,发现都是这样的风格。如此种种,当然会把一个newbie逼到抓狂。
你会因为无法把这些配置文件和类文件的功能连起来而抓狂,又同样因为要不断地切入切出各种种类繁多的文件类型而焦躁:搞这么多的文件类型的目的是什么?为什么需要它们、为什么需要这些独立又互不关联的文件?
要理解这个,就必须回到我们最开始说的关于工程师本质目标的思想:控制复杂度。
控制复杂度最基本的技术就是:分而治之,把一个复杂的问题分解为独立的子问题。
这是一个看起来简单,实则深不见底的技术。甚至可以这样夸张地说,所有的工程上控制复杂度的技术,都是对这一条的直接/间接地使用,又或是通过复杂的其它技术的辅助,来实践这一条技术。
将问题分而治之,有很多好处,其重要的就两条:
一是把问题分解后,你就可以不必直接面对一个大问题,从而可以更好地通过各个击破的方式将它解决。用最通俗的话来讲,就是饭要一口一口地吃。你不会直接把一大碗饭倒入嘴里,而是各个击破。
另一个是,当你把问题分解成独立的子问题后,那么复杂度就从系统性的关联复杂性,转变为了一个个小模块各自的复杂度。因为这个独立性,你才得以获得更好的稳定性。因为,就算是一个模块突然出现了问题,由于它的独立性,便可以只把损失限定在它这个模块里,不会影响到系统别的方面。以这样的方式,实实在在地把问题,限定在了一个更小的范围,从而控制住了复杂度。
那么,配置文件、互不相关的源文件、以及Server端的J2EE代码竟然没有main函数,其实都是一系列关于“设计模块、系统构架”的综合技术对这一思想的体现。它们无疑都是为“分而治之”控制复杂度而服务的。
所以,当你有了这些疑问时,其实是最好的学习设计模式和系统构架的机会。因为你有了一个真实场景,从而会立刻能感受到现实的限制条件对你的逼迫。此时,你将会为这些限制而焦头烂额。如果这时候,你去研究一下业界的成熟解决方案,就会很快发现它们都会和设计模式、系统设计搭上线。进而,你便能够势如破竹地理解清楚这些技术的精髓和存在的意义。
5、繁多的理论知识
由于J2EE涉及的环境很多,又是web应用,那么最基本的一点,便是网络、web、Server端的软件、Client端的软件他们之间有什么区别和联系。
还记得我最开始学习J2EE的时候,那简直是胡子眉毛一把抓,且不说把网络和web各种混淆,就连互联网产品和传统IT技术产品的区别都傻傻分不清楚。结果便是,各种概念混用。
而大部分的资料,会一个个地讲解browser的运行方式,讲解HTTP多么高深莫测,又提到Tomcat的Servlet多么本质,又或是Spring框架多么方便和利剑出鞘。可TM从来没有谁把他们串起来,好好地说明他们的职能位置在哪里,在一条生产流水线的位置在哪里。
或许,这是因为这个东西恰好处在一个微妙的尴尬之地:会的人,会觉得这个东西太过简单,拿出讲解或许没啥技术含量,有点不好意思。而不会的人呢,任凭他看多少细节的东西,反正就是不能把各个模块安放在正确的位置,便总是打不通任督二脉,干着急。
我想,我的一个重要任务,便是对这些关联性的东西,做一个细致的宏观review,反正我的脸皮比较厚,不怕diss。
理清楚了这些潜藏在newbie内心模糊的疑问,我们才能在下一篇开始比较系统的自顶向下的技术细节讨论。
不要小看这些问题的梳理。往往,一个newbie从入门走向放弃,就是因为感觉极端模糊,感觉到处都是问题,进而开始展开联想,怀疑是不是自己有问题。而如果能够理清楚自己的问题真正在哪里,就如同分而治之的思想那样,你便能够做到心中有数,只需要把不清晰的技术点,逐一攻破就好了,没什么天塌下来的大事情。
近期回顾
《前端技术的碎碎念》
《放眼望去都是痛》
《网络概念与快递物流》
如果你喜欢我的文章或分享,请长按下面的二维码关注我的微信公众号,谢谢!
更多信息交流和观点分享,可加入知识星球:
VIP赞赏专区: