【本文為個人意見,不喜就噴吧!】
最近,同事問到我,『那時候為什么從PHP轉成Java?』,我想了很久,且撇開主觀上的原因,當初業務重構使用java確實有很多可以說道的地方。
槽點1:哪有最好的語言,只有最合適的語言
2017年的3月份,我所維護的業務,跑的是php,使用的是thinkphp3.2 框架。剛接手的時候,這個業務還是單機,還記得有同事笑道:『這台機厲害哈,單機一年能跑出200多萬的流水來!』我當然是一笑置之。可是隨着業務組擴展外部渠道,開始發展這個業務,我慢慢發現這樣子的系統很難搞:難維護,難擴展,難自定義,不穩定。這樣子的系統,每次改到支付功能,上線都是心虛的,就怕突然出現問題,影響用戶體驗。於是在一段煎熬的思索和過渡后,老大開始帶着我進行重構。最開始的一套方案,是准備放棄原有的tp 框架,轉而使用 yii2,但由於人手不夠,老大親自操刀,架起了一套 play1.4.3(業務端) + spring-mvc(后台管理) 的一套系統,所以,我也轉到了java。
我這里想說的是,一個項目選擇啥語言,需要考慮團隊的配置,不能上來就搞一套不切實際的東西,從實際出發,找到適合自己的語言。曾幾何時,我也覺得php是世界上最好的語言,還沒有之一,現在只覺得哪有最好的語言,只有最合適的語言。
......
槽點2:面向對象編程,而不是面向數組編程
也許你一定很想知道,如何才能完成從php 到 java 的轉身呢?
說實話,一開始的時候,確實很痛苦,基礎薄弱就不說了,精神上還有壓力,因為全世界都知道【你是寫java的 php程序員】。舉個特別糗的例子,剛剛寫spring-mvc 的時候,不知道如何接收10多個參數,於是我很活該的使用了map, 我當時想啊,這不就是我們php 的 $_GET 和 $_POST 么【想當然害死人呀!】。可是寫着寫着我就發現不妥了,首先,別人並不知道你的map里面有啥子參數;然后,從map取出來的值不一定有值,如果是null,還要做邏輯判斷,這樣子代碼又麻煩了。所以呀,雖然這個代碼順利上線了,也沒發生過大的故障,但是我一直把這份代碼當成我的【眼中釘,肉中刺】。后面我是知道了,其實用一個對象來接收這些參數,既優雅,有便於維護,可讀性也好。
下面,我把自己最恨的一段代碼貼出來,告誡小伙伴們,【別這樣子干啊】
// 控制器
@RequestMapping(value = "/list", method = RequestMethod.GET) @ResponseBody public AjaxResponse getOrderList(@RequestParam Map<String, String> searchMap) { return orderService.getListsData(searchMap); }
// 惡心的邏輯
/** * 解析搜索關鍵詞, 組裝matches * * @param matches * @param searchKey * @param searchVal * @return */ public Matches getMatchesBySearchMapEntry(Matches matches, String searchKey, String searchVal) { switch (searchKey) { case Properties.tradeType: if (Integer.parseInt(searchVal) > 0) { matches.eq(Columns.tradeType, searchVal); } break; case Properties.state: int state = Integer.parseInt(searchVal); if (state == 4) { matches.match("complete_status", 1); // 表示已完成 } else if (state == 3) { matches.match("order_status", 0); // 0 表示已下單 } else if (state == 1) { matches.match("order_status", 1); // 1 表示已支付 } else if (state == 2) { matches.match("order_status", 2); // 2 表示已退款 } break; case Properties.channelId: List<Long> belongIds = accountService.getChannelIdBelongThisUser(HttpSessionUtils.getUseAccountId()); if (belongIds == null) { if (GeneralUtil.isObjNotZero(searchVal)) { matches.match("channel_id", searchVal); } } else if (belongIds.size() > 0) { Long id = Long.parseLong(searchVal); if (belongIds.contains(id)) { matches.match("channel_id", id); } else { matches.match("channel_id", belongIds); } } break; case Properties.cepingId: if (GeneralUtil.isObjNotZero(searchVal)) { List<Long> cepingIds = scalePoolDao.findIdsByParentId(Long.parseLong(searchVal)); matches.match("ceping_id", cepingIds); } break; case Properties.orderNo: matches.match("order_no", searchVal); break; case Properties.openId: String userKey = userDao.getUserKeyByOpenidAndUserType(searchVal, 1); matches.match("user_key", userKey); break; case Properties.userKey: matches.match("user_key", searchVal); break; case Properties.createStartTime: // 下單時間 Date createStartTime = DateTimeHelper.timeFormatStringToDate(searchVal); matches.gte("create_time", createStartTime); break; case Properties.createEndTime: Date createEndTime = DateTimeHelper.timeFormatStringToDate(searchVal); matches.lte("create_time", createEndTime); break; case Properties.payStartTime: // 支付時間 Date payStartTime = DateTimeHelper.timeFormatStringToDate(searchVal); matches.gte("pay_time", payStartTime); break; case Properties.payEndTime: Date payEndTime = DateTimeHelper.timeFormatStringToDate(searchVal); matches.lte("pay_time", payEndTime); break; case Properties.userType: int userType = Integer.parseInt(searchVal); if (userType > 0) { matches.eq(Columns.userType, searchVal); } break; case Properties.buyType: int buyType = Integer.valueOf(searchVal); if (buyType > 0) { if (buyType == BuyType.DEFAULT_COPY_ORDER.getCode()) { buyType = 0; } matches.eq(Columns.buyType, buyType); } break; } return matches; }
我現在用又臭又長來形容,這樣子的code 既不方便閱讀,出問題了也不好排查。而且這個代碼,我還是放在個循環中來拼接的,可讀性之爛可想而知。唉,要是我如果有時間了,就把這段代碼改了。
其實呢,說了這么多,我就想說,包括我在內的部分 phper額,太過分依賴數組了。是啊,在php里面,沒有啥是一個數組搞不定的,如果有,那就倆個。我走心看了下其它業務線的php代碼,哎喲喂,好家伙。推送服務配置用數組,微信公眾號配置用數組,接受請求用數組,傳參用數組(個人最不喜歡的方式),好像數組少些,項目就不能正常運行了。
我並不是說不該用數組,但是數組確實不好維護。當我們思緒亂的時候,你根本記不清這個數組中有哪些參數,你也可能想不起這個return的對象有哪些對象,特別是return json的時候,如果一個數組不存在,這時候返回了null,這樣子返回的接口數據,對客戶端的同學來說就是一種災難。
槽點3:一包不掃,何以掃天下
除此之外,也是我最想吐槽的一點,就是php的命名空間和包管理。雖然php現在也有了composer,但是部分包載入時,還是需要做一下手動處理的,如果是一些小白的話,那久很尷尬了。相對於php呢,java就很成熟了,maven 一出,問題基本就解決了。而php的命名空間呢,我最不爽的一點是,明明一個包沒關聯上,項目居然還若無其事的走着,之前沒覺得咋樣,寫java后就覺得,這樣子特別不嚴謹,對於我這樣的強迫症者來說,不能接受!
還有就是,需要手動載入 擴展,關於這點,php做的不夠好
槽點4:定時任務
此外呢,php有一點做的不夠好的,定時任務!(且不說用swoole做定時任務哈,畢竟swoole還是需要點學習成本的呢!)
之前我很少用php做定時任務,如果要做的話,就要依賴linux系統crontab,或者用swoole 了。
但是在java里面,完全不是這樣子的體驗,在play 或者 spring-mvc ,完全就是一個job 就搞定了,哪里要這般麻煩!
槽點 5:必不可少的單元測試
然后呢,php 在單元測試方面比java 差挺多的。這里我不否認有idea 的功能,但是想要用phpunit 測試一個方法,我感覺千難萬難,但是在java里,很容易就實現了!除此之外,包括我在內的部分phper,很少寫單元測試,甚至有些壓根就不知道這是咋回事!我覺得這是個可怕的現象,這樣子的代碼,連自己這關都沒過,如何敢上線,如何能穩呢!基本上走過單元測試的代碼,基本不存在啥語法錯誤,這就是妥妥的保障啊!
槽點6:你debug都不用,就不要假裝在搬磚了
接下來, 包括我在內的部分phper 呢,很少去debug,有些甚至從來沒這么搞過。在那段維護 thinkphp的時間了,我開始使用phpstrom的debug,說實話,代碼質量,開發效率都有很大的提升!我實在不能再接受自己用 echo, var_dump 這樣子去調試代碼,這樣子會讓人覺得,這是個門外漢呢!
槽點7:php是世界上最好的語言
請放下這個想法,你會發現,無論是python,golang,java 都不比咱php差,你不知,只因你未接觸!
槽點8:php代碼打包功能弱
在寫java前呢,每次遇到要復用的php代碼呢,我都是直接copy,但是寫java 一段時間后,我就覺得java 這方面比較好了,我可以通過maven 對共用的包進行打包,放到另一個項目中去,這樣子既方便管理,又利於版本的迭代,省時省力!
好了,就到這里吧,接下來還會有一篇吐槽java的。