<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Yang Lin on Medium]]></title>
        <description><![CDATA[Stories by Yang Lin on Medium]]></description>
        <link>https://medium.com/@yanglin_68397?source=rss-9d1ba7125c47------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*FwxSUGILt-DyQXM64JByLw.jpeg</url>
            <title>Stories by Yang Lin on Medium</title>
            <link>https://medium.com/@yanglin_68397?source=rss-9d1ba7125c47------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 11:53:10 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@yanglin_68397/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[我拒絕了 Google 的 Offer]]></title>
            <link>https://medium.com/@yanglin_68397/%E6%88%91%E6%8B%92%E7%B5%95%E4%BA%86-google-%E7%9A%84-offer-cb506743bc7a?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/cb506743bc7a</guid>
            <category><![CDATA[careers]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[google]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[critical-thinking]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Mon, 03 Nov 2025 11:20:13 GMT</pubDate>
            <atom:updated>2025-11-05T16:49:04.300Z</atom:updated>
            <content:encoded><![CDATA[<p>標題寫得比較聳動，不過事實是我在 Google 面試的過程體驗出乎意料的好相，也對於放棄這個機會感到相當煎熬。</p><blockquote>給忙碌的人看的懶人包：因為在 Google 面試的過程中，我已接受並加入 Proton，最後決定還是繼續留任。</blockquote><p>因為曾有不少工程師朋友在幾年前面試 Google 時獲得不太好的體驗，所以原先我在面試 Google 前的期待值相當低，以一個試試看也無妨的心態去投，沒想到整個過程比我預想的更快速、有效率，面試過程中的所有人也都相當友善而專業，因此其實這個故事並不是那種典型的「工程師拒絕大公司的穩定高薪工作追逐夢想」的心靈雞湯故事，更像是一個職場打滾一陣子的小小工程師的一次求職紀錄，包含面試的準備階段、過程，以及最後經過各種反思，忍痛放棄 Google offer 的艱難抉擇。</p><p>另外，這次求職過程中，我在 Proton 與 Google 之間經歷了協調與競價（competing offer）。對於 那些 FAANG 一把抓的大神們來說，這樣協商討論的機會可能是司空見慣，但對於包含我在內的很多普通人來說，這種情況應該不那麼常見，也不容易找到參考經驗。我希望把我能分享的資訊盡量寫出來，讓有類似狀況的人能少踩坑，也留作自己的紀錄。</p><h4>關於我</h4><p>這邊也先給一些關於我個人的規格以及背景資訊：</p><p>我的專長主要是網頁開發，全端都可以做，但主要偏向前端。工作經驗約五年，大部分的職涯都是在偏新創的小公司，曾經當過前端主管，帶領五人的工程師團隊開發，更多的資訊可以參考<a href="https://yanglin.site/#/">我的個人網站</a>。</p><p>這次原訂投遞的職缺是 Pixel Team 的 Fullstack Engineer L4，以及 Proton B2B Frontend Engineer L2 。</p><h3>時間線</h3><p>投遞履歷給 Google 的過程大約發生在今年的六月底，當時因為前公司一系列令人不安的跡象，大量同仁出走，也讓我決定雖然任職時間並不長，但應該立即開始另謀出路。</p><p>7/11 第一次與 Google HR phone screen，HR 介紹了面試關卡、流程、準備方向，還有各種該職位相關的資訊等等。</p><p>基本上因為 Google 工程師的面試流程現在已經很固定了，所以相同職階的面試流程應該都大同小異，也很容易找到相關資料：一般來說會有三關 Technical Test，一關 BQ，然後進入 Team Match 環節，接著進入 HC(Hiring Commitee)，最後 Offer Get。</p><h4>準備 Technical Test</h4><p>HR 在初次溝通時會提供準備方向，包含 Leetcode 題量建議與面試須知，所以其實這部分如果已有準備要投 Google 的人，可以直接在這階段聽 HR 說明就好，HR 也會提供一份詳盡的文件供參考。</p><p>原則上 Google 面試可以給予一個月左右的時間給面試者熟悉 Leetcode like 題目，所以如果一段時間沒有刷題的人，可以適度利用這段時間重新回覆一下手感。我自己對於解題比較沒有信心，所以就有刻意安排的比較晚一點，延到 8/8 才開始第一次面試，也在這個階段有嘗試投遞包含 Proton 的其他職缺。</p><p>典型的 Google Technical Test 基本上就是一節 45 分鐘，其中組成可能是一題 hard 程度或兩題 medium，而面試時的編輯器基本上就是一個有語法高亮的 shared doc，沒有關鍵字補完、AI 輔助或任何其他輔助，也不能編譯測試，因此對於一般平常的上班族工程師來說可能要花點時間刻意練習關掉所有輔助寫程式。</p><p>另外最重要的一點就是要刻意練習 Think Out Loud，在一邊寫程式的時候，也要能同時把你的思考流程一邊講出來，這也是對於一般上班族可能要刻意練習的一塊，平時可以多使用小鴨 Debug 法，或是找人 Pair Programming ，對於這個環節應該會有些幫助。另外其中一關必須選擇以英文來面試，所以各種常見演算法、運算符號、Function 名稱的英文，平常不常使用的話可能需要多留意一下。</p><p>對於 L4 的職缺，三關 Engineering Test 裡可能會有一關是偏 System Design，不過這部分我也不知道該如何準備，因為我什麼準備都沒做(聳肩)。以我收到的 System Design 題目來說，很大程度是依靠實際實務設計經驗來回答，也因此很難給出一個制式化的準備流程或答案，簡單來說就是平常有沒有燒香(笑)，不是臨時抱佛腳可以學會的。</p><p>不過一般來說，在 45 分鐘內能做的 System Design 當然不可能是太複雜、精細的系統，因此其實重心應該是放在如何跟你的面試官確認需求，依你自己的經驗判斷邊界條件、可能會遇到的問題，並想出適當的解法、切分問題、分析各種 Trade Off ，能考量到越多可能情境應該整體來說都會是加分。</p><p>關於解題的部分，其實我自認都不算回答得特別好，兩次面試都稍稍有點超時，也聽了一些面試官的 Hint 才找到最佳解，不過幸運的是面試官都給出相當好的評價；System Design 的部分就相對是我比較擅長的，因此整體來說比較輕鬆愉快，我想就當作技術交流的心態來準備就好，不要太刻意想用太高深或是抽象的概念或工具。整體來說，我的面試過程算是相當的順利，面試官都非常友善且很好溝通，給予的評價都比我預期的好。</p><p>順帶一提，在這三關面試接近一個月的過程中我同時也在面試 Proton ，並且平日也在上班，因此其實過的相當的忙碌充實，不知道人生之後還會不會有這麼高壓求職的過程(笑)。因為這次的標題寫的是 Google ，我想大部分的受眾應該也期望看到 Google 的相關資訊，因此我就不特別介紹敝司的面試流程，不過如果有人很有興趣想跟我當同事歡迎留言或私訊找我討論，我很缺同事 QQ</p><h4>Behavioral Questions</h4><p>因為我有其中一場 Techincal 被延期，因此我提前先參加了 BQ，原本以為這兩個階段是 Sequential 的，我也是第一次知道可以這樣重新排列。</p><p>BQ 其實也沒有什麼真正的準備要點，基本上就是考量面試者的職業素養：什麼時候該說什麼話，什麼時候不該說，心中要有一把尺。相信有不少有能力的工程師都天性樂於分享，喜歡討論技術、想法，但是對於大企業來說，哪些東西屬於商業機密，哪些東西屬於技術討論，勢必需要有明確的界線，這點我覺得是需要一些工作經驗拿捏的，基本上也沒有什麼準備的必要或建議方向，考驗的就是在社會打滾的專業素養。</p><h4>Team Match</h4><p>其實只要到了 Team Match 階段，基本上可以說是十拿九穩了，可以對自己說聲恭喜，然後準備探索各種可能的選項。</p><p>Google 的 Team Match 給我的感覺就很像 Speed Dating，對你有興趣的 Hiring Manager 會約你進行 30 分鐘的說明，期間你也可以對 HM 提問，如果兩邊都是 Match，就可以進行到下一階段。</p><p>因為是 Speed Dating，所以這個 HM 如果覺得你不適合這個 Role，HR 就會幫你安排下一場 Match；反之如果你不喜歡這個 Team，也可以繼續要求其他 Match，直到兩邊都同意，就可以送交下一階段。</p><p>經過了前面的關卡，基本上表示 Google 已經核可你這個人的專業能力了，因此這一個環節不用刻意展現你的技術能力，就誠實的與 HM 討論並儘量提問了解團隊細節，幫助彼此做出最好的決定。</p><p>我原本投遞的職缺是 Pixel Team 的 Full Stack Engineer，不過跟 HM 討論過後他覺得我的職能比較不適合該團隊，因此我後來是在第二次 Team Match 才 Match 到適合的 Team ，不過相對來說已經算是相當快速了，有不少人在這個環節可能會等上數個月甚至一年以上還等不到適合的位置。</p><p>而在我開始 Team Match 的時間點(約 9月中)，我已經接受 Proton offer 並準備開始工作，因為我原先並不認為 Google 會推進的太快，已經做好等上三個月至半年的準備，又因為敝司在 9 月底有 Global meetup，如果我在 9 月中能 onboard 就能馬上親身跟國外團隊成員見面，是個相當好的機會，因此我當時的考量就是，既然有好的機會就先上，Google 反正可能還要很久。</p><p>而我收到 Team match 通過的時間，剛剛好就落在 9 月底，我準備要出差去歐洲的前一週。當下其實是一個喜憂參半的複雜情緒，本來一直想著反正不一定會上，上了再來想，結果就真的上了。</p><p>收到通知的當下，我就盡速去找我的老闆討論這件事，老闆也很有誠意且有很效率，當天晚上通知了其他高層，隔天就與我討論了調薪方案，基於 Google HR 當初給我的 L4 薪資 Range 提出 Match Offer，因此我在兩週的出差前就覺得我把這件事訂妥了，雖然還沒收到 Google 的 Actual Offer，但我原先的計劃是打算直接放棄。</p><h4>Offer get</h4><p>時間快進到十月中，Google HR 通知我 HC 順利通過，來告知我 Offer Delivery。</p><p>看到實際數字的那一刻我有點小吃驚。原本 HR 說 L4 的 TC 會落在某個範圍內，不太會超過上限，但最後給出的 offer 還是比當初的範圍高出了一截，即使已經爭取過一次調薪，還是有一段不算小的差距。</p><p>又是另一個憂喜參半的瞬間，我就跟 HR 說我目前有另一個 offer ，雖然出價範圍比較低，但我有些其他考量。這部分感覺稍微被 HR 話術施壓了一下，壓力之下講出了自己的底牌(現在的價碼）以及承諾說會盡快做出決定，因此當下說出兩天內答覆。</p><p>當天我立刻聯繫老闆說明情況，希望再討論看看是否有調整空間。那時他人在國外，我們透過幾封信往返，最後得到的結論是公司已盡力給出最具競爭力的方案，最終我也沒能爭取到更高的薪酬。</p><p>時間線推到這邊，基本上就是這段時間我的求職過程的濃縮版精華，也覺得十分幸運在兩個很不錯的 Offer 之間選擇；在收到 Google Offer 之後的一個禮拜之內，我做了很多很多考量，也跟很多不同的朋友們討論，上述流程面的事情講完之後，接下來我想分享的是我對於自己職涯、人生規劃上的自我檢討之後，為什麼最後做出放棄 Google 這一個決定的一些想法。</p><h3>反思</h3><p>首先對於整個 Match Offer 的討論流程，因為沒有經驗，所以我覺得我犯了一些小錯誤。</p><p>第一個就是 Team Match 通過時不應該先急著去談，畢竟還沒拿到真的 Offer，其實很有可能會落到兩邊都不滿意的情境，而且從事後結果來看，其實我拿的是不完全的籌碼去做談判，應該等一切塵埃落定，才拿完整籌碼去做協調，才能得到最好的結果。</p><p>其次是在跟 Google HR 談的階段，太早亮出自己的底牌，因為透露了另一邊的出價其實沒有比較高，失去了一些 Bargain Power 。雖然我也不覺得有多少機會可以從 Google 那談到更高的數字，但也有可能可以要求一些額外的福利，只能說在電話討論的環節很容易臨時腦袋沒轉過來，就順著話術把自己的籌碼交出去了。</p><p>但其實整體來說，這些決策上的小失誤不見得有帶來什麼實際影響，固然會希望如果有新一次機會的話，自己能處理得更好，但作為一個務實主義的工程師，我認為還是把時間精力多投資自己的專業能力上，有這些協商談判的機會就努力去爭取，但是不要過度鑽牛角尖而本末倒置。</p><p>至於如前面提到的，如果 Google 開價的數字真的比 Proton 還高，那為什麼我最後會做出留在 Proton 的決定呢？</p><h4>錢、生活、工作</h4><p>我想任何職涯的選擇，最終其實都離不開這三件事情的平衡。</p><p>Google 毫無疑問提供了最直觀的誘因：錢，以及同樣相當重要的一個條件：Branding。可以想像在 Google 工作過，之後就算想轉往其他任何公司，都可以省下很多解釋的力氣吧。</p><p>生活上的平衡來說，我認為敝司與 Google 能算是平分秋色，對於 Hybrid Work、請假、工作量等等，兩邊能提供給我的福利和價值是不會相差太多的。</p><p>所以我想最終影響我的決策的，大概就是工作內容了吧。</p><p>最終我在 Google Match 到的團隊，雖說工作內容聽起來不是我會不喜歡，但我其實無法想像我在那個位置能發揮什麼影響力(Impact) 。當然這部分有點見仁見智，但對於我自己而言，在過去的職涯之中我了解到自己是一個喜歡對團隊產生影響的人，這一點能讓我對我的工作得到認同並且維持熱情，而在 Google 這樣巨大的機器裡，我感受不太到我有產生足夠影響力的機會。</p><p>相較之下，我目前在 Proton 的工作，非常的符合我的職能與專業，我可以想像我在這邊能推動哪些事，能做到哪些影響，因此即使才入職很短一段時間，我已經能想像半年到一年之內，我有哪些事情可以著手，能做我最擅長的前端相關的工作。</p><p>當然，因為我根本沒有實際去過 Google，我無法知道是否真的會如我所想，說不定其實我也會很喜歡那個 role，you’ll never know，因此其實這個理由並不算太充分。</p><p>另一個理由則是很直觀的：新創 vs大公司。</p><p>在我的職業生涯裡我待過大約五個新創，我認為我是一個充滿新創與創新基因的人，也比較喜歡扁平、自由、效率的文化，而即使 Google 再怎麼強調科技、創新、自由等等，都改變不了他是一間有接近 20 萬員工的巨獸公司。而船大難掉頭，很多事情在這間公司有很大機率是無法改變的，至少是以我這樣一個小小的個體不太可能撼動的。</p><p>而在 Proton，我有很大的機會可以自由的實驗、探索，按照自己喜歡的方式做事。</p><p>思考到這一點時，又讓我開始探討自己的初衷，為什麼一開始認為我會傾向留在 Proton ，而不是去 Google 呢？</p><p>經過多日的思考與梳理，我歸納出了這兩間公司分別能對我的價值：一邊是立即性的更多錢、收益，另一邊則是自由與潛在的成長機會。</p><p>那麼現在的問題就變成了：更多的錢，與更多的自由，我會如何選擇呢？</p><p>我想這樣講可能很假掰，但我是真的這麼認為的 —— 錢不重要，至少不是最重要的。</p><p>身為一個社會人，就不可能不談錢，錢並非萬能，但沒有錢絕對是萬萬不能。然而當財富累積到一定程度的時候，人生就會自動圓滿了嗎？答案恐怕是否定的，大多數人很可能終其一生可能都不知道自己需要什麼，想著有錢之後就能盡情做自己想做的事，然而卻在追逐金錢的遊戲中迷失自己。</p><p>錢就是資源，是價值儲存的形式，但當人生到達一個階段的時候，我想很多人都會同意：有很多其他資源，是錢這個資源無法換到的，像是友情、愛情、健康，以及最重要的 —— 快樂。</p><blockquote>Love, laughter, and relationships,<strong> t</strong>he best things in life are free.</blockquote><p>我很喜歡的動畫《烘焙王》中，主角東和馬在面對總店三倍薪水的機會時說過這樣一句話：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DhVsARqO9jql5c_37XW87g.png" /></figure><p>這讓我回想起了一開始我認為自己會優先選擇現在 Proton 的工作機會而非 Google 的原因。</p><p>作為一個前端工程師來說，現在在 Proton 的工作有更多會讓我覺得有趣的機會，有更多讓我感到興奮的挑戰，而且我的努力更有可能對公司與我個人的成長造成影響。當然我也會希望這些努力最終能透過股份轉換成實質利益之類的，但與此同時，這些經驗本身就是如果我選擇其他工作 —— 即使是在Google —— 都很難有機會獲得的寶貴體驗。</p><p>另一方面來說，新創迷人的地方也在這邊，雖然說我在新創圈打滾多年，早已經對所謂的上市起飛、財富自由的新創夢沒什麼感覺了，但是對我而言在新創公司最浪漫的地方就是：你的手上握著一張彩票，而這張彩票你有能力去改寫他的機率，只要你能付出一定的努力。</p><p>因此在經過幾天的天人交戰之後，我還是忍痛做出了抉擇：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F-p4_CZS0aFiqxN2ijRLBQ.jpeg" /></figure><p>其實除了上述所列的這些大方向及原則性的思考之外，還有很多很多各種細節考量，像是稅務、升遷、裁員風險、RSU/Options、Relocate …. 族繁不及備載的一大堆事情可以考慮，認真要說的話有太多太多因素了，但我已經花了足夠多的篇幅寫我的內心糾結了，如果真的有人關心這些細節的話可以期待我的下篇分享，或許一兩年之後(?)</p><h4>結語</h4><p>坦白說，雖然上述列出了許多我的真實的想法，但我對這個選擇並非沒有任何懷疑。我是真的很想瀟灑的說我不在乎錢，或是我不在意一流公司工程師的光環，但 Google 的條件真的是滿誘人的(笑)。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/671/0*XuaAF9LbYMk6I20P.jpg" /></figure><p>其中一位在 Google 的朋友，對於我的煩惱，跟我說出了這樣的建議；我也很想帥氣地說出這種話，但是他說的 <em>那點錢</em>，其實是一年數十萬的差距 🫠 我還沒有辦法如此淡然的看待這個差距。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/862/1*9ONQTwh9fBO79Nxw3xaC1Q.png" /></figure><p>不過基本上，我想人生應該沒有所謂的絕對的對或錯的抉擇，會如此苦惱表示兩個選擇其實都有差不多的吸引力，所以既然我已經做出這樣的決定，那就是我在這個當下經過各種考量之後，對我而言最佳的抉擇。</p><p>如果有另外一個人跟我站在相同的人生叉路口，這篇文章絕對不是要告訴你怎麼樣的選擇是對的，我想人生的醍醐味就是在各種選擇中迷惘著、糾結著，然後毅然前進。如果你有幸讀到了這一行，希望能讓你在選擇的過程中給你帶來一些不同的思路，感謝你的閱讀，peace ✌️</p><p>最後，敝司還有在徵才： <a href="https://proton.me/careers">https://proton.me/careers</a>，如果有興趣當我的同事的話，歡迎來聯繫我討論，假如我有空的話。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cb506743bc7a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[討厭區塊鏈的我，加入了一間區塊鏈公司]]></title>
            <link>https://medium.com/@yanglin_68397/%E8%A8%8E%E5%8E%AD%E5%8D%80%E5%A1%8A%E9%8F%88%E7%9A%84%E6%88%91-%E5%8A%A0%E5%85%A5%E4%BA%86%E4%B8%80%E9%96%93%E5%8D%80%E5%A1%8A%E9%8F%88%E5%85%AC%E5%8F%B8-ec907c4f6392?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/ec907c4f6392</guid>
            <category><![CDATA[職場]]></category>
            <category><![CDATA[加密貨幣]]></category>
            <category><![CDATA[web3]]></category>
            <category><![CDATA[前端]]></category>
            <category><![CDATA[區塊鏈]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Tue, 07 Dec 2021 13:35:03 GMT</pubDate>
            <atom:updated>2021-12-08T05:03:43.674Z</atom:updated>
            <content:encoded><![CDATA[<p>不少私底下認識我的人應該知道，有很長的一段時間我都是一個對區塊鏈和幣圈嗤之以鼻的”幣黑”，原因其實跟所有看空區塊鏈的人差不了多少，不外乎就是浪費能源破壞環境、交易速度低落、缺乏殺手級應用、泡沫化、圈錢、詐騙、割韭菜 … 等等。</p><p>這樣的我，在因緣際會下加入了一間開發加密貨幣錢包的公司 — <a href="https://blocto.portto.com/">門戶科技 portto</a>，然後在不知不覺間，半年就過去了，因此這篇文主要是給自己做個紀錄，也順便介紹一下敝司 —— 還有許多職缺招募中，有興趣的大大也歡迎來投遞 😇</p><p>大約 2014 年以來，我就對於區塊鏈的基本原理大致有認識，也因此在當時覺得以那時候的區塊鏈技術根本無法普遍應用在日常生活中。而在 portto 工作的這半年之中，我一口氣更新了累積超過 6 年的資訊，發現自己對於區塊鏈的認識停滯太久了，而這個領域已經有十分驚人的改變與進步，因此接下來我將介紹我是如何從一個幾乎是區塊鏈技術的門外漢，變成一個跨鍊應用開發者，關於區塊鏈技術及應用的看法，有什麼部分改變了，有什麼部分維持原狀、甚至更深信不疑了，對於其現狀及未來的發展又有什麼樣的想法，就請大家繼續看下去。</p><p>接下來會分兩個部分，第一部份是我個人這半年工作對 portto 這間公司的總結，第二部分是我對區塊鏈產業的看法。</p><h3>Part 1: 進入 portto</h3><p>會進入 portto 也是一個神奇的機緣，故事要從四月的那一天說起：</p><p>我被現在的同事內推，然後就進來了。</p><p>end of the story (?)</p><p>精簡版是這樣啦，不過當時我其實有過一番心裡掙扎。</p><p>當初大學剛畢業的時候，我給自己立下的原則是：兩個產業不碰，第一個是博弈，另一個是區塊鏈。結果大學畢業的三年後，我在博弈產業做得灰頭土臉，而現在收到的 offer 來自一間區塊鏈公司，不禁令人苦笑。</p><p>不過，在博弈產業做了一年，認識到博弈產業果然跟自己原本設想的差不多而覺得工作沒有成就感；進到 portto 之後重新認識的區塊鏈產業，才發現有很多事情都跟自己原本知道的差很多，每天都不斷有很多有趣的新東西冒出來，或許工作了一陣子之後也漸漸發現很多事不那麼的非黑即白，總要多多嘗試才知道是否跟自己想的一樣吧？</p><p>算是工作幾年後的一點反思跟想法，不過這部份跟本篇的主題比較無關，就到此先打住。</p><h4>公司文化</h4><p>在 portto 工作的這段期間體會到，敝司對於<strong>建立公司文化</strong>這件事情相當重視，COO 與 CEO 都很重視員工們的意見， 每個員工也都有很多機會直接跟老闆們面對面 1 on 1 討論想法，即使現在因為人數逐漸增多開始有 Team Lead 的角色，但同事彼此之間的上下層級都是非常扁平，我個人滿喜歡這種同事關係，很多事情可以很快速的同步。</p><p>在 portto 工作真的非常有”與公司一起成長”的感覺，不是單純的因為持有股份這樣表面的理由，而是可以看著人數逐漸擴張，並且同事之間都很願意彼此互相幫助學習、遇到困難一起討論解決，老闆們對於公司的情況也都會定期在 all hands 會議中與大家報告，面對一些疑問也會盡量回答，讓人有一種確實置身在其中的臨場感。</p><p>因為區塊鏈技術與市場變化的很快，很多技術的基礎架構其實都很不完整，要踩過幾次坑才能上手，這時候靠單打獨鬥就很容易感到挫折，不過在 portto 大家都很樂意分享知識，不會上演一些其他公司的勾心鬥角、偷藏一手的戲碼，公開與透明是我覺得公司很注重的一個環節。</p><p>除此之外，平時辦公室空間的工作氛圍算是滿 chill 的，每個月固定會有 team building 活動，平常大家也會揪一揪就去吃吃喝喝，三不五時還會有人炒幣賺錢空投飲料點心給同事 😋</p><h4>工作節奏</h4><p>我想在任何一間區塊鏈的新創公司裡，工作的步調應該都是無可避免的快，市場變得太快、技術變得太快、有人暴富的太快(?)，在 portto 也不例外。我們處在一個瞬息萬變的環境，光是這半年來我已經看過兩三次在 30 分鐘內整個幣圈大盤暴跌 10% 以上的慘況了。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ViufYC_YB18vgSuP-GIMjg.png" /><figcaption>第一次看會怕，多看幾次都習慣了</figcaption></figure><p>在這樣一個高速發展、快速進化的產業，每天都有新的團隊、新的產品問世，也因為區塊鏈技術與金融經濟層面息息相關，對於新的東西除了了解技術面細節，也需要了解其商業面的特點，來判斷是否要跟隨潮流串接一些產品或實作一些新功能等等，即使以一個禮拜為單位做調整也不見得可以跟得上，對於某些數週甚至數個月才討論一次方向的傳統類型的公司而言，這種速度可能是非常難以想像的。</p><p>這樣的工作節奏當然不見得適用於所有人，我自己至今也還在調整，現在下班之後還是會自己研究很多相關的東西，一方面是為了多方了解新的技術、市場潮流，一方面是也會跟其他人一樣開始 FOMO (Fear Of Missing Out) 害怕錯過下一個新玩意兒，畢竟不得不說，幣圈相較於現實世界真的還是多很多賺快錢的機會。</p><h3>Blocto — 區塊鏈應用(dApp)的 steam</h3><p>開始進入無情工商環節(?)</p><p>在 portto 最主要的產品就是手機平台的跨鏈智能合約錢包 Blocto ，因為我們的產品辨識度比我們的公司名稱更高，所以也常常有人以 Blocto 代稱我們的團隊。</p><p>Blocto 的願景是成為去中心化區塊鏈應用的 steam —— 就是那個買遊戲的 steam；像逛 steam 買遊戲一樣，讓使用者可以一樣在 Blocto 上面瀏覽使用 dApp 、管理資產，透過良好的 UX 讓新手用戶能以低負擔暢遊區塊鏈世界。</p><p>對於新手來說，參與區塊鏈世界其實相當的不容易，甫一進門，錢包、地址、公鑰、私鑰、助記詞、gas、公鏈、代幣、合約、去中心化應用 … 隨便一想都可以有十來個名詞需要了解，所以 Blocto 的終極目標就是要讓小白用戶們可以在不造成太多心智負擔的前提下，只需要一個 email 帳號，就可以快速開始他們在區塊鏈世界的旅程。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rVIzlPITByVLluDw.png" /><figcaption>密密麻麻的文字，卻只是新手入門的其中一小塊</figcaption></figure><h4>跨鏈智能合約錢包</h4><p>Blocto 為了讓用戶可以降低用戶心智負擔，使用了滿前沿的技術 —— 至少我目前沒聽過多少競爭對手在做類似的東西，這個核心技術就是：<strong>智能合約錢包</strong>。</p><p>顧名思義，智能合約錢包代表用戶的錢包不是一般的公鑰/私鑰對錢包，而是我們部署的智能合約模擬的錢包，藉由這個方式讓我們有兩個關鍵技術可以改善用戶體驗：</p><ul><li>Meta Transaction：使用 Meta Transaction 技術可以讓第三方來代付在鏈上交易所產生的手續費。目前無論在哪條公鏈平台上，要發送一筆交易都必須要支付該鏈上的代幣做為手續費，Ethereum 上使用 ETH， Solana 上使用 SOL，Polygon 上使用 Matic 等等，對於新手用戶來說要使用鏈就要先了解如何獲得這些對應的公鏈代幣，體驗上不甚友善。透過 Meta Transaction 的代付機制，即使用戶沒有該代幣依然可以進行交易，甚至也可能將手續費支付的費用成本轉移給 dApp 開發者。</li><li>Multi-Signatures：用戶在區塊鏈世界最頭疼的問題之一就是遇到詐騙而被竊取或是遺失私鑰，而一般錢包的痛點就在於一但這類情況發生，沒有有效的手段可以恢復錢包，而透過 Blocto 智能合約錢包的特性，可以讓一個錢包需要多把鑰匙簽章同意，才能完成交易，或是透過另一把鑰匙恢復賬戶，等於是 Blocto 與用戶共同保管錢包。<br>當然，比較有背景知識的用戶可能會質疑，這樣不就是中心化錢包了嗎？<br>對於新加入的用戶，一開始我們確實會讓用戶以這樣中心化的託管模式持有錢包，但隨著用戶經驗增加，了解到持有私鑰的資安風險之後，也可以透過我們提供的管道切換為非託管模式，Blocto 方持有的權限將完全轉移給使用者，由使用者全權掌控自己的錢包，我們稱之為混合中心化 (mix-custodial)模式。</li></ul><p>總結一下 Blocto 錢包的特色：</p><ul><li>手機 app 錢包</li><li>跨鏈</li><li>代付手續費</li><li>混合中心化託管</li></ul><h4>Blocto Token (BLT)</h4><p>BLT 則是 Blocto 錢包的平台代幣，具體的說明就不贅述了，可以直接參考我們的代幣經濟這篇文章。</p><p><a href="https://medium.com/portto-tw/blt-%E4%BB%A3%E5%B9%A3%E7%B6%93%E6%BF%9F-f9b44e7db2d3">BLT 代幣經濟</a></p><p>接下來的環節就比較跟我的工作相關，因此特地拉出來介紹一下，讓大家知道一下 Blocto 的前端工程師大多在做什麼工作，基本上跟典型的前端工程師還滿不一樣的！</p><h4>SDK</h4><p>前面所述，Blocto 錢包主要是在手機應用，但是也會有用戶有網頁端需求，因此我們最近在緊鑼密鼓的開發網頁版本的 SDK，讓用戶可以透過點擊按鈕或一些觸發事件，開啟一個 iframe 的 UI 使用錢包。</p><p>而由於我們合約錢包的架構特殊性，有託管與非託管模式等，加上想要讓 SDK 可以 npm 安裝或是 CDN 開箱即用，如何在安全性及易用性之間取得平衡著實是一個挑戰。</p><p>另一方面，不是每條公鏈的介面都相似，如何弭平公鏈之間的差異，讓同一個介面可以通用於各種公鏈的串接方式，也是一件不容易的工作。</p><p>跨鏈應用本身就充滿許多障礙，而我們以更高的標準在實作這些東西，使用許多沒有前例可以參考的工具，因此不管是後端的合約及伺服器架構部分，或是我們前端介接的這些部分，都需要不少臨機應變跟架構規劃。</p><h4><strong>周邊生態系</strong></h4><p>雖然 Blocto 的目標是成為區塊鏈的 steam，主要的走向是要成為平台方容納其他 dApp，但我們自己本身也是帶有一系列的生態系 dApp，包含去中心化交易所 <a href="https://swap.blocto.app/">BloctoSwap</a>、NFT Marketplace <a href="https://bay.blocto.app/">BloctoBay</a> 以及之後即將上線的服務等等。</p><p>在 Blocto 我們主要的 Frontend Stack 是圍繞在 React 與其生態系，但沒有特別選定哪些工具，一切都是視情況調整，如 BloctoBay 有 SEO 需求，因此我們採用 Next.js 的 SSR 架構，BloctoSwap 架構比較複雜，因此引入 RxJS ，如果是很輕量的展示用 dApp，甚至可能完全不使用任何框架等等，團隊討論比較適用的方案之後，剩下就由實作者自由發揮。</p><h3>Part 2: 區塊鏈到底是什麼？</h3><p>區塊鏈技術到現在，對普羅大眾來說仍然是如霧裡看花，即使是一些主流的大型媒體，在報導時仍可能會搞錯很多重要的環節，或是刻意地誇大、過分解讀某些名詞，各種資訊的不對等跟落差讓區塊鏈技術蒙上一層神秘色彩，也讓很多心懷不軌的宵小有很多為非作歹的機會。</p><p>即使是資訊圈從業人員，如果不是直接接觸到最新的區塊鏈技術的話，仍然會對其有很多誤解，像我從 2014 年之後沒有再更新資訊，就一直停留在 2014 年的區塊鏈，到了 2021 年才發現這個領域進步的速度已經今非昔比了。</p><h4>分散式儲存帳本</h4><p>其實區塊鏈的本質，從起始至今都沒有太大的改變，一言以敝之就是<strong>去中心化、分散式的所有權記錄</strong>，也就是大家可能多少聽過的<strong>分散式儲存帳本。</strong></p><p>區塊鏈網路由多個節點組成，一個節點可能從一台 PC 到高階工作站都有可能，每個節點都包含一份從起始至今所有帳本的歷史，紀錄 A 轉了多少資產給 B、C 對 D 做了什麼操作 … 等等類型的資訊。</p><p>可以想像成是一個班級裡面有很多小朋友(節點)，每個人都有自己的一份作業(帳本)，每個人的作業都應該是相同的，如果有人跟別人的不一樣，有可能就是他亂寫，亂寫的人就會被抓起來打屁股。</p><p>當我們在網路上交易，所有節點就會計算取得共識，確保每個節點所記錄的帳本歷史是相同的，一段時間區間過後，就會把取得共識的帳本歷史打包成塊封存，一塊一塊的帳本紀錄串聯起來，就是我們知道的區塊鏈了。</p><p>後來有人發現，如果我們能透過區塊鏈網路儲存資產轉移資訊及轉帳明細，那我在明細裡面放程式碼，然後讓他可以在各個節點上被設法運行，不就可以寫一些邏輯來做一些更方便的事嗎？例如一次轉帳給 10 個人，或是做一些算術運算作分帳。</p><p>這就是智能合約，儲存在鏈上、執行在鏈上的程式。</p><p>看吧，其實區塊鏈也沒那麼難吧？</p><h4>區塊鏈 = 詐騙 X 圈錢 X 浪費能源 X 泡沫？</h4><p>想到區塊鏈，很多人可能會想到標題所說的這些名詞，可以很確定的是：區塊鏈的詐騙真的超級多，我平均一天可以收到四五則詐騙，今年中第一次參加一個代幣 IDO (去中心化交易所代幣上市活動) 就差一點被詐騙，而且我自認已經是對於資安敏感度相當高的人。</p><p>詐騙跟圈錢真的是幣圈層出不窮的亂象，代幣項目方捲款潛逃、假冒官方的詐騙訊息，或著 KOL 挟帶名氣賣垃圾幣、開設動輒十幾萬的課程等等，各種這樣的新聞，讓大家對這個產業充滿不信任，包含我原本也是這樣覺得。</p><p>事實上我到現在還是這樣覺得啦，嘿嘿。幣圈就真的很亂，充滿詐騙跟投機，很多很令人噁心的人。</p><p>不過前一陣子跟敝司的 COO 談這個現象，有被一個觀點所說服：</p><p>在早期網購剛流行的時候，各方平台上也是充斥各種詐騙與漏洞，老一輩的人可能到現在還是對網購充滿不信任，但是隨著時代進步，大家對於資安的意識提高，平台的安全性也逐漸提升，我們現在對於網購的接受度就逐漸提高了。</p><p>區塊鏈的特性，讓資產的流動變得比傳統金融更容易，點按之間就可以交易大量金額，投資各種標的也不需要經過中心化機構的各種繁複手續與監管，少了監管固然是一個好處，但是同樣的也會失去其所提供的保護力，而很多的使用者在這方面的素養相當不足，只看到區塊鏈方便的那一面，而忽略掉了其中隱含的責任與風險。</p><p>但是這樣的特性其實不是區塊鏈的錯，這個遊戲規則原本就是設計給懂得掌管自己風險的人去玩，因此我們真正該做的事，是讓一般人都能夠有足夠的認知，知道區塊鏈的運作機制及可能的風險之後，可以自己做出正確的選擇。以前大家會被簡單的電話詐騙給騙到，現在相同的伎倆成功率可能就不高了，當去中心化世界的資訊落差逐漸被弭平之後，我們才能真的開始正常的應用情境。</p><p>浪費能源這件事情，也是我一直對於區塊鏈心存芥蒂的重要原因。區塊鏈網路確實是相當能源密集的，比特幣、以太坊 1.0 都採用 PoW (Proof of Works工作量證明) 的共識網路機制，這種共識機制需要所謂的”礦工”消耗大量電力及算力來達成，不僅浪費能源而且效率十分低落。</p><p>好消息是，這樣的情況很有可能都將成為過去，以太坊 2.0 目前已經接近完成，未來將切換為基於 PoS (Proof of Stake 持有量證明)的共識機制。有別於以往比特幣、以太坊 1.0 PoW 的機制，PoS 可以節省極大量的算力，不再需要”礦工” 使用高算力裝置(顯卡/CPU) 計算，就可以進行區塊驗證及出塊，而且具有更高的交易吞吐量。以太坊預計 2.0 升級完成搬遷到 PoS 共識網路之後，可將交易需要的算力從<strong>已開發國家級 </strong>降低至 <strong>村莊級</strong>，實現更有能源效率的網路系統。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rxnvBNF-pSntJM9RLVOxXQ.png" /><figcaption>PoS 升級預計將能源損耗降低 99.95%</figcaption></figure><p>新一代的公鏈如 Solana、Flow、Poylgon 等等，都已經採用 PoS 或基於PoS 的衍生共識機制，也被證實這樣的機制是可行的，因此區塊鏈技術已經不如大家以往所想的消耗這麼多能源了，也終於快要可以還我們便宜的顯卡了 😇</p><p>至於加密貨幣是不是一場大泡沫，看到過去幾個月增發了 35% 循環供應量的美金之後，我已經不在乎了。</p><h4>區塊鏈 X 前端</h4><p>身為一個前端工程師，當然會特別關注前端工程與其他新技術的整合狀況，而<strong>前端技術跟區塊鏈可以說是一拍即合</strong>。</p><p>對於前端工程師來說，很大一部分的工作就是在串接後端給的資料，在用戶端做視覺化呈現及資料操作、互動，而掌握了一些 web3 工具之後，<strong>與區塊鏈互動的過程與跟一般後端伺服器互動並沒有不同</strong>，只要了解如何呼叫介面即可，對於前端工程師來說是一個幾乎無痛的轉換。</p><p>更有趣的是，因為鏈上的資料都是透明的，想要看到一些有名的 dApp 的合約怎麼實作也是易如反掌，覺得哪家 dApp 的介面不好用，自己找那些 dApp 背後的合約來串接完全可行，相當於公開的後端，這對前端工程師來說有很多可以發揮的空間。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uQlQdY7VegY2OjrYK-sMrw.png" /><figcaption>應用分析：查看代幣市值的服務 CoinMarketCap ，可以透過自訂義介面串接 uniswap 等多家去中心化交易平台的合約</figcaption></figure><h4>DeFi/NFT/GameFi/Metaverse</h4><p>近幾年來基於區塊鏈的應用逐漸進化，從前幾年火紅的 DeFi，到今年的 NFT 熱潮，現在最流行的則是 GameFi。除了 DeFi 之外，最近興起的這些新應用我認為可以囊括為<strong>”元宇宙(Metavse)”熱潮</strong>，這些東西確實有很多值得興奮的地方，但也有很大部分具有炒作、投機的成分，有機會的話也想寫幾篇文章分享我對這些應用的觀點，從稍微比較技術面的角度切入。</p><h3>區塊鏈的未來</h3><p>以下是一些我對於區塊鏈技術的現狀及未來的想像。</p><h4>多公鏈並行</h4><p>比特幣與以太坊可能是大多數人對公鏈技術認識的起點，他們具有不可動搖的先驅者的地位，因此被大家親暱的稱作大哥二哥。</p><p>然而最近幾年，有越來越多新的公鏈推出，如 EVM 系列的 Immutable X、Polygon、AVAX，專注於遊戲及 NFT 的 Flow，高交易吞吐量的 Solana 等等。雖然有許多後起之秀競爭 ”以太鏈殺手”的位置，未來的區塊鏈世界很有可能不會只有一個平台鏈，而是有許多條公鏈並行，每一條公鏈會有差不多的吞吐量及性能，而 dApp 開發者可以像選擇程式語言一樣，根據公鏈生態系及智能合約撰寫語言等等因素做選擇，用較合適的平台開發 dApp。</p><h4>混合中心化</h4><p>區塊鏈的去中心化概念非常吸引人，程式與資料被保存在網路中的分散節點，不需要維護後端伺服器及資料庫的成本，且只要網路存在就可以保障服務可以持續運行，對於用戶來說也可以看得到鏈上的邏輯，公開且透明化。</p><p>然而實際操作撰寫過智能合約就會發現，現階段的智能合約其實仍有相當多的限制，光是最基本的產生隨機數，就可以讓大部分的區塊鏈開發者傷透腦筋，遑論一些複雜的商業邏輯。</p><p>因此，我認為去中心化的區塊鏈網路在短期仍然不能完全取代現有的中心化網路，但是兩個世界可以截長補短，透過去中心化網路確保虛擬資產擁有權，在鏈下的中心化網路撰寫商業邏輯，混合中心化的應用將能結合兩邊的長處。</p><h4>Seamless UX</h4><p>如前面所述，區塊鏈應用對新手來說仍然非常的不友善，進入的門檻相當高，絕大多數的 dApp 都會讓人覺得”啊，這跟我平常使用的 app 不一樣”，會在心中把 dApp 跟傳統 app 區分開來。</p><p>以我自己的經驗，即使是智能合約發展最久、生態系相對最完整的以太坊，仍然對一般用戶有不小的心智負擔，開發者體驗也還有相當相當大的進步空間，因此如何能透過基礎建設、周邊生態系讓使用者能幾乎無痛的開始進入去中心化應用世界，幾乎可以算是這個領域的聖杯，因此這也一直是 Blocto 在努力的目標(無情置入)。</p><p>最好的區塊鏈應用體驗，就是讓使用者感覺不到自己正在使用區塊鏈應用。</p><h3>結語</h3><p>幣圈打滾了半年多，不敢說自己是否真的已經對區塊鏈技術有足夠了解，但是確實已經顛覆了我 2014 年以來的許多觀念，雖然對於區塊鏈技術的未來仍然還是抱持不少懷疑，但是已經從絕對的反對方漸漸變成中立偏正向的態度了，黑轉路人的概念。</p><p>經歷了整年的大牛市，區塊鏈與加密貨幣的應用逐漸從小眾市場走向主流，身為一個做技術的人，我認為如果能將一些技術面的細節推廣給更多人知道，消弭檯面上的資訊不對等，雖然可能會讓很多有心人士少很多割韭菜的機會，但長期而言對這個領域應該會是一個比較健康的發展。</p><p>另外，小米創始人雷軍的名句：站在風口上，豬也能飛起來。現在的區塊鏈市場正在風口上，GameFi、NFT、元宇宙、P2E 遊戲，有太多太多新名詞冒出來，但是風口上的豬，風一停還是會摔死的，對我而言現在區塊鏈市場大多都是豬，想要順著風起舞的人最好還是多小心為上，海水退了，才知道誰沒有穿褲子。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec907c4f6392" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[為什麼我從 Google 辭職而為自己工作]]></title>
            <link>https://medium.com/@yanglin_68397/%E7%82%BA%E4%BB%80%E9%BA%BC%E6%88%91%E5%BE%9E-google-%E8%BE%AD%E8%81%B7%E8%80%8C%E7%82%BA%E8%87%AA%E5%B7%B1%E5%B7%A5%E4%BD%9C-aeba39005d38?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/aeba39005d38</guid>
            <category><![CDATA[中文]]></category>
            <category><![CDATA[職涯]]></category>
            <category><![CDATA[人生]]></category>
            <category><![CDATA[google]]></category>
            <category><![CDATA[軟體工程師]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Tue, 11 Feb 2020 17:39:18 GMT</pubDate>
            <atom:updated>2020-08-09T17:45:52.745Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>此篇為翻譯轉載，已獲得原作者同意</blockquote><blockquote>原文： <a href="https://mtlynch.io/why-i-quit-google/">https://mtlynch.io/why-i-quit-google/</a></blockquote><blockquote>翻譯參考：http://www.codeceo.com/article/why-i-quit-google-to-work-for-myself.html</blockquote><p>在過去四年時間裡，我在Google擔任軟體開發工程師。 (2018年)2月1日，我辭職了。因為他們拒絕買聖誕禮物給我。</p><p>好吧，其實裡面還有更複雜的原因。</p><h4>剛開始的兩年</h4><p>這兩年，我深深地熱愛 Google。</p><p>當”年度員工調查”問我五年後是否期望還留在谷歌時，答案是毋庸置疑的。</p><p>五年後我當然依然還會在谷歌。我的周圍有著全世界最優秀的工程師，我們使用的是全世界最先進的開發工具，我們還可以免費享受世界各地的美味食物。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*IxaK7BhLhEnS3dP7.png" /><figcaption>我在谷歌的典型一天</figcaption></figure><p>我最近的業績評定是”遠超乎預期”。如果繼續保持這種態勢的話，我很快就能晉升到更高一級的資深軟體工程師。多麼厲害的頭銜！以後在我的職業生涯，我就可以自豪地說，“對，我曾在 Google 擔任資深軟體工程師。“聽到的人肯定會十分印象深刻。 我的經理向我保證我很快就能晉升，他覺得我已經有能力從事進階工作了，我只需要用合適的專案向晉升委員會證明即可。</p><h4>經理不給你晉升？</h4><p>不是的，這和經理無關，因為 Google 的經理不能晉升他們的直接下屬。他們甚至沒有投票權。</p><p>相反，晉升的決定權在於由資深軟體工程師和經理組成的小型委員會，在決定晉升之前他們甚至從未聽說過你。</p><p>申請晉升你需要整理”晉升資料集”：收集來自隊友的書面建議，你創建的設計文件以及你撰寫的小型論文，通過這些來解釋為什麼你值得晉升。</p><p>然後晉升委員會與其他少數人一起審核你的資料集，花一天時間來決定誰能晉升，誰不能。</p><p>在我與 Google 前兩年的蜜月期，這個系統聽起來很棒。我的命運掌握在一個從未見過我的神秘委員會手中。他們不會有任何偏袒也不受政治的左右。他們會看到我所有的努力，他們會因為我高品質的程式碼和精明的工程決策而認可我。</p><h4>但事情其實並不是這樣運作的</h4><p>在我整理我的第一份晉升資料集之前，我從未想過它運作流程的後勤方面。</p><p>在我的腦海裡，晉升委員會就是這樣一個站在上帝視角的公正組織。如果每一天我都全心全意地選擇要解決的正確問題，努力提高程式碼的品質，竭盡全力幫助我的團隊高效執行，那麼晉升委員會就會神奇地無所不知並因此而獎勵我。</p><p>然而，事實是，它並不是這樣工作的。而我花了兩年才弄明白這一點。</p><h4>天真地工作</h4><p>在看清真相前，我的主要責任是一條老舊的資料管線。它多年來一直處於維修模式，隨著負荷的增加，管線因為過大流量而不穩。它經常悄無聲息地停止運作或產生不正確的輸出。其故障需要數天才能診斷，因為自最初的設計規範開始就沒有人為它寫過文件。<br><br>我自豪又親切地呵護管道使得它恢復了健康。我修復了數十個 bug 並撰寫了自動化測試，以確保它們不會再出現問題。我刪除了數千行程式碼，這些程式碼要嘛已經沒用了，要嘛完全可以被現代函式庫所取代。我為管線添加了文件，以便我的隊友可以隨時了解其結構知識。<br><br>問題是，正如我在晉升時發現的那樣，這些成果沒有一個是可以量化的。我無法證明我所做的任何事情對 Google 產生了積極的影響。</p><h4>不能測量 = 不存在</h4><p>該管線記錄的指標不多。指標確實會使事情看上去更糟。我的 bug 發現導致整體 bug 數量增加。管線的故障增加了，因為在異常情況下，它將迅速出現故障，而並非悄悄地傳遞錯誤的資料。我大幅減少了開發人員修復這些故障的時間，但是我沒有製定追蹤開發者時間的指標。<br><br>我的其他工作用書面形式表達時也是毫不出色。有幾次，我擱置了自己的專案幾週甚至幾個月時間去幫助隊友，因為他的新發布版本有風險。這對團隊來說是正確的決定，但在晉升資料集中則顯得平平無奇。對於晉升委員會來說，我隊友的專案是一項重要的工作，需要多個開發者的協助。他們能想方設法地讓我幫助他們，這是他們領導素質強大的證據——而我只是一個沒有意識的工作傀儡，反而顯得我本身負責的工作無關緊要，以至於可以隨叫隨到，立刻就能放下手頭的工作。<br><br>在我提交我的第一個晉升資料集時，最後的結果正如我所擔憂的那樣：晉升委員會說我沒有證據證明我可以處理技術複雜性，他們也看不到我對 Google 的影響。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yROsDBNZygXtcNzt.png" /><figcaption>向晉升委員會辯駁我的能力</figcaption></figure><h4>從拒絕中學習</h4><p>被拒絕是一次重大的打擊，但我並沒有氣餒。我覺得我的表現超出了我的程度，但晉升委員會看不到。不過，這是可以解決的。<br><br>我承認頭兩年我實在是太天真了。我沒有提前做好計劃，使得我所做的工作成為了一紙空文。現在既然我明白了這個過程是如何運作的，那麼我只要在繼續做好同樣工作的同時，準備更充分地記錄保存。<br><br>例如，我的團隊會因為誤報而接收大量令人分心的電子郵件警報。以前的我只會解決這些警報。但現在的我知道為了讓這項工作出現在我的晉升資料集中，我首先應該設定測量指標，以便我們有警報頻率的歷史記錄。在晉升考察期間，我就能展示一個令人印象深刻的警報趨勢圖。<br><br>不久之後，團隊分配給我一個看似注定會晉升的項目。該項目很大程度上依賴於機器學習，而這一直是谷歌的熱門話題。它可以自動完成需要數百名人工操作員手動完成的任務，因此它將對 Google 產生顯著和客觀的影響。同時我還需要在整個專案過程中帶領一名初級開發人員——這通常在晉升委員會眼中也可以加分。</p><h4>節日禮物與叫醒電話</h4><p>幾個月後，Google結束了為所有員工提供奢華節日禮物的悠久傳統。相反，他們將禮物預算用於購買偽裝成慈善的廣告(X) Chromebook (O) 給貧困的中小學生。</p><p>此後不久，我親耳聽到兩名員工之間的以下對話：</p><pre>員工A：實際上你仍然得到了禮物。像這樣的花費消減會增加 Google 股票的價值。你可以出售你的股票獎勵用於購買所選擇的任何禮物。</pre><pre>員工B：這不就像是，我告訴我的妻子我沒有為她買聖誕禮物，但她可以用我們銀行賬戶裡的錢購買她想要的任何禮物？ </pre><pre>員工A：你與 Google 構建的是一種商業關係。如果你對 Google 沒有像你為你妻子那樣準備禮物而感到失望，那麼你誤解了這種關係。</pre><p>等等。所以我與Google建立的是商業關係。<br><br>我花了兩年半的時間才意識到這一點或許會讓人覺得有點不可思議，但谷歌在組織內部很好地打造了一個社群意識——讓我們覺得我們不僅僅是員工，我們還是 Google 本身。<br><br>那次談話讓我意識到我不是 Google。我不過是一個向 Google 提供服務以換取金錢的打工者。<br><br>因此，如果 Google 和我之間存在一個可以服務於各方利益的商業關係，那麼為什麼我要花時間在所有這些符合 Google 利益而不是我自己利益的任務上？如果晉升委員會不獎勵 bug 修復和團隊支援工作，那麼為什麼我還要去做這些事情呢？</p><h4>為晉升之路做最佳化</h4><p>我第一次晉升的否決讓我學到了一個錯誤的教訓。我認為我可以繼續做同樣的工作，但是可以做一些事情使得晉升委員會看得我的成果。然而其實我應該做相反的事情：弄清楚晉升委員會想要什麼，然後專門去做那項工作。<br><br>我採用了新的策略。在開始任何任務之前，我會問問自己這是否有助於晉升。如果答案是否定的，那麼我就不做。<br><br>我的程式碼品質標準從“能否在未來5年內仍能維護這份程式碼？”變為“是否可以維護到我被晉升為止？”。我不提交也不修復任何bug，除非它們會威脅我的專案的新版本發布。我設法推脫了所有關於維護工作的職責。我停止了去校園招聘的志願活動。我從每週執行一次或兩次面試降低到零。</p><h4>然而我的專案被取消了</h4><p>優先度被改變了。管理層將我的專案移交給了我們在印度的姐妹團隊。作為交換，該團隊向我們提供了他們的一個專案。這是一個沒有文件記錄的系統，建立在不推薦使用的基礎設施上，但它仍然是產品的關鍵組成部分。分配給我的工作是將此系統從姐妹團隊的程式碼中清理出來，並搬遷到一個新的框架中，同時確保它能在正式環境中運作並達到其性能指標。<br><br>就晉升而言，我這幾個月的努力都白費了。因為我為了那個被取消的專案而沒有發布任何東西，所以我耗費在該專案上的兩個月時間毫無價值。而且我還得花上幾週時間才能加快掌握我繼承的系統，並且在為了保持系統可操作這一苦差事中，我必定會耗費許許多多時間。</p><h4>我到底在做什麼？</h4><p>這是六個月來第三次，我的經理在一個專案的中間重新安排我了。每一次，他都向我保證，這與我的工作績效無關，而是高層管理策略或團隊人員的一些變動。<br><br>此時，我回過頭來想從高層發生的事情。不去想我的經理，他的經理，甚至忽略所謂的晉升委員會。如果我僅僅把另一邊簡化為 Google，會怎麼樣？我們的“商業關係”之間發生了什麼？<br><br>是的，Google 一直告訴我，除非看到我完成了一個專案，否則它無法評判我的工作。但是，因為 Google 中途不停的中斷並將我分配到新的專案，所以我無法完成任何專案。<br><br>整個過程荒謬無比。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4U85NbLejRcnBubn.png" /><figcaption>Google 晉升委員會的處理模式</figcaption></figure><p>我的職業生涯由一個流動的匿名委員會所決定，他們將在一個小時的時間裡決定我的前途。一個我抗議無效的管理決策抹殺了我那麼多月在事業上取得的進步。<br><br>最為糟糕的是，我並不以我的工作為榮。我捫心自問的不再是：“我該如何解決這個具有挑戰性的問題？”而是：“我怎麼才能讓這個問題從晉升的角度看起來具有挑戰性？”我討厭這樣。<br><br>即使我獲得了晉升，然後呢？主流觀念是每一次的晉升都會比上一次更難。為了繼續推進我的職業生涯，我需要範圍更大、涉及合作團隊更多協作的專案。但這意味著該專案可能會失敗，因為會有更多我無法控制的因素，從而浪費數月甚至數年時間。</p><h4>有什麼其他選擇？</h4><p>大約在這個時候，我發現了 <a href="https://www.indiehackers.com/">Indie Hackers</a>。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NqZVfcKpnxMOj1n1.png" /></figure><p>這是一個面對小型軟體創始人的線上社群。要強調的重點：小。這些創建者的目標不是成為第二個祖克柏，而是想從一些適中而又有利可圖的業務中賺點錢糊口。<br><br>我一直對創辦自己的軟體公司非常感興趣，但我只知道矽谷的創業之路。我原本以為成為一名軟體創始人意味著要將大部分時間用於融資，剩下的時間則要擔心如何吸引新的百萬用戶。</p><p>Indie Hackers 給出了一個誘人的選項。大多數會員利用自己的積蓄建立企業，或將其作為全職工作之外的業餘項目。他們不需要答覆投資者，當然也不必向匿名委員會證明自己。</p><p>缺點也是有的。一方面收入不太穩定，另一方面還面臨更多災難性風險。如果我在Google上犯了一個錯誤，導致公司損失1000萬美元，我不用承擔任何後果 — — 我需要做的是寫一篇事後報告，然後每個人都會開心於此次學習機會。但對於大多數創始人來說，1000萬美元的錯誤將意味著企業的破產以及幾輩子的債務。</p><p>在Indie Hackers做創始人的念頭在我腦海中揮之不去，讓我魂牽夢縈。因為無論業務是取得巨大的成功還是一蹶不振多年，都在自己的掌控之中。在Google，我不覺得我可以自己控制專案，更不用說職業成長以及團隊方向了。</p><p>我反覆思索了幾個月，最後終於下了決心。我要成為一名獨立開發者。</p><h4>離職前的最後一件事</h4><p>我在Google上還有沒完成的事情。在為了晉升投入三年時間後，我自己也不想毫無建樹就離開。此時只需要幾個月時間我就可以重新申請晉升了，所以我決定給自己最後一次機會。<br><br>悲劇的是，距離成果統計結束還有六週，我的專案被取消了。又一次被取消了。<br><br>事實上，我的整個團隊都被取消了。這在 Google 是很常見的，而且它還有一個委婉的稱呼：碎片整理(defrag)。管理層將我們團隊的專案移交給我們在印度的姐妹團隊。我的隊友和我都必須從不同領域重新起步。<br><br>不管怎麼說我已經申請了晉升。幾週後，我的經理給我看了結果。我的表現評分是“極為傑出的”，這是最高的分數，每期只給約5％的員工。晉升委員會指出，在過去的六個月中，我清楚地展現了高水準的工作。而這剛好不是我為了最有效晉升而努力的那幾個月時間。<br><br>但他們覺得六個月的追蹤記錄時間不夠長，所以……祝我下次更好運。</p><p>我的經理告訴我，如果我再做六個月的高水準工作，我的晉升機會很大。我不能說我沒有受到誘惑，但到那時為止，在過去兩年時間給我的鼓勵一直都是“六個月後晉升機會很大”。</p><p>所以現在是時候離開了。</p><h4>那麼，下一步呢？</h4><p>當我告訴別人我離開了 Google 的時候，他們認為我一定有一些絕妙的創業點子。只有傻瓜才會辭掉 Google 軟體工程師這份工作。<br><br>我究竟是不是一個傻瓜，見仁見智吧。<br><br>我的計劃用幾個月的時間嘗試一些不同的專案，看看其中有沒有迎合人心會流行起來的，例如：<br><br>- 繼續致力於 <a href="https://mtlynch.io/ketohub-month-3/">KetoHub</a>，看看我能否實現盈利<br>- 在 Sia 上建立業務，這是我經常用到的分散式儲存技術<br>- 花更多時間撰寫程式，並尋找從中賺錢的途徑</p><p>Google 是一個偉大的工作場所，我在那裡學習了許多寶貴的技術和技能。辭職是一個很艱難的抉擇，因為我還有更多需要學習的東西，但要找 Google 這樣的雇主總還是可以的。我不會一直有這樣的自由可以順從本心地創辦自己的公司，不知道我能走多遠，期待我的成果吧。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aeba39005d38" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2019 年回顧 — 菜鳥網頁工程師的職涯分享]]></title>
            <link>https://medium.com/@yanglin_68397/my-2019-wrap-up-as-a-rookie-web-developer-e0170119734e?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/e0170119734e</guid>
            <category><![CDATA[前端]]></category>
            <category><![CDATA[程式設計]]></category>
            <category><![CDATA[職涯]]></category>
            <category><![CDATA[2019]]></category>
            <category><![CDATA[網頁設計]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Mon, 30 Dec 2019 13:29:27 GMT</pubDate>
            <atom:updated>2020-06-05T15:34:37.774Z</atom:updated>
            <content:encoded><![CDATA[<h3>2019 年回顧 — 菜鳥網頁工程師的職涯分享</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*TBQ_TeQQXWP35s78D2tfQQ.png" /></figure><p>2019 年快要劃下句點了，差不多是個時候來做個整年度的 review 。2019 年這一年，各種意義上都讓我覺得成長許多，但是要細說我私人的一些體悟的話有點族繁不及備載，可能也不是那麼有營養，所以在本篇我會比較著重在職涯上的一些心得分享。</p><p>這一整篇文章分成幾個部分來解構這一年我在我自己身上看到的改變，包含身份轉換、做為一個菜鳥網頁產品工程師的心得、變成社會人之後的生活步調改變與省思，以及對個人未來職涯發展的想法。</p><h3>身份轉換</h3><p>今年是我正式開始全職工作的第一年，在一個完全陌生的城市一個人開始新生活，是一個滿不可思議的體驗。以往在學校的時候，住在宿舍或著家裡，即使不一定想，也會每天接觸到室友、同學、家人、朋友；現在下班回到家，就完全只有自己一個人了。</p><p>剛開始的時候覺得很興奮，時間完全都是自己的，感覺非常的自由，但是過了幾個月之後說真的還是會覺得有點寂寞。本來以為透過網路，就多少還能跟老朋友保持聯絡，但是別人也會也有自己的事情要忙，很難在你想找人說說話的時候剛好就有個人在那空閒著，透過訊息文字跟真人直接對話還是有本質上的差別。</p><p>前幾週生了一場重感冒，發燒到 38.5 度，躺在床上昏沉的時候，好幾次都會閃過「如果就這樣死翹翹了，會不會也沒有人發現」這樣子的念頭。最後還是認命的走路去看醫生 😆。</p><p>此外，當學生的時候，隨時隨地都會有事情可以忙 — 雖然跟我個人在當學生時的時間規劃也有關係，我屬於那種有點工作狂的人，總是會有很多計畫、專題、社團、球隊 …… 各式各樣的活動，修課也排得很滿，下課永遠都有作業、計畫進度等等各式各樣的問題可以操心，所以總是很忙碌。</p><p>可能跟大部分人想法很不一樣，我覺得當學生遠比當上班族忙碌的多，有可能是因為交作業大學的作業量，也可能是我自己把自己推太緊，不過我真心的覺得上班比讀書時清閒多了。學生永遠有排定好的考試、作業、活動可以忙，但是上班族下班之後的時間，就完全都是自己的了。</p><p>沒有人告訴你應該做什麼，或不該做什麼。自由本身是祝福也是詛咒。</p><blockquote><strong><em>人類是註定要受自由之苦的</em></strong> – 尚-保羅・沙特</blockquote><p>不過，過了比較難熬的幾個月之後，最近有慢慢調整生活的方式。也因為有很多時間跟自己對話，所以思考了很多人生的不同面向。這部分會留到下下段落再繼續。</p><h3>菜鳥網頁工程師</h3><p>這裡必須先打個預防針：雖然以全職工作來說我確實是全新的開始，但以寫程式的經歷來說，我認真學寫程式的時間大約已經有六年、網頁相關的專案經歷大概也有三年了，大概也做過四五個小專案，所以從技術角度看我大概不太能算是菜鳥，我也不會在這邊深入講技術相關的部分。如果是如白紙一樣的新鮮人可能沒太大的共感，可以上一頁離開了(先不要啦QQ)。</p><p>其實在四月的時候就有寫過一篇文章講自己的心得跟介紹 Y 社，有興趣的人也可以順便看一下(硬要置入)。</p><p><a href="https://medium.com/@yanglin_68397/hello-world-%E5%9C%A8-yourator-%E7%9A%84%E5%85%A9%E5%80%8B%E6%9C%88%E9%9B%B6%E4%B9%9D%E5%A4%A9%E8%88%87%E7%A4%BE%E6%9C%83%E6%96%B0%E9%AE%AE%E4%BA%BA%E7%94%9F%E6%B4%BB%E9%9B%9C%E8%AB%87-b7c5f2c8e0fa">Hello world — 在 Yourator 的兩個月零九天與社會新鮮人生活雜談</a></p><p>雖然算是有不少實務經驗，但是真正開始工作才發現：寫程式大概只佔工程師的 50% 不到的時間。以我最近的工作狀態來說，可以心無旁騖的寫程式的時間，一個工作天八小時裡面能佔到三、四個小時就很了不起了。</p><p>那剩下的時間在做什麼呢？大多數是會議及討論，會議包含產品的規格、驗收、工作回顧、code review 等等，有時候也需要快速地跟行銷、設計、BD 討論一些規格及小 bug 修正。值得一提的是我有實際參與過幾次客戶訪談，這可能是大部分工程師不太會遇到的。能第一線知道用戶的回饋，而且可以直接提問討論想法，其實對做產品滿大的幫助。</p><p>除此之外，在 Y 社個人覺得做得不錯的一點是 <strong><em>學習組織</em></strong>。目前每週會有一次讀書會讓大家分享自己有興趣的主題，而工程團隊也有自己的讀書會。準備讀書會雖然也會吃掉工作的一部分時間，不過可以讓大家共同提升，個人覺得算是滿划算的。</p><blockquote>Together, We Go Far. — 交大校長張懋中</blockquote><h4>挑戰</h4><p>很多人或許會覺得，工程師就是悶起頭來一直寫程式就好，不太需要跟人溝通，input coffee output code — 如果你也是這樣想就大錯特錯了。</p><p>工程師其實是很需要溝通和表達的生物。尤其是在新創的環境裡，我們的目標及商業需求可能會變得非常快，如果沒有確實溝通好規格的話，很容易造成做出來的東西跟預想的不同，或是無法正確傳遞我們想要的價值的狀況。</p><p>在 CPU 設計裡面有個名詞叫做 pipeline stall：CPU 是由很多不同的階段構成的，以產品來說就是一個需求會經過很多人 — User, PO, UI/UX, RD, QA，簡單列一下就要過好幾個管線，而 pipeline stall 就是指管線過長時，如果有某個地方出錯，勢必要回到前面的階段重跑，而通常這樣的代價很大。</p><p>避免 pipeline stall 的方法，一個就是讓管線不要這麼長，或著是不要讓管線斷掉；對應到工作流程上的話就是，一個需求不要經手太多的人，越精簡層級越好，溝通能越準確透明越好，避免溝通不確實造成的重工。</p><p>除此之外，雖說有很多公司都是一個人橫跨多個產品，但是在多個產品線上切換其實是相當消耗精力的。在新創裡，每個人往往都要身兼多職，才能應付快速變動的市場需求。</p><p>所以即使技術能力已經足夠 cover 工作所需，也大概只涵蓋工作內容的 50% 甚至更少而已，軟性的能力也是工程師—尤其是產品工程師—很重要的基本素養。除非你是頂尖中的頂尖的技術人才，在技術層面有非常高的不可取代性，不然無可避免的，你還是得跟其他人頻繁的交流，即使不是走管理職也一樣。要從用戶或老闆有時候有點衝突的需求中抽理出真正要傳遞的商業價值，需要很清晰的邏輯跟對產品的理解，所以如果你是因為不喜歡人而喜歡寫 code 才選擇做工程師的話，你很可能需要多思考你的決定。</p><p>噢不過，技術面的基本功還是很重要，50% 的工作就足夠吃力的話，剩下 50% 再把握不好日子就有點難過了。幸運的是技術的基本功基本上可以靠自己努力，而上面提到的能力很多都要在專案協作中學習。</p><h3>生活步調</h3><p>比對四月的文章，那時候還處於塵埃尚未落定、充滿新鮮感的時候，因為每天都很忙、剛開始跑 scrum 新工作流程、住處很多東西還沒整頓好…等等，所以每天都過得很忙碌，跟熟悉的朋友們也才剛分離一下下沒什麼實感，所以沒什麼時間沈澱下來思考一些關於自己的事。</p><p>時間又過了半年多，生活逐漸趨於穩定之後，漸漸的有時間想自己的下一步，也因此有一些關於自己的體悟。</p><p>前面說過我屬於有點工作狂的那種人，對閒下來有一點莫名的恐懼。但我其實並不是只有工作，我彈吉他，我打排球，運動，會自己一人到 costco 買自己吃不完的食物，如果有空的時候我也偶而會嘗試自己做甜點。</p><p>我其實認為我的興趣很廣泛，也過得相當忙碌(是真的！)，理應該過的更快樂，但是卻覺得哪裡不太對。</p><p>發現的問題之一是自己的生活太過太規律。別誤會，我很喜歡規律的生活，有紀律的按照步調走超棒的，不用擔心明天會發生什麼事，不用為太多瑣事煩惱。</p><p>但是太過規律這件事也是一個警訊。我可以輕易的列舉平常工作日的行程：每天早上8:50起床，漱洗完畢 9:10 出門，9:18 分搭上捷運，9:46分抵達北車，9:51分打卡上班，18:51 打卡下班，約 19:50 回到家，吃完飯 20:20 做點簡單的重訓運動，21:00開始練吉他到 23:00，看點短片、洗澡、睡覺、起床，又是新的一天。</p><p>我的生活規律到分鐘等級，雖然確實是有下班後的活動，但是當生活規律到這種程度的時候就變成有點作業感，像是工作的延伸了。這一點讓我覺得有點恐慌。雖然這樣的生活不算不快樂，但是如果這樣的生活持續五年、十年、二十年，我會覺得很不對勁。我甚至還在年底時發現我的特休還剩好多，但是卻完全沒有想法特休要做什麼，假日要做什麼。</p><p>這大概也是某種程度的 burnout ，對於一成不變缺乏刺激的生活感到空虛，雖然持續個幾個月、甚至到一年，可能還不錯，但是再多下去就有點可怕了。談到 burnout ，就想到最近在聽的 podcast 頂樓加蓋(哇還置入其他棚)，Ep3 有談到 burnout 及自我探索的部分，也有給我一點啟發。</p><p><a href="https://twitter.com/overbuild_io">Overbuild/頂樓加蓋</a></p><p>發現到自己的同事，或著已婚有家庭生活，或著有穩定感情關係，或著參與一些線下活動，也給我另外一個啟示：我下班後的生活太封閉了。雖然有一個人的自由，但是完全沒有跟人接觸真的會讓人跟世界失聯，也因此這幾個月，公司有活動的時候我都儘量去支援，也比較積極的參與技術社群的活動。</p><p>當然也不是說一定要接觸人群才會快樂，有些人也是自閉的很快樂(?)，而有很多人喜歡用旅遊來轉換節奏，有些人可能會用追劇、看書等等靜態活動充實生活。不過我發現我個人其實還是很喜歡跟人交流的，所以其實不是一定要接觸人群，重點應該是：找回自己的「熱情」。太習慣一成不變的生活很容易會讓人忘記自己的熱情是什麼，而我給自己的其中一個答案就是「透過分享去影響這個世界」，這也是我開始經營自己的技術內容粉專的原因。</p><p>既然都說到技術內容粉專了，不置入一下怎麼行？請大家多給<a href="https://www.facebook.com/%E6%9A%98%E6%9A%98%E7%A8%8B%E5%BC%8F%E5%BF%83%E5%BE%97%E9%9A%A8%E7%AD%86-103934994422018/?modal=admin_todo_tour">暘暘程式頻道</a>捧個場，乾溫乾溫。</p><p>總之近幾個月下來，多參加了一些活動、多接觸了一些人，真的有比較找回跟世界的連結感，雖然也可能有一點太多 — 上個禮拜甚至連續三天下班後跑了三場不同的活動，但終於感覺到某個什麼東西在推動了。<strong>工作與生活的平衡調整</strong>很可能是我這一年最大的體悟，社會人已經不再像當學生時有(非常明確的)升學壓力、求職壓力、經濟壓力，學習如何運用自由的時間並且維持自己對生活的熱情變成新的一個課題。</p><blockquote>人生就像騎單車，想保持平衡就得往前走</blockquote><blockquote>— 阿爾伯特·愛因斯坦</blockquote><h3>對職涯的思考</h3><p>前面講了一些目前工作、生活上的調整，接下來要討論的就比較偏向自己對未來在工作方面的想像跟省思。</p><h4>轉換</h4><p>事實上我將要從 Y 社離職了。</p><p>誒？前面鋪墊了這麼多，居然就要離職了？</p><p>契機大概是今年八月左右跟朋友們去日本畢業旅行。以往我其實對出國旅行或生活沒有太多興趣，拜家裡有一個很愛出國玩的媽媽所賜，我小時候去過的國家一隻手數不完，得到的結論就是 — 台灣真棒。我一直覺得如果要選一個地方定居終生，很難找到比台灣更好的國家了，J丟喜愛歹丸啦。</p><p>不過這次出國跟以前不太一樣，除了不是被家人拉著跑之外，因是為完全自由行的關係，我們必須實際跟當地人交流、互動，實際體驗真正的在地人是怎麼生活的，那邊的環境有什麼樣的優點、又面臨什麼樣的挑戰跟問題。</p><p>這帶給我一些想法是，有時候出去看看世界並不 (只)是為了知道別人有多好，而是可以從不同的觀點回頭審視自己。知道自己比別人有什麼優勢跟劣勢，從一個不同的角度重新審視自己，才能更完整的拼湊出自己真實的樣貌。</p><blockquote>最短的捷徑就是繞遠路，繞遠路就是我最短的捷徑 。</blockquote><blockquote>— 傑洛・齊貝林</blockquote><p>當時在工作上，其實也剛好遇到一個瓶頸。</p><p>並不是技術或是政治、效率上的瓶頸，而是我開始意識到我的工作有點重複了。工程師是一種最討厭重複的生物，同一段 code寫兩次就要寫成 function，同一個功能被用到兩次就要包成 module，而我意識到雖然我做得還不錯，但我好像在重複做類似的事情了。</p><p>那時候其實有跟一些朋友還有前輩聊到，也是很接近前面所說的概念：我不討厭現在正在做的事情，但是如果想到五年、十年後我還在做一樣的事情的話，我會有點恐慌。生活已經過的很單調，連工作都開始重複的話，我應該會快速喪失生活的熱情。</p><p>當然還有一點是，我覺得我還太年輕。如果我 30、35 歲，即使重複一樣的事情，我可能就會選擇安逸，安全舒適的繼續下去了，但我才 23 歲，現在就開始平穩好像太早了一些。雖然我嘴巴上說想過跟植物一般平靜的生活，但我想在我還能拼的時候，還是希望能夠多嘗試不一樣的跑道、體驗不同環境、甚至不同國家的文化，探索更不一樣的自己吧？</p><p>綜上所述，我覺得可以把我想轉換的想法歸納為一個概念：<strong>跳脫舒適圈</strong>。在舒適圈待太久，是會麻木的，不是說待在舒適圈不好，但是對我來說可能早了點。</p><p>這段時間跟不少朋友、前輩還有老闆談過，很感謝老闆非常的開明 🙏。職場鬼故事聽多了就覺得，最後能好聚好散也是十分不容易的事。</p><h4>職涯心得</h4><p>再來想談一些這一年來工作上得到的、關於工程師職涯發展上的心得。</p><p>先來談談<strong><em>技術</em>。</strong></p><p>網頁圈的技術變化的幅度非常巨大，同一個工具可能一個月出一次小板本，半年出一次大版本，一年就面目全非了。</p><p>在這樣快速迭代的生態系裡，如果只學到最末端的 API、使用方式，而沒有學到工具真正的精神的話，就會無法理解為什麼而改變，不斷試圖去抓住變化的潮流卻什麼都抓不住。對於技術相關的話題我覺得也沒什麼特別需要說明的東西，多看文件、多做範例、多想為什麼，只有當你真正開始做了什麼東西並深入思考其背後的原理的時候，才是學習一樣技術的開始。</p><blockquote>天地滂沱如何渡？蓑衣褪盡任濁流！</blockquote><blockquote>— 刃無鋒・殤不患</blockquote><p>再來談談<strong><em>管理</em></strong>。</p><p>以前覺得管理者，就是一個 main function，把所有工作拆給所有 sub-function 讓他們去處理，最後把 return 的結果收集起來就好。</p><p>工作了一年之後才發現，管理著實是一個大學問。實際上來說應該比較接近 load balancer ，request 進來之後分派給不同的 node，要能夠知道哪個 node 現在 loading 重、哪個 node 死了，決定 request 要怎麼分配才能達到最大效益。</p><p>這兩個比喻可能都有點太 geek，總之我認為管理最大的困難在於：人並不會是完美無缺、具有一致性的，每個人在不同身心狀態、工作環境、生活因素之下，工作的效率、思考方式、採取的行動也會有所不同，以 load balancer 來說，要知道各 node 的 loading 的數據都還算容易，但是人的不可預測性高的多。</p><p>程式是沒有意見跟觀點的，給定怎麼樣的 code 電腦就會做什麼樣的事情，但是人是有觀點、意見跟情緒的。同樣的一件工作或任務，可能因為觀點不同，導致最後結果出現分歧，因此溝通是管理很重要的一環，確定大家 on the same page，對要傳遞的價值有明確共識。</p><p>再來想談論的是<strong><em>如何定義自己的價值</em></strong>。</p><p>如果對金融體系有一點研究的話，會知道「價值」跟「價格」是一件不一樣的事情。消費者主觀的感受是該商品的價值 (Value)，而市場經濟機能體現出來可以量化的是價格(Price)。</p><p>有很多求職、履歷健檢課程，教大家怎麼包裝、行銷自己，凸顯自己的長處。當然不是說這類型課程不好，畢竟敝司也有做這樣的課程。</p><p>既然都提到了，雖然這篇置入實在有夠多，但我還是要在這硬是插入一波置入：敝司老闆嘔心瀝血之作，「<a href="https://hahow.in/cr/resumeclass">求職平台大揭秘！寫出讓人資心動的專業履歷！</a>」課程 ，社會新鮮人或是求職碰壁的求職者可以參考😎😎😎😎。</p><p>包裝自己是彰顯自己的價值、進而提升自己價格的一種方式，但是任何行銷工具手段，最後都還是要回歸：你 — 作為求職市場上的一個產品 — 所能提供的價值是什麼。</p><p>在價值與價格的基礎上可以分成三類人：價值 &lt; 價格，價值 &gt; 價格，價值 = 價格。</p><p>市場上，如果價格一味的升高，而價值卻沒有跟上的話，就會走向泡沫化。以這個角度來看人的話，有些人會過度膨脹自己的價格，利用話術、行銷、人脈來包裝自己，但是實際的價值卻及不上自己的價格，終有一天，就會被人看破手腳。</p><p>而如果價值很高卻賣不出好價格，不能只是怨天尤人、抱怨別人沒眼光，而是發現自己的價值並設法讓別人感受到。作為工程師來說，有時候我發現資深工程師跟初級工程師的差異，「自信」往往是很重要的一環。當覺得自己能力不夠，你就無法相信自己的決策跟判斷，懷疑自己是否有能力而做到。當你能夠展現出駕馭所有狀況的自信，往往才是真的邁進到職涯下一階段的時候。</p><p>然而「自信」是建立在足夠了解自己，也足夠了解現狀的前提之下。不夠了解狀況的人也會有莫名的自信(Mount Stupid)，必須要遇到一些自己無法解決的問題，掉入 valley of despair ，並設法從裡面走出來，才是真正的建立起可以撐起自己價格的價值的開始。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/840/0*-h-Tm5BDAOdJNqEi" /></figure><p>認識自己，了解自己的價值，進而提升自己在求職市場上的競爭力，是我覺得不只是工作上，也是人生目標上很重要的一個課題。而有了價值之後，如何說服別人你有這個價值，是另一個也需要花費很多心思去經營的目標。</p><h3>結語 &amp; 新目標</h3><p>最後來從比較高的維度來定義一下明年的職涯目標：</p><ul><li>調整工作與生活的平衡，找回自己的熱情。</li><li>嘗試不一樣的文化、不一樣的環境，踏出自己的舒適圈。</li><li>更認識自己，了解自己的價值，並讓自己的價格符合自己的價值。</li></ul><p>雖然這篇文章標題寫菜鳥網頁工程師，但其實 87% 的內容跟網頁工程師沒有太大關係😆，會不會被人說是標題詐欺？比較像是我個人對第一年工作所學到的體悟，以及對未來自己的期許。希望各位觀眾看完可以得到一點收穫或是靈感囉~</p><blockquote>一個人生命中能達到最了不起的成就，無非就是發現自己，並勇敢成為自己 。</blockquote><blockquote>— 侯文詠《我的天才夢》</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0170119734e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[react-dev-tool v4 overview]]></title>
            <link>https://medium.com/@yanglin_68397/react-dev-tool-v4-12098f34707f?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/12098f34707f</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[中文]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Wed, 25 Dec 2019 07:26:41 GMT</pubDate>
            <atom:updated>2019-12-25T08:09:30.477Z</atom:updated>
            <content:encoded><![CDATA[<iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FMjrfb1r3XEM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DMjrfb1r3XEM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FMjrfb1r3XEM%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/271fb71e5447474368a52a5440c596b8/href">https://medium.com/media/271fb71e5447474368a52a5440c596b8/href</a></iframe><p>今年的 React conf 2019 也如往年一樣出現了不少新東西，讓人感受到 react 社群充沛的開發創新能量，與蓬勃發展的生態系。雖然還沒有看過全部影片，不過其中有一個更新特別吸引我的注意 — 全面升級版的 react-dev-tool。</p><p>debug 永遠是工程師心中的痛，我們工作內容大部分時間都在與層出不窮的 bug 周旋，尤其是那些無法重現、如不定時炸彈般的 bug，如果炸開在週末下班前，整個週末大概都不得安寧。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*12xxNV8_waZpCT4Igv45Gw.png" /></figure><p>最近聽了一些案例，甚至有因為偵錯工具生態系還沒有追上，所以忍痛不使用某些套件的狀況，可以說 debug &amp; develop 相關的輔助工具是一個套件生態系很重要的一環，因此 react 團隊聽見大家的聲音，大幅更新了 react-dev-tool 的功能，不僅更好的支援了新的 API，在 UX 上也做了許多優化，效能方面也比以前更好。以下逐一介紹 dev tool 新增的功能：</p><h4>瀏覽 App 架構</h4><p>在瀏覽一個 project 的架構時，新版的 dev-tool 可以直接點擊 component，就可以在右邊側欄看到 props/state/hooks，以及該 component 的 parent — 包含所有的祖先。</p><p>props/state/hooks 的編輯現在變得很容易，只要點擊兩下就可以了直接編輯了，十分方便。不只是字串，連物件也可以填入 JSON 字串來編輯。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C7qW4dIquCD_kMXG5Prt9Q.png" /></figure><h4>檢視功能</h4><p>除了可以用上方的搜尋欄，也可以按右上角的小齒輪進去做一些設定，濾掉一些不想看的 component (如 context 相關的)。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DT9EgWrGm_dbs-zjAxz4mw.png" /></figure><p>檢視元件時，右邊側欄有三個小按鈕</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/675/1*vc55i8kZ5gb2HBcjk99noA.png" /></figure><p>最右邊的🐛形狀的按鈕，可以將檢視中的 component 的資訊 log 到 console，如此一來就可以在 console 中做一些進階互動。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/995/1*Ee3u9GhYzMiDQLRPAjE1bw.png" /></figure><p>中間的眼睛形狀的按鈕，會直接跳到對應的 DOM，也可以從上面提到的🐛按鈕 log 的 Nodes 資訊中連過去(影片中有人在這邊鼓掌歡呼，終於可以不用找到 component 再自己回推 DOM 在哪裡了)。</p><p>左邊的時鐘按鈕則是可以 toggle suspense，這部分因為 Suspense 還是實驗中的 feature，可能不太有人有共感，簡單說就是可以測試 Suspense 的 fallback 元件是否如預期中渲染 。更詳細的部分請參<a href="https://reactjs.org/docs/concurrent-mode-suspense.html">考官方文件</a>。</p><h4>錯誤訊息整合</h4><p>影片中提到現在 react call stack 可以整合第三方錯誤訊息，使套件開發者提供的錯誤訊息更容易看懂，不過我個人是還沒玩出來，也可能有 API 提供給套件開發者？這部分比較沒看懂。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6HnsnPbMboA9BcCVDuo0_A.png" /></figure><h4>Reload &amp; Profile</h4><p>以往的 profiling tool，重整後必須自己按下錄製鍵，才能監測這段時間內的 效能狀況。而新版的 dev tool 直接新增一個 reload and start profiling 的按鈕，可以重整之後，錄製從第一次渲染開始的 profile。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xAX12xUPIjuOd-2cuIh8hQ.png" /></figure><p>另外 profile 檔案現在可以 export 出去，也可以重新 import 回來，雖然還不確定 import 回來有什麼用 XD，可能方便 peer review 吧。</p><h4>why did it render</h4><p>自己玩的時候很難試出來，因為真實世界的 app 元件數量實在太多了。profiler 的設定有一個選項是可以針對個別元件紀錄為什麼會重新 render，在錄製的時候跟元件 DOM 做一些互動，就可以在 profiler 右側看到因為什麼緣故導致了元件重新渲染。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jNq7yRW67rJvMAB0wd14GA.png" /></figure><p>雖然大家都為這個功能歡呼，但是我個人還是覺得不夠好用 …… 以前曾有一個套件叫做 <a href="https://github.com/maicki/why-did-you-update">why-did-you-update</a>，可以直接在 console 看到哪些元件有更新、更新的原因是什麼，甚至可以分辨變動的屬性是 strict equal 還是 loose equal，如果是 loose equal 造成的 re-render 或許就可以避免，或著 function property，就可以用 memoized 的方式避免 re-render。然而這套件作者似乎太忙碌不再更新了，實在是有點可惜。</p><h4>Misc &amp; UX improvement</h4><p>一些 ux 上的小調整</p><ul><li>remember selection after reload</li><li>better search UX (搜尋時會有 highlight了！)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DzGVNmIgKkA4Kq7MBpNC_A.png" /></figure><ul><li>HOC badge(HOC 改成顯示在外面，而不是以前的 <strong><em>withHOC(component)</em></strong> 的形式)</li><li>smart indentation(component 層數很多時，自動調節排版的寬度)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DmL6x1taVL_D7uqRDuUMaw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Kakh1TnFXP3pCM0NXC7PLg.png" /></figure><h4>總結</h4><p>雖然有一小段時間沒使用 react-dev-tool 了 — 主要是因為早期的版本真的不怎麼好用 — 所以不太確定這一波改動( 3 →4)到底多大，不過以往的痛點都解決的很不錯，UI/UX 上的體驗也比以前好得多(甚至支援 dark mode！)，有好的debug 工具真的可以讓檢索 bug 的枯燥流程變得舒服許多呢！🤟</p><p>如果有人還沒使用過 react-dev-tool 想玩看看這些功能的話，可以到官方提供的這個 <a href="https://react-devtools-tutorial.now.sh/">playground</a> 玩玩看。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=12098f34707f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[好用的 Bootstrap 4 utilities class]]></title>
            <link>https://medium.com/@yanglin_68397/%E5%A5%BD%E7%94%A8%E7%9A%84-bootstrap-4-utilities-class-79484fa4c506?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/79484fa4c506</guid>
            <category><![CDATA[html]]></category>
            <category><![CDATA[bootstrap-4]]></category>
            <category><![CDATA[中文]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Sun, 19 May 2019 12:53:24 GMT</pubDate>
            <atom:updated>2019-05-19T12:58:46.183Z</atom:updated>
            <content:encoded><![CDATA[<p>Bootstrap (以下用 BS 簡稱) 第四代版本從 2018 年 1 月發佈至今已經過了一年有餘，作為一個廣為流行的 UI 框架來說，從 BS3 到 BS4 做的改動其實相當大，包含底層的採用 SASS、 Flexbox 、styleshet 模組化，以及表層設計上更加彈性的 UI 元件、更明亮的主題色微調等等。</p><p>然而使用 BS4 之後最使我驚艷的部分其實不是上述的這些改動，而是新引入的 utilites class ，讓開發時的舒適度頓時提升了好幾個檔次，實在是居家旅行，殺人滅口，必備良藥。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/560/1*qDGCCF5YCp629AntdpT42w.jpeg" /></figure><p>吹捧了這麼多， utilities class 到底是什麼呢？</p><p>基本上 utilities class 包含了一些 functional CSS 和 atomic CSS 的概念，透過<strong>把常用的 style (margin, padding, text-align, flex… 等等)抽出來做成獨立的、單一職責的小 class</strong> ，這些小 class 通常非常非常小，可能只包含 1 條 css rule，<strong>透過組合這些小 class 來做到複雜的 style</strong>。</p><p>那麼到這裡就會有人提出一個問題：<strong>既然這些 class 只有一行，為什麼不用 inline style 就好了呢？</strong></p><p>其實這也是 functional CSS 或 atomic CSS 常見的問題。我們可以從幾個面向來看：</p><ul><li>效能： 用 css class 來寫 stylesheet rule 的渲染效能通常會比 inline-style 來得好，這可能牽涉到瀏覽器的實作。數據可以參考這個連結：<a href="https://jsperf.com/classes-vs-inline-styles/4">https://jsperf.com/classes-vs-inline-styles/4</a></li><li>可複用性：將同樣的 style 寫成同一個 class ，就可以快速的通用在所有程式碼中。</li><li>一致性：同樣是微調 margin，有時候你可能會寫 margin: 4px ，有時候可能會寫 margin: .25rem ，雖然畫面上看起來相同，但是卻不容易被當成一樣的程式碼。更糟的是這樣的 CSS 規則可能被寫在好多不同的 selector 裡，在重構時會造成巨大的困擾。</li><li>文件/展示分離：我們用 DOM 表示文件的架構，用 CSS 表示文件的樣式，CSS 與 DOM 透過 inline-style 耦合在一起通常不會是一個好主意。舉個例子來說，假設現在我們有個 CMS 系統想做到改變主題色的功能，若所有的 stylesheet 都使用 class selector 撰寫，並且正確的使用變數來儲存色碼，我們可以透過改變變數迅速而簡單的改變整體主題，而使用 inline style 就會變得很痛苦。</li></ul><p>基於這些理由，雖然用 inline style 的彈性最好，但是我們通常不把它當作最佳考量，而 functional CSS/atomic CSS 的好處就是在保有的彈性的同時，亦可以統一管理 stylesheet 規則。</p><p>介紹完好處與為什麼我們應該使用這樣的設計方式之後，我們終於要進入正題：到底 BS4 引入哪些實用的 utilities class 呢？</p><p>首先我個人最愛用的是 m-class和 p-class 。m 和 p 分別是 margin 跟 padding 的縮寫，BS4 中可以使用如 {m|p}({side})(-{breakpoint})-{value} 這樣的命名規則的 class 來快速調整元素的 margin &amp; padding，以下舉幾個簡單的例子：</p><ul><li>m-5：元素四周的 margin 是 5級。</li><li>pt-2：元素的上方(top)的 padding 是 2 級。</li><li>mx-md-0：元素左右(x軸方向)的 margin 在 medium 以上的裝置是 0。</li></ul><p>透過組合方向、breakpoint 和等級就可以簡單調出常用的間距，就不需要額外抽出去寫 stylesheet 了 💯 💯 ，從 1~5 級 BS4 預設是從 .25rem 到 3rem ，基本上足以應付大部分的狀況，可參考：<a href="https://getbootstrap.com/docs/4.0/utilities/spacing/">https://getbootstrap.com/docs/4.0/utilities/spacing/</a></p><p>再來是 d-class， d 是 display 的縮寫，顧名思義是用來調整元素的 display 屬性， d-inline-block 代表 display: inline-block ， d-flex 代表 display: flex ，就是如此的簡單！而這些 class 也適用 breakpoint ，所以可以做到如 &lt;div class=&#39;d-block d-lg-none&#39;&gt;&lt;/div&gt; 這樣，在 lg 以下的裝置不顯示的 div 。</p><p>然後是 text-class 跟 bg-class ， text-class 包含 alignment、font-weight、wrap 等等，例如 text-left ，代表 text-align: left 的縮寫， font-weight-bold 代表 font-weight: bold 的縮寫，一樣可以套用 breakpoint，更詳細的內容可以參考文件：<a href="https://getbootstrap.com/docs/4.0/utilities/text/">https://getbootstrap.com/docs/4.0/utilities/text/</a></p><p>而 text 跟 bg 都可以套用主題色，因為一張圖勝過千言萬語，所以我直接天兩張文件的截圖，絕對不是因為我打到這邊已經懶得解釋 😝</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*OLjvlGPZEYgLF_YEB9Oo2g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*bGmOUy4WXJ0TXoVQnK_ldQ.png" /></figure><p>說了這麼多，其實也有點難傳達這個 utilities class 的好用之處，不如我們直接看一段範例，了解 BS3 跟 BS4 的想法與寫法差異。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dpcyjaxTyEgwnrCfnllMcA.png" /></figure><p>上圖這樣一個陽春的、兩個方塊的畫面，用 BS3 的想法寫可能需要寫：</p><pre>// css file<br>.hello {<br>  text-align: center;<br>  background-color: var(--color-primary);<br>  color: var(--color-white);<br>  margin: 1.5rem;<br>  padding: 2rem;<br>}<br>.world {<br>  border: 2px solid var(--color-success);<br>  background-color: var(--color-primary);<br>  color: var(--color-success);<br>  margin-top: 1.5rem;<br>}</pre><pre>// document(HTML) file</pre><pre>&lt;div class=&quot;hello&quot;&gt;Hello!&lt;/div&gt;<br>&lt;div&gt; class-&quot;world&quot;&gt;World!&lt;/div&gt;</pre><p>用 BS4 utilities class 寫需要寫幾行 css 呢？</p><pre>&lt;div class=&quot;m-3 p-4 bg-primary text-white text-center&quot;&gt;<br>  Hello!<br>&lt;/div&gt;<br>&lt;div class=&quot; mt-3 border border-success text-success text-center&quot;&gt;<br>  World!<br>&lt;/div&gt;</pre><p>答案是： 0 行！Σ(*ﾟдﾟﾉ)ﾉ</p><p>當然，這樣一來 class 名稱會變得稍嫌冗長，對於不習慣的人可能需要一些陣痛期去適應，但是對於某些只需要改幾行 margin、padding 的元素來說，這些功能就變得相當實用，對於現代 scope CSS 盛行的框架來說，也不必為了區區一兩個元素的的一兩個 style 微調，就得新增一個 css 檔案，整體而言我認為是一個利大於弊的設計方式。</p><p>BS4 引進的包含 utilities class 的許多新觀念有效的解決了許多開發上會遇到的痛點，今天介紹的只是冰山一角。其實暸解這些設計上的理念之後，也可以自己實作一些專屬於自己專案的 helper class ，應該有效能減少很多重複、冗餘的程式碼，讓程式碼看起來更加清爽~</p><pre>喜歡這篇文章的話歡迎左上角給我股個掌或分享喔~ ヽ(●´∀`●)ﾉ</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=79484fa4c506" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hello world — 在 Yourator 的兩個月零九天與社會新鮮人生活雜談]]></title>
            <link>https://medium.com/@yanglin_68397/hello-world-%E5%9C%A8-yourator-%E7%9A%84%E5%85%A9%E5%80%8B%E6%9C%88%E9%9B%B6%E4%B9%9D%E5%A4%A9%E8%88%87%E7%A4%BE%E6%9C%83%E6%96%B0%E9%AE%AE%E4%BA%BA%E7%94%9F%E6%B4%BB%E9%9B%9C%E8%AB%87-b7c5f2c8e0fa?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/b7c5f2c8e0fa</guid>
            <category><![CDATA[畢業]]></category>
            <category><![CDATA[生活]]></category>
            <category><![CDATA[career-advice]]></category>
            <category><![CDATA[careers]]></category>
            <category><![CDATA[職場心得]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Fri, 19 Apr 2019 18:20:13 GMT</pubDate>
            <atom:updated>2019-04-20T02:26:03.192Z</atom:updated>
            <content:encoded><![CDATA[<h3>在 Yourator 的兩個月零九天與社會新鮮人生活雜談</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/0*aSMEghBZSc7cJTJI" /><figcaption>選一張全公司與呱吉合照而我本人不在裡面的照片當作封面</figcaption></figure><p>為什麼是要選在兩個月零九天發心得文，我也並不是很清楚，不過其實正式上工滿第一個月左右就有在醞釀，覺得第一份工作還是應該記錄一下，才知道自己到底是否有所成長。</p><h3>畢業 X 網頁 X 打工仔</h3><p>讓我們把時間稍微往前拉一些些，拉到 2018 年的九月 — 那時候我還是個死大學生，處於課修的差不多在等畢業的狀態，過著頹廢的生活。後來想想覺得很快就要畢業了，一直這樣下去好像也不是辦法，得準備找個工作做做，就面臨畢業即失業的現實。</p><p>托平常就有在各大 FB 社群打混的福，我原本就知道 Yourator、CakeResume、Meet.jobs 等等的求職平台，所以我就先上 Yourator 搜尋 web 相關的職缺(在資工系打混了三年多沒學到什麼實用的技能，只好跟大家一起當難民)，結果意外發現 Yourator 本身也在 Yourator 上在徵才 — 自己的職缺刊登在自己的平台，可以，這很 meta。</p><p>聊天聊一聊就莫名其妙的收到 offer，屁顛屁顛地就上工了。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/0*6AB6BJfHB1QPF7BK" /><figcaption>面試時就坐在官網的這張圖裡，不是照騙</figcaption></figure><p>所以雖然標題是寫說是兩個月零九天，但是其實這是指擔任正職的時間。事實上我從去年 11 月初左右就開始在 Y 社做打工仔了。</p><p>至於為什麼會在這麼奇怪的時間點畢業 &amp; 上工，是因為我提前畢業了一學期。雖然原本就打算提前畢業開始工作，不過原本的打算只是先找工作等到畢業才上工，結果一發入魂，著實打亂了一點人生規劃。</p><p>關於我提前畢業時遇到的諸多阻礙暫且按下不表，總之 11 月開始就開始快樂打工仔生活 — 並沒有，不要瞎掰：一但準備當個社會人士，各種奇形怪狀的事情就接踵而至，還有當時我手上剛好還有學校的計畫沒處理完，所以那段時間其實頗崩潰，我想所有剛要脫離學校的莘莘學子們可能都要面對這樣的陣痛期吧，很多事都要學著自己處理，也難怪現在有很多人不想或不敢脫離學校舒適圈。</p><h3>學生 ⇒ 社會人士</h3><p>不知道前言會不會太長，總之現在要進入正題了。</p><p>從我打工仔期間，到我在 yourator 正式工作兩個多月加起來約半年左右的時間裡，過得有點過分充實，甚至讓我沒空沈澱下來寫下心得硬是拖了一個多月。作為剛出社會的新鮮人有太多的東西要學習，但我的笨鍵盤寫不出萬分之一二。</p><p>生活方面，第一個感受到的就是台北市區的物價真的可怕，在台北車站附近吃飯平均消費大概是我在交大時的 1.5–2 倍左右，偶而來點休閒娛樂，看個電影、吃個拉麵、喝個飲料，可能一張小朋友就消失了。</p><p>另外就是台北又平又熱又擠，狹小的空間裡，到處都充滿了人，讓人有莫名的焦慮感。這個城市的步調很快，每個人似乎都在追趕著什麼，如果不跟著加快速度可能還會造成別人的阻礙，還可能遭人白眼 — 在各大捷運站的手扶梯可以真切的體驗這種感覺。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*Qk69UrCsIzjfn2cc" /><figcaption>當然偶而還是要吃點好的，人生已經很苦了不能再讓肚皮受罪</figcaption></figure><p>從以上的敘述應該可以感覺到，我個人是相當不習慣那種快速的生活步調和消費水準，所以找房時也是幾乎就直接略過台北市區，直接鎖定在新北地區。當然蘿蔔青菜各有所愛，有人覺得時間寶貴，願意用更多金錢去享受市中心的便利、豐富的娛樂等等，但我覺得最重要的是：要先想好自己要的是什麼。我很慶幸在大四上跟家裡討論過後，有先在校外找房自己住了一個學期，讓我在後來找房時更明確的知道自己想要什麼樣的條件，而這些東西不自己嘗試光靠 google 搜尋或親友探聽其實效果很有限。</p><h3>我所認識的 Yourator</h3><p>第一份全職工作，所以其實也沒有太多東西可以比較，就先來談談我自己在 Yourator 所看到學到印象比較深刻的事情。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/0*rlewldkF70ABxSjx" /><figcaption>章魚燒 &amp; 鬆餅趴踢</figcaption></figure><p>首先：Yourator 真的很小 XD。</p><p>包含我在內有很多人對 Yourator 都有很大的誤解，以為我們是很大的公司，其實敝司最近規模才突破 10 人，雖然還不至於到捉襟見肘的程度，不過很多時候很多事要大家一起分攤才有辦法解決，大家要互相 cover 解決問題。這或許帶來另一個好處是大家的關係比較緊密，我爸媽過年前後常會問我辦公室會不會有部門衝突或是勾心鬥角，但我想想以我們的人數應該是勾不出什麼花樣。</p><p>團隊小的好處是溝通很容易更加緊密，這也是目前我們的 workflow 方針之一：讓溝通更加透明，大家彼此都大概知道別人正在做什麼，也可以集思廣益讓產品的輪廓更加明確。</p><p>另外是對整個求職過程、相關單位的理解。</p><p>由於我們的服務牽涉到就業活動的很多部分，所以對於這個體系和一些淺規則有更多的了解，偶而也會聽到一些有趣的小八卦，但是礙於自主規範我顯然不能在這裡分享，總之知道一些小細節跟背景知識之後會發現整個就業活動中，求職者、人資、企業、用人單位…等等各種不同角色，其實都有一些不容易解決的痛點，這也是我們希望我們的服務能解決的。</p><p>在軟體開發層面，我認為有一些做得很好的地方，像是嚴格的 code review 制度 — 每個人的 code 要有兩人以上 approve 並經由 QA 在 staging 機器上測試過才會 merge，而 code review 也不是瞄一瞄看過而已，而是會互相給予意見和回饋，大家都能在 code review 的過程得到一些啟發。除了各自看別人的 code 以外我們在每週都會排定一段時間用投影機來聽別人逐段解釋各自做了哪些部分，遇到哪些困難、如何解決等等，大家一起成長。</p><p>在 flow 的部分最近在進行 scrum 的導入，雖然之前的開發流程就已經有些敏捷的精神，不過隨著開發團隊人越來越多我們也在做一些適應性的調整，讓設計、開發、QA、BD&amp;行銷的流程更加明確而緊密，得到一個大家都覺得舒適的開發流程。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/357/1*PHDfVDnx3gEVrVglTyatSA.png" /><figcaption>看到自己有對公司對社會有貢獻，總算是有點兒欣慰吧</figcaption></figure><h3>結語</h3><p>大學畢業就工作其實是滿辛苦的，不只是實務層面，還有社會層面的壓力(包含各種人關心為何不讀研究所之類的)，需要保持腦袋清楚，不然很容易會被別人的意見帶著走，而對自己產生懷疑。但我覺得不要太在意別人的想法，了解自己想要什麼、想達成什麼目標，如果想得夠清楚，升學、工作或是創業都不會是什麼壞主意。</p><p>在 Yourator 工作的2+3個月，感覺有逐漸習慣社會人的節奏，也學到不少東西，目前覺得一切還在軌道上，有跟著 Yourator 一起在成長的感覺。</p><p>如果對 <a href="https://yourator.co/">Yourator </a>或是對我個人在做什麼有興趣，也可以在下面留言問我窩</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b7c5f2c8e0fa" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Hooks API ⎯ 不只是 useState 或 useEffect]]></title>
            <link>https://medium.com/@yanglin_68397/react-hooks-api-%E4%B8%8D%E5%8F%AA%E6%98%AF-usestate-%E6%88%96-useeffect-57ebc46b3f61?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/57ebc46b3f61</guid>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[中文]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript-development]]></category>
            <category><![CDATA[react-hook]]></category>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Fri, 22 Feb 2019 04:46:48 GMT</pubDate>
            <atom:updated>2019-06-10T06:48:00.872Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qMdsWYWnaDScPDzm.png" /></figure><pre>TL;DR: 你可能低估了官方 hook API 的功能</pre><p>React 16.8 推出之後，想必大家都很關注這個鎮上新來的酷小孩，但是大部分的教學與範例似乎都圍繞在 <strong>useState</strong> 與 <strong>useEffect</strong> 兩個 hook 之上，然而其實 React 官方提供的 API 還有不少有趣的 hook 可以利用，說不定將官方文件好好的讀過一遍之後，會發現你並不需要引入新的套件，用現有的 hook API 就能解決問題。</p><p>這篇文章主要是要介紹一些比較少被提及，但其實相當好用的官方提供的 Hook API ，以及對比較常用的 <strong>useEffect</strong> hook 的補充。</p><h4>useCallback/useMemo</h4><p>在預設的 <strong>React.Component</strong> 的機制裡，如果 props/state 發生改變即會觸發 重新渲染(re-render) ，而 parent 重新渲染時理所當然的會重新渲染 child components 。</p><p>為了達到優化的效果我們可以透過 <strong>shouldComponentUpdate </strong>這個 lifecycle 方法來選定只有特定的 props 有改變時才更新 component ，或是改使用 <strong>React.PureComponent</strong> ，這樣就能僅在任何 props/state 有改變時才觸發更新。</p><p>更多關於 PureComponent 優化的說明可以參考下面這篇文章：</p><p><a href="https://blog.wuct.me/react-%E5%B7%A2%E7%8B%80-component-%E6%95%88%E8%83%BD%E5%84%AA%E5%8C%96-b01d8a0d3eff">React 巢狀 Component 效能優化</a></p><p>而在 React 16.6 引入的 <strong>React.memo</strong> 讓 function component 也可以獲得 <strong>PureComponent</strong> 的效能補強。</p><p>但是，<strong> shouldComponentUpdate</strong> 比較 props/state 是否相等的基準是使用<strong>shallowEqual </strong>，特性是會以 object 的第一層 key 做 <strong>strict equal (===)</strong>，換言之即使是同樣的值，若 reference 的物件不同就會被視為是不同的物件。</p><p>考慮以下程式碼：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9957f4dbf2d6416708c561e2382ee9f8/href">https://medium.com/media/9957f4dbf2d6416708c561e2382ee9f8/href</a></iframe><p>看似沒有問題， ChildComponent 用 <strong>React.memo</strong> 包起來，在 setState 裡也沒有對 ChildComponent 的 props 做改動，理論上運行這段程式碼時我們會期待看到 <em>clicked!</em> 3 次，再按 ChildComponent 按鈕時應不會觸發第 3 行的 console.log。</p><p>然而實際運行時會發現：當每個 ChildComponent 的按鈕點擊時，仍然會觸發 console.log。原因就在於 ParentComponent 的 <strong>onClick</strong> 在 ParentComponent 自身重新渲染時被重新綁定到一個新的箭頭函數，在 <strong>shallowEqual</strong> 的 strict equal 的情況下會被視為是不同的物件從而造成 memo 失敗。</p><p>在 class component 中，我們可以將這樣作為 props 傳遞下去的 callback 綁定到 class 上變成 member function ，但是 function component 不存在 instance，也就不能將 callback 綁定 ⎯ 這就是 useCallback/useMemo 的使用時機：<strong>在 function component 中產生一個不隨重新渲染而改動(mutate)的 callback。</strong></p><p>我們將上列程式碼做一些小改動：</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0377392a5206bb943f9f1b64a7a8c40a/href">https://medium.com/media/0377392a5206bb943f9f1b64a7a8c40a/href</a></iframe><p>將<strong> onClick </strong>用 <strong>useCallback </strong>包起來，點擊 ChildComponent 的按鈕時就不會觸發 console.log 了！ 💯 💯 💯</p><p>這讓 function component 可以做到一些以往只有 class component 能做到的優化方式，而 useMemo 跟 useCallback 的使用方式類似，可以看看<a href="https://reactjs.org/docs/hooks-reference.html#usecallback">官方文件</a>怎麼說：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/930/1*-GoYvY9P8gQVMBMdWi2F4Q.png" /></figure><blockquote>useCallback(fn, inputs) is equivalent to useMemo(() =&gt; fn, inputs)</blockquote><h4><strong>useLayoutEffect</strong></h4><p>如第一段所說，大部分的教學都著重在 <strong>useEffect</strong> 與 <strong>useState </strong>，然而 <strong>useEffect </strong>其實還有一個好兄弟 <strong>useLayoutEffect </strong>，差別在於 <strong>useEffect 是非同步執行(不阻擋瀏覽器渲染)</strong>，而 <strong>useLayoutEffect 是同步執行(等待瀏覽器渲染完成)。</strong></p><p>簡而言之，<strong>useEffect</strong> 會在瀏覽器完整跑完 <strong>reflow/repaint </strong>流程之後才觸發，適合放不與 DOM 相依、不會阻擋瀏覽器主線程渲染的 effect，如 data fetching、event handler binding 等等。</p><p>但是因為 <strong>useEffect </strong>發生在瀏覽器 <strong>reflow/repaint</strong> 之後，如果某些 effect 是從 DOM 獲得值 (clientHeight、clientWidth) 並對 state 做操作的行為，就可以在改用 <strong>useLayoutEffect</strong> ，在 <strong>reflow/repaint</strong> 之前先做 state 的操作，有機會避免瀏覽器花大量成本重新跑 <strong>reflow/repaint</strong> 的完整循環。</p><p>關於瀏覽器的完整重新渲染流程可以參考<a href="https://www.jianshu.com/p/7fbd239ca0e2">這篇文章</a></p><p>需要注意的是，<strong>useLayoutEffect</strong> 的行為可能甚至跟現有的 componentDidMount/componentDidUpdate 比較接近，比起 <strong>useEffect</strong>。</p><p><a href="https://scrimba.com/p/pwQZ6tV/c68wGu2">這個連結</a>是一個解釋的很好的範例。</p><h4>useRef</h4><p>以往 ref 只被用來當作儲存 DOM 節點的變數，在 React Hooks API 裏拓展了 ref 的用法與定義，現在<strong> ref 可以用來儲存任何會變動(mutable)的值，角色變得跟 class component 的 member variable 很像</strong>，解決了 function component 沒有 instance 不能儲存變數的問題。</p><p>這讓 ref 變得更加彈性，事實上<a href="https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state">官方文件</a>就推薦<strong>使用 ref 來紀錄 prevProps/prevState</strong>，即可實作類似 class component 的其他 lifecycle 功能。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/941/1*0oZ7zDvKbjpwapxDHpnhZA.png" /><figcaption>官方文件的解決方法</figcaption></figure><h3>總結</h3><p>Hooks 解決了長久以來 function component 比起 class component 缺的一些拼圖，包含優化手段、彈性、lifecycle 等等，也順帶解決了以往兩大 pattern (render props &amp; HOC) 的一些缺點，並不是只是讓 function component可以用 state 和 componentDidUpdate 這麼簡單(當然這也是非常重要的特色)。</p><p>雖然 Hooks API 還在很早期階段，可能近未來還有許多 breaking change ，或許現在還不是最佳時機將這些 API 採用到專案中，但是我們可以從這些概念上學習到很多東西，看的見 React 官方展現的企圖心，非常值得期待。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=57ebc46b3f61" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用 pixi.js 開發 2D 小遊戲 (三) — DisplayObject]]></title>
            <link>https://medium.com/@yanglin_68397/%E4%BD%BF%E7%94%A8-pixi-js-%E9%96%8B%E7%99%BC-2d-%E5%B0%8F%E9%81%8A%E6%88%B2-%E4%B8%89-displayobject-4b885d06dae2?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/4b885d06dae2</guid>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Tue, 07 Aug 2018 05:33:08 GMT</pubDate>
            <atom:updated>2018-08-07T06:32:44.880Z</atom:updated>
            <content:encoded><![CDATA[<p>趁有空多寫點 lol</p><p>上一篇講到 PIXI.Container 構成 pixi application 的資料與渲染架構，那什麼東西可以放進 Container 裡呢？</p><p>基本上任何繼承自 <a href="http://pixijs.download/dev/docs/PIXI.DisplayObject.html">PIXI.DisplayObject </a>這個抽象介面的物件都可以被放進 Container 裡，包含：</p><ul><li>Container</li><li>Text</li><li>Graphics</li><li>Sprite</li><li>extras.AnimatedSprite</li></ul><p>等等。</p><p>上一篇有稍微講到 Text 如何使用，基本上就是使用建構子產生一個物件之後丟到 Container 就好了，API 相當簡單：</p><pre>text = new PIXI.Text(&#39;foo&#39;)<br>container.addChild(text)</pre><p>而 PIXI.Text 的建構子也可以提供類似 CSS 的 style 來改變樣貌，這部分沒有什麼需要特別注意的地方，可以直接參考官網的<a href="https://pixijs.io/examples/#/basics/text.js">範例</a>。</p><p>Graphics 則像是比較低階的 primitive 的集合，包含畫點、線、面等等，或是畫一些三角形、多邊形、圓形的 API 。</p><pre>let graphics = new PIXI.Graphics()</pre><pre>// 調整線條的跟填充的顏色<br>graphics.beginFill(0xFF3300)<br>graphics.lineStyle(4, 0xffd900, 1)</pre><pre>// 畫多邊形<br>graphics.moveTo(50,50)<br>graphics.lineTo(250, 50)<br>graphics.lineTo(100, 100)<br>graphics.lineTo(50, 50)<br>graphics.endFill()</pre><pre>// 畫一個四邊形<br>graphics.lineStyle(2, 0x0000FF, 1)<br>graphics.beginFill(0xFF700B, 1)<br>graphics.drawRect(50, 250, 120, 120)</pre><p>如果有學過一些電腦圖學或是操作過原生 canvas/webGL，就能發現這個 Graphics API 相當原始，沒經過什麼特別包裝，操作上挺直覺的。</p><p>需要特別注意的是若是<strong>要更新 Graphics 的內容，一定要先呼叫 .clear() 方法清除之前定義的 primitive</strong> 。在遊戲的開發中常常會有需要對某些 Graphics 進行重繪(ex: hp條的更新、粒子顏色改變)，在每個 tick 中重繪時如果沒有清除之前的資料在畫面上很難是看出來的(因為重繪過後的畫面通常會蓋過先前的內容)，但是 primitive stream 內容仍然會被上傳到 GPU ，因此會造成畫面看起來沒什麼東西但是 GPU/CPU loading 直線上升的狀況，算是筆者當初太年輕而犯下的錯誤之一。</p><p>Sprite 跟 AnimatedSprite 則是稍微比較複雜的元件，因為他們牽涉到外部的資源，因此這裡也會引進 PIXI.loader 的概念。</p><p>Sprite 在祖國的翻譯叫做雪碧圖，印象中我最早看到這個單字是小學在玩 RPG Maker 的時候，然而我到現在仍然不明白為什麼這個東西叫做雪碧(Sprite)，可能洋人的玩法比較特別吧。</p><p>sprite 通常會合併成一張 sprite sheet，常用應用是把人物/NPC 或是物品的不同面向合併成同一張圖，這很有可能跟早期傳輸/硬體限制有關，因為我不是遊戲設計系所以也不是很清楚呢。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/384/0*DqEW5b-pY5qRX_4w.png" /><figcaption>8bit 風格的 sprite sheet</figcaption></figure><p>在 pixi 中載入雪碧圖有兩種方式，一種是透過 PIXI.Sprite.fromImage 方法直接從圖片載入，一種是使用 PIXI.loader 預載入之後從 texture cache 裡拉出來初始化。</p><pre>// 法1: 直接載入<br>const sprite = new PIXI.Sprite.fromImage(&#39;assets/image.png&#39;)</pre><pre>// 法2:<br>// 在某個地方從 asset 預載入 image 到 memory 並給予 key &#39;foo&#39;<br>PIXI.loader.add(&#39;foo&#39;,  &#39;assets/image.png&#39;)<br>...<br>// 要使用時從 texture cache 取出<br>const sprite = new PIXI.Sprite(PIXI.loader.resources[&#39;foo&#39;].texture)</pre><p>兩種方法的好處與壞處應該也相當明顯：直接載入簡單直白，但是可能無法重複使用 cache ，加上必須當場載入，如果 asset 量大可能就會造成明顯的延遲。 preload 寫法比較囉唆，但好處是可以在 application 一開始就載入完畢，之後都直接從 cache 找即可，所以對於遊戲來說通常需要先定義好一個 init 函式來 preload asset 。</p><p>PIXI.loader 是 PIXI.loaders.Loader 的預先定義好的一個實例，可以直接拿來使用，當然也可以自己實體化 PIXI.loaders.Loader，如果有這個必要的話。add 這個操作可以串連，因此可以寫成如下的形式：</p><pre>PIXI.loader<br>  .add(&#39;bunny&#39;, &#39;data/bunny.png&#39;)<br>  .add(&#39;spaceship&#39;, &#39;assets/spritesheet.json&#39;)<br>  .add(&#39;scoreFont&#39;, &#39;assets/score.fnt&#39;)</pre><p>或者也可以直接寫成一個 config json file ，如果 asset 數量真的很多的話。</p><p>PIXI.loader 也支援如 progress, complete, load, error 的 event ，可以監聽載入的狀況並呼叫自定義的 handler。</p><p>AnimatedSprite，顧名思義是會動的 Sprite ，建構子吃的參數是一個 array of texture(或稱作 frame) ，呼叫 .play() 方法會使其在 parent update 的時候會根據其內部的 animateSpeed 參數調整速度遍歷 frames 渲染。</p><p>常見的應用場景是同一個 object 可能需要在不同狀態套用不同的 texture ，例如遊戲角色面向不同方向的時候使用不同段的 sprite sheet ，然而重新建構一個 AnmatedSprite 需要的成本是比較高的，所以並不建議直接這樣操作。<strong>若新的狀態的動畫的 frame 數量跟舊狀態動畫的 frame 一樣多的話，可以直接抽換 AnimatedSprite 的 texture</strong> ，就可以避免重新建構物件的額外成本，如下：</p><pre>// 實體化物件<br>let character = PIXI.AnimatedSprite(frames)<br>...<br>// 僅改變 textures 的 binding，避免重新建構物件<br>character.textures = another_frames</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*zcPKSVjlD7Ebg0cB" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4b885d06dae2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用 pixi.js 開發 2D 小遊戲 (二) — Container]]></title>
            <link>https://medium.com/@yanglin_68397/%E4%BD%BF%E7%94%A8-pixi-js-%E9%96%8B%E7%99%BC-2d-%E5%B0%8F%E9%81%8A%E6%88%B2-%E4%BA%8C-8e3e0fa915fe?source=rss-9d1ba7125c47------2</link>
            <guid isPermaLink="false">https://medium.com/p/8e3e0fa915fe</guid>
            <dc:creator><![CDATA[Yang Lin]]></dc:creator>
            <pubDate>Mon, 06 Aug 2018 17:42:19 GMT</pubDate>
            <atom:updated>2018-08-07T03:48:42.692Z</atom:updated>
            <content:encoded><![CDATA[<p>不知不覺過了兩週多，再不寫可能就沒有惹。</p><p>上次稍微介紹了一點點 pixi.js 的特色，這次會稍微涵蓋到一些 pixi.js 的架構如何設計，以及 api 如何操作的部分。當然要學一個語言/框架/工具，看官方文件通常是最準的，這部分 pixi.js 做的還不錯，在<a href="http://www.pixijs.com/">官網</a>上就有許多包含原始碼的 demo ，也有 gallery 介紹一些做得不錯的作品，但是 <a href="http://pixijs.download/dev/docs/index.html">API 文件</a> … 就有一點差強人意了，查詢的功能做的沒那麼好，並且只有按照字典序排列的部分，參考上比較辛苦一些，而且有些東西還是翻了 <a href="http://www.html5gamedevs.com/">html5gamedevs</a> 的文章之後，才知道這支 API 實際的功用，我個人給 pixi.js 文件的評分是 7.5/10 ，想要做一些簡單的東西還滿好查的，但是一些細部的調校與進階的 API 資源不太容易找到。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IBGVnJT8KI1nxBepQYM-Tg.png" /><figcaption>pixi.js 官網的 example</figcaption></figure><p>其他資源的部分，我一開始是看 <a href="https://github.com/kittykatattack/learningPixi">learningPixi</a> 這個 repo ，因為他有中文翻譯的版本，不過中文翻譯的進度比較落後。另外這篇 <a href="https://ithelp.ithome.com.tw/articles/10190574">IT鐵人賽</a> 也很有參考價值，裡面講的比較多是如何將 pixi 應用在網頁前端上，跟遊戲的邏輯稍有不同不過也是很珍貴的中文資源。</p><p>推薦先把這一篇大致看一遍再來看這系列的文章，裡面提到的 Container, Loader, Ticker 等等，都是 pixi application 重要的部分。</p><p><a href="https://ithelp.ithome.com.tw/articles/10190574">[PixiJS - Day-01] 為何選擇 PixiJS - iT 邦幫忙::一起幫忙解決難題，拯救 IT 人的一天</a></p><p>那麼直接進入(業配)主題，這次的文章主要介紹如何安裝 pixi 的環境，以及 pixi 渲染架構的特性。</p><p>首先安裝環境的部分： pixi 只要引入 CDN 就能使用，安裝成功的話當打開該網頁時會自動在 console 跳出一小段資訊，因此很容易知道是否安裝成功</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/656/1*z14Pn56VAA73S4wXbKA4VQ.png" /><figcaption>如果你沒看到這個，你可能有哪裡做錯了;)</figcaption></figure><p>而 pixi v4 有提供 PIXI.Application 物件，將整個 pixi app 會用到的 renderer、ticker、 event manager 等等工具包裝在此物件中，只要實體化此物件並將 renderer mount 到 html body 裡，就建構出一個簡單的 pixi app 了。</p><pre>const app = new PIXI.Application()<br>document.body.appendChild(app.view)</pre><p>在 pixi 的架構之中，將常用到的可渲染的東西包裝成物件，像是 PIXI.Text、PIXI.Sprite、PIXI.Graphics … 等等，這些 renderable 的物件需要一個舞台 才能展示，在 pixi 中將這類舞台稱作 Container ，只要把物件使用 addChild 方法放到 Container 上，該物件就會被渲染在該 Container 上對應的座標(原點是(0, 0))。</p><p>而只要賦值給 renderableObject.position 物件或是透過 renderableObject.position.set(x, y) 這個 function，就可以修改物件在 container 中的相對位置。</p><pre>const app = new PIXI.Application({ backgroundColor: 0xFFFFFF })<br>const helloWorld = new PIXI.Text(&quot;Hello world&quot;)<br>helloWorld.position = { x: 50, y: 30 }<br>app.stage.addChild(helloWorld)</pre><pre>document.body.appendChild(app.view)</pre><p>上列的輸出大致長得像下圖(加上 border 以分辨 app 邊界)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/479/1*_VDDcD_K4MYEA8ke4DcDxA.png" /></figure><p>一個 pixi app 就是一個樹狀的結構，由一個 root container (app.stage)包含所有 renderable 物件，而 Container 當然也可以包含其他 Container ，所以整個 app 的資料架構相當簡單就是一顆巨大的樹。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/821/1*lRD0t-HUuVuNr76gqps23g.png" /><figcaption>簡單的 pixi application 架構示意圖</figcaption></figure><p>而由於在 PIXI 中 render Container 的成本相當小，又 renderable 物件的位置是相對於其 Parent Container ，所以 Container 有時候也被當作是物件群組的概念：將屬於同一個物件的不同部位放在同一個 Container 裡，只要移動 Container 就可以移動全部的子元素。</p><p>Container 本身也算是一種 renderable 物件，但是他不具備 width 和 height，因此修改其 width/height 並沒有意義，而一般 renderable 物件都可以改變其位置(position)、大小(width/height)、伸縮(scale)、原點(transform-origin)等等屬性。</p><p>需要特別注意的是， <strong>pixi 沒有原生方法可以改變渲染順序，物件的 zIndex 直接決定於被加進 Container 中的順序。</strong>唯一可以(間接)改變渲染順序的方法是 addChildAt ，可以決定插入 container 渲染佇列的 index，然而仍然不能直接改變元素的 zIndex。</p><p>幸運的是，<a href="https://github.com/pixijs/pixi-display">pixi-display</a> 這個插件提供了 pixi 跨 container 共享元素，且能自定義 zIndex 與 zOrder 的功能 — pixi-display 中的 Layer 可以說是 改良版的 container ，支援在 update 的時候自定義 callback 來改變渲染佇列中的元素的 zIndex/zOrder，因此解決了許多在 2D 遊戲中，需要依據螢幕深度改變渲染順序的需求。在 pixi v5 proposal 已有人提議把 Layer 的功能直接加進原生 pixi 中，來源在<a href="https://github.com/pixijs/pixi.js/wiki/v5-Proposal,-Layers">這裏</a>。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/486/0*zcPKSVjlD7Ebg0cB" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8e3e0fa915fe" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>