物件
身在成都小微企業,前兩天面試深圳老牌金蝶公司。對我這個荒廢了三年光影的人來說,怎一個跨度之大了得?作為人我生第一次面試的,整個面試過程,只能用詭異來形容這次感受。而結尾也是迷迷糊糊中草草收場。
不是很好的開局
我我畢業就進了國企。畢業前,在我想象中,他是一個偉光正的形象。所以我抱著人生值得,未來可期的想法進去了。結果不懂事的我被暗中轉了外包。之後那就是段黑暗中的日子了。一個書記負責畫大餅及洗腦,一個負責催加班。主打一個職責分離,找人時方便推卸責任。而工資也是入職以來一動不動的8000多,我也因此悲觀,頹廢了三年,感覺受到了欺騙,怎麼是這樣的?世界觀崩塌了。整天就是行屍走肉的上下班,沒話可說,就這樣略去吧。
算了,學習其他的去了
這基本是我下班後唯一的學習和值得說的地方。生活總是先使人絕望,又去點燃人的希望,又讓人失望,再讓人希望,反反覆覆,這樣來訓練我的認知。作為工科生的我,關於自然的科學知識和計算機知識學了一大把,但關於人的社會知識卻沒有學。不知道社會險惡,所以碰到點事就繃不住了。
因此我進公司幾個月之後,就夥著同事,和上級鬧情緒,搞串聯,搞曠工。不過我們在專業的書記面前搞這些,豈不是太嫩了點?我在這期間讀列寧的《帝國主義是資本注意的最高階段》,《資本論》第一卷。還專門跑到中馬庫讀了很多小冊子,工人小說。後來又向前,讀更早的盧梭的《社會契約論》。這時的我更像是在無力的臆想,精神可嘉,戰鬥力拉跨。但遭受打擊卻催發了其他的東西。讀社會學怎麼能不讀哲學?
完敗的我又跑去讀哲學,《讀西方哲學史》,讀《理想國》,留意智者和形而上學的針鋒相對的觀點,現在看來都不無道理。略過中世紀,從笛卡爾的我思故我在開始瞭解,到後面形而上學的終點,讀《純粹理性批判》、《實踐理性批判》、《判斷力批判》,《精神現象學》。最後到了理性的崩塌後的三個解決方案,馬克思的異化理論、尼采的超人、弗洛伊德的精神分析。把馬克思和之前的哲學史串聯了起來。
從馬克思的《1844年經濟學哲學手稿》開始又轉到經濟學。從古希臘的奴隸經濟開始,到中世紀的莊園經濟,再到近代的資本主義。從英國重商主義開始,讀托馬斯孟的《貿易論》《論英國本土的公共福利》,到法國重農主義,讀《獻給國王和王后的政治經濟學》。最後到古典政治經濟學,讀英國威廉配第的《政治算術》、《獻給英明人士》、《賦稅論》、《貨幣略論》、法國布阿吉爾貝爾的《法國詳情》、魁奈的《經濟表》、亞當斯密的《國富論》、李嘉圖的《政治經濟學及賦稅原理》、最後到了西蒙斯第的經濟危機理論結束。
最後,當然就是馬克思的經濟理論了。這場經濟學冒險也讓我經濟學歷史串聯了起來。
走了算了
我人生加起來也沒讀過這麼多書,遇到這麼多針鋒相對而又各自明智的觀點。正印了那句“人是萬物的尺度”。我說不出具體的影響,但沒有這些知識,我可能還在渾渾噩噩。
到了去年過年,幾個親戚兄弟碰到一起,頓時激起了我的心思,社會形勢惡化不可逆轉,公司待遇惡化不可逆轉。人生沒有反途,不能在這坐以待斃,死耗下去了!
於是我今年過年後就開始努力學習,沒有一天荒廢。爭取把這三年落下的技術追回來。這樣從2月份到7月份,5個月時間,每天晚上4個小時學習,週末24個小時的學習。平時和同事暗中比較,技術已經超過不少了。是時候走了,離開這個傷心之地了。他們有家庭,這份工還算能餬口,而我沒家庭牽掛,只剩下點技術,這裡又缺少磨練和實踐,久了技術就忘了,走了。
面試
面試以騰訊語音會議的方式開始,時長大概40分鐘。聽聲音,是一箇中老年人事,一箇中青年技術。
首先是讓我自我介紹,我之前總結了一段自我介紹,基本上照著唸了一遍。這是我第一次面試,很緊張,感覺聲音有點發抖。沒有任何反映。
然後讓我介紹一下平時怎麼工作的,在團隊中扮演的角色。我對著準備的資料,回憶著總結了一下日常工作以及面對新專案時的組織小組工作方式。沒有任何反映。
接下來問“你的工作經歷和專案中遇到過哪些難題”。我說了一下剛開始那段時間用XSLT
生成doc文件,然後合併的經歷。然後技術人員就問我假如我有20個文件,要合成四個怎麼辦?我蒙了,我們那是一個資料檔案,要存檔的,分成四部分幹什麼?我提出了疑惑,他還是堅持問,並說,20個文件合成4個,每5個合併成1個,最後四個怎麼合併。我想了一會兒,我就說,你是想說多執行緒的問題嗎?那就執行緒同步唄。不過我們一般都使用非同步,而不是多執行緒。我感覺他沉默了一下,不知道是不是記錯了。
然後最近還遇到一個記憶體洩漏的問題,我起先以為是託管記憶體洩漏,但用記憶體診斷工具又沒發現異常。到現在也沒解決,只能一段時間就重啟。我在這方面也不懂太多。(這個我是真想找那個.net高階除錯一線碼農去問下)
他說那你說一下多執行緒的非同步的區別。我就說非同步是語法糖,會翻譯成狀態機,最後用執行緒池裡面的執行緒執行。多執行緒則是建立了一個新的執行緒。他問非同步怎麼回到原來的執行緒?我又懵了?為什麼非同步要回到原來的執行緒?(可能他是想問同步上下文?或者是他想問一發即忘和阻塞式的呼叫方式?)我就說非同步方法碰到耗時任務後,原執行緒就返回最上層的同步方法繼續向下執行了啊?而非同步方法中的程式碼會有新執行緒來接手(用並行堆疊工具可以觀察到這個過程),為什麼需要返回原來的執行緒?這整個非同步方法都會被交給新執行緒。這樣可以避免原執行緒阻塞(控制檯中才需要手動配置任務返回原執行緒。只有更新ui才需要返回原執行緒,但WPF中任務會自動返回原執行緒,但這也不需要我們特別指定啊?)因為他始終不正面提問,我始終不知道他想問什麼?這就是面試的方式嗎,詭異。
他然後問我看裡簡歷裡面寫你們用webform和mvc,那他們有什麼優缺點?我說我們用的不多,只中間用了一年,後面就轉向webapi加web專案了。他又問,那什麼是前後端分離?我又懵了?這怎麼回答?我想,後端寫webapi,前端寫html和js,js請求後端介面的資料重新整理頁面,標準的web開發流程,這還要回答什麼?我就說不明白你的意思。我感覺他又沉默了。他到底想問什麼呢?也許webform和mvc是用的服務端元件和razor,而webapi+html不用?這有什麼可說的嗎?難道他不是這個意思?好奇怪啊?
我看你簡歷寫了redis,redis是怎麼快取的?我說我們主要是快取主要用memorycache,redis還是主要用來存一些實時資料。我的話就是當時做一個簽到的介面,因為短時間內訪問量可能比較大,所以把redis作為訊息佇列,用來削峰。(他是想問有哪些資料型別嗎?)
他又接著問,MVVM是什麼?這下我激動了,就說MVVM的好處是增加了一個檢視模型VM,可以為UI建模,如何為UI建模,這是之前建模方法中沒有見過的。而UI易變,MVVM可以讓UI的變化不會影響到VM和Model。(也許還應該加上VM利於測試?我一緊張就忘了,不過我們到現在都沒寫過正規單元測試,存疑)
他問VM如何跟UI通訊,我說是透過命令command。他問具體是怎麼通訊,我一時間沒想明白,問是不是呼叫和傳參。他說都講一下。然後我說呼叫是透過datacontext(xaml檔案在訪問時透過建構函式那句InitializeComponent程式碼被例項化了,VM可以在這個過程中例項化,也可以透過構造注入到這個物件中,因此VM是透過委託呼叫的。一緊張也忘了說出來)
然後他問介面的資料變化怎麼通知到後端。我說是INotification這個介面(實際上叫INotifyPropertyChanged)。他問具體怎麼通知的?我想,介面的屬性是依賴屬性,透過將資料存到統一的一個私有靜態屬性中,透過屬性去訪問這個值,所以能知道資料的訪問。但是不是所有屬性都是依賴屬性啊。INotification介面原理沒搞清楚,沒回答上來。
然後人事問我,你們加班情況怎麼樣,我說我們是半個國企,很少加班。
面試差不多這就結束了。然後人事問我,你還有什麼想問的嗎?我想好多都答得不好,估計沒戲了。就說沒什麼想問的。結束得非常急迫,半分鐘不到。
至此,面試結束。
後續總結
-
第一個沒答上來的問題是前後端分離是什麼
這怪我不識廬山真面目,只緣身在此山中。基本上沒有寫過以前的麵條程式碼,一直都是前端後端分開寫。結果就忘了什麼是前後端分離了。這裡應該是要談web的歷史。最開始只有靜態html檔案。伺服器就是去去檔案,然後返回報文。到了動態網頁時期,因為後端介面返回的http報文,靜態網頁檔案也是伺服器響應的http報文,所以是可以程式碼拼字串,設定content-type來模擬一個靜態檔案的,這個時候只有後端。再後面一點有了模板引擎,razor,webform之類的,前端可以寫一些HTML+js了,但還是後端程式碼生成網頁需要的靜態檔案。而現在有了xhr和fetch,一般都是前端後端各寫各的。以後用blazor還是要回去。 -
第二個沒答上來的問題是wpf中INotifyPropertyChanged的原理
從寫法上來看,繼承INotifyPropertyChanged介面的VM具有一個事件public event PropertyChangedEventHandler PropertyChanged; PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
然後在屬性set中,觸發了此事件。到這裡為止還是很好理解。那麼應該是UI元素繫結到這個屬性時,訂閱了此事件,所以才能接到通知並更新介面。UI元素有個SetBinding方法,應該是例項化xaml檔案時,遇到了
{Bingding}
標記,這個SetBinding方法於是被呼叫,才建立了UI元素依賴屬性和VM的CLR屬性的binding關係。然後Binding
會偵聽實現了這個介面的物件的PropertyChanged
事件。這個物件更新屬性時,clr屬性中set中主動觸發了此事件,然後Binding偵聽到此事件,更新UI元素。
如果他又追問binding監聽了這個事件是怎麼取到資料,並傳遞給UI,通知UI變化的?我還要研究一下這個問題。
這個也比較簡單,因為就是事件訂閱,然後透過反射取資料來源的值。internal class MyBinding { /// <summary> /// 這一般是UI元素的屬性 /// </summary> public DependencyProperty dependency; public PropertyPath path; /// <summary> /// 一般是UI元素 /// </summary> public DependencyObject dependencyObject; public object source { get; set; } public MyBinding( DependencyObject dependencyObject, DependencyProperty dependency, object source, PropertyPath path) { if (source is INotifyPropertyChanged inpc) { inpc.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); } this.source = source; this.dependency = dependency; this.path = path; this.dependencyObject = dependencyObject; } private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) { //資料來源可能又多個屬性被繫結,檢查是不是繫結的那個屬性發生了變化 if (e.PropertyName==path.Path) { dependencyObject.SetValue(dependency, sender.GetType().GetProperty(e.PropertyName).GetValue(sender)); } } }
我來測試一下
TextInfo textInfo; public MyBindingTest() { InitializeComponent(); textInfo = new TextInfo() { Text = "TextInfo" }; MyBinding myBindin = new MyBinding(this.text, TextBlock.TextProperty, textInfo, new PropertyPath("Text")); } private void btn_Click(object sender, RoutedEventArgs e) { textInfo.Text = "newValue"; }
不同之處在於wpf的繫結時基於弱事件而我這裡是+=。我的MyBinding
類沒有繼承MarkupExtension
,所以沒法被xaml解析。但這裡暫時不研究了。 -
第三個沒答上來的問題,Redis是怎麼快取的,這問到我的知識盲區了。我下來去網上搜了一下。Redis快取有3種模式
- Cache Aside(旁路快取):旁路模式在讀取取時,優先取快取,沒有再取資料庫並重新整理快取。寫資料時則更新資料庫,再刪除舊快取。
這個模式其實我們MemoeyCache做快取時也是這麼幹的,只是忽略了寫的操作,不知道這叫旁路模式,給快取設定了過期時間就完了。這種模式缺點是存資料和刪除快取之間時間段內讀的資料和實際的不一致。 - Read/Write Through(讀寫穿透)的改進是搞了快取中間層,代替應用訪問資料庫。再中間層中進行資料庫讀寫。並且在寫資料的時候,以事務的方式更新快取和資料庫,避免資料不一致。缺點是更新資料庫這段時間,其他讀快取的阻塞了。
- Write Behind Caching(非同步快取寫入)在讀寫穿透的基礎上取消了事務,寫資料時優先更新快取,並在之後非同步的更新資料庫,這樣解決了寫資料這段時間裡,讀快取阻塞的問題。但缺點是寫入資料庫之前有人訪問資料庫的話,資料實際是不對的。
- Cache Aside(旁路快取):旁路模式在讀取取時,優先取快取,沒有再取資料庫並重新整理快取。寫資料時則更新資料庫,再刪除舊快取。
-
第四個沒答上來的問題是webform和mvc的優缺點,說實話,我兩者都沒怎麼用過。對webform的瞭解限於知道開發起來像winform,有服務端元件和檢視狀態。開發起來很快。缺點是WebForms傾向於生成較為笨重的HTML和ViewState,這可能會導致頁面載入速度慢,而且除錯複雜,不靈活。但我們實際用webform的時候都是一般事件處理程式ashx+aspx.cs後臺事件+ajax突過去得了,沒想過這玩意。也許我該做個demo看看了。
MVC裡面我還是第一次接觸到路由,這玩意確實比原來的webform那個路由方便。還有是實現了檢視和模型關注點分離。可以一定程度上前後端分離。其優點對於不熟悉的人同時也是缺點。
不管怎麼說,這兩個框架都是表現層框架,主要精力還是集中在UI上。 -
面試觀點
我和同學說了這事,他說我碰到的面試可能是喜歡聽聽你的知識面,然後挑著問的型別,掌控方在我手裡。而不是那種面試官需要明確面試者掌握了哪些知識,固定提問的型別。要發散思維,展示你的知識面。
他問了你很多自學的東西,這種記得不牢固是正常的。
還有,問你工作經歷那裡讓你繼續說是感覺還好,應該繼續下去。可視我總結的不夠,反而說不下去了。
他問你現在的加班情況,是考慮你能不能適應。像我這種回答人家未必會考慮。
關於工資,金蝶寫的是15-30K,像你這種3-5年的應該18-20K。但是我現在這家奇葩公司月薪才8900啊,就算加年終獎也才一萬,我怎麼敢想。而且我之前幾年一直沒考慮過離職,也不知道自己在人力市場上應該要多少,我說不出口。
追加
-
前後端分離是什麼意思
看了@過錯的評論,我上網去搜了一圈。總結出這樣一段話。職責分離並非一個具體的設計模式,而是一種設計原則
職責分離(Separation of Concerns,SoC)雖然不是嚴格意義上的設計模式,但它是軟體工程中的一種重要設計原則或思想。
它指的是將一個軟體系統分解為不同的部分,每個部分解決特定的任務或關注點,從而降低系統的複雜性並提高可維護性。
具體來說,職責分離強調以下幾點
單一職責原則(Single Responsibility Principle,SRP):一個類或模組應該專注於實現單一的功能或職責。這樣做不僅使得程式碼更加清晰和易於理解,而且在需要修改時也可以降低影響範圍,減少引入錯誤的可能性。
職責分離的實現可以依賴於多種設計模式,例如:
MVC(Model-View-Controller):將應用程式分為模型(資料和業務邏輯)、檢視(使用者介面)和控制器(處理使用者輸入和排程任務),實現了職責分離和程式碼重用。
MVVM(Model-View-ViewModel):在WPF和其他現代UI框架中使用的一種模式,透過資料繫結將檢視(View)與檢視模型(ViewModel)分離,使得UI設計和業務邏輯分開。(這確實和@過錯所說不差)前後端分離看起來是符合單一職責原則的軟體設計