[生活筆記] 2023 的回顧與展望

引言

2023 年過去了, 作個回顧

工作相關

2023 年對我來說是個不穩定的一年,甚至考慮出國去唸語言學校,但最終留在了台灣。
T 社的本來想說點什麼,一年內提筆多次想想就又算了。
一年都過了還是作個簡單記錄。

T 社事件

本來想加入一個前輩 S 作為主管的團隊,
與這位前輩其實沒那麼多接觸,但知道技術實力不差,本來也是 N 社早期的創業員工之一。
預計是希望能近距離合作並學習,並以創業心態開發一款國際產品。
實際上加入 T 社後,S 桑進公司的次數屈指可數,
產品的發展也與預期不符,市場已有大量類似的競品,老闆吹的天花亂墜,但只是一個點餐系統
T 社本身到母公司 W 集團,完全缺乏軟體專案的管理經驗,隨便而缺乏專業開發團隊,
而缺乏軟體工程的管理專業,使得他們無法有效追蹤進度

需求與溝通

後續的結果是開發團隊與 W 集團互信不足,演員底的老闆,只能帶著兒子、特助或是咖啡甜點來信心喊話,
團隊內的產品部門變成了對講機與美工,唯一的功能就是轉達集團的需求與繪製 Figma。
整個產品團隊無法回答開發團隊的疑問,反而不斷的抱怨集團、特助或老闆,
整個溝通變得無效且變形

開發

反過來是招募時,餅畫得太大,導致 RD 明顯過度設計,
比如說,RD 跑了一個沒有 Domain Expert 的 DDD,
在沒有上線、沒有賺錢沒有用戶的情況下,用自已的腦補進行了領域的分工,
不到10人的團隊切分了 10 幾個微服務,並且濫用了 GraphQL。
這樣又帶來後續的問題,
第一、語言不一致,一開始的想法是讓各個開發者有開發的自主,但問題變成無法互相支援,各自畫地為王
第二、開發風格不一致,即使是使用相同的語言,使用的套件與寫作風格也未統一,所以要支援也有難度
第三、開發準備作業多,很多需求經討論後都需要新建成服務,RD 需要從建立 Repo,
到自行建置 GCP 相關服務(網路、資料庫、CI/CD 等),
第三、串接複雜,API 重重呼叫,為了要追蹤錯誤,需要延申很多額外的設計,
一個簡單的 CRUD,需要兩個 GraphQL 如果有要異動到呼叫的 API,更新一個 API 就要動到三個專案
第四,但是因為團隊缺乏領導者(S 桑)的情況下,開發者沒有有效的權責分工,GCP 的權限被一些早期入職的員工掌握,而需要等待。
第五,無溝通與不透明,晨會就形同虛設,整個團隊每個人變成一個一個穀倉

缺乏用戶

整個產品核心的兩個功能(點餐與收費)在兩個系統上,一個外部公司開發的軟體,一個在老舊的 POS。
而我們開發的系統比較像是一個單純的 App 加周邊整合。
這麼簡單的東西,卻用了一個複雜的架構,導致修改速度緩慢,遲遲無法上線,面對需求調整時也沒有彈性。
更進一步加深集團與開發團隊的不信任。

團隊狀況

  • 資料與雲端權限在一個菜鳥身上,不論有意無意,權限與知識不願意共享,除非有人踩到雷
  • 前端上班睡覺,開發品質低下的 React(完全沒有模組化的思維,不如用原生三本柱開發還比較快)
  • 產品設計的後台實務上沒有人會使用,主要還是在母公司的 ERP E
  • APP 組用了 Flutter 思維確停留在 IOS/Android/Web 的分工,到後來兩人也無法互相支援
  • 想學 C# 的 RD 整天吹噓 N 社的失敗專案(XmiERP),而代碼品質可讀、可測試性極差,讓我理解 Php 工程師的下限
  • 想學 Golang 的 RD 應該是整體過度設計的原兇,第一時間離職了。
  • 領頭 S 桑遲遲未進入團隊後,
  • 來了一個之前也在 N 社待過”幾天”的 R 主管
    • 缺乏開發能力(至少在這樣的穀倉下)
    • 也缺乏軟體開發管理的素養
    • 甚至連基本守法都作不到

  

勉強要說會作簡報,但是產品設計不合理,比如說,他花了 3 個月作簡報搞了一個動態標籤點餐,
然後跟廠商要了一個動態標籤機,丟在那裡再放3個月,然後拒絕承認有過這件事ಠ_ಠa,是在哈囉。
然後面試找來自已的樁腳。
整個公司與團隊缺乏互信

我的努力

試著找 S 桑與團隊開了一場大會,總算把 APP 推上架。
上架唯一可以收費的功能由我開發部署到實體店面驗收,並給了團隊與主管中實的逆耳忠言。
儘可能的 Change Your Company。
只可惜爛泥扶不上牆,石瓦塗黃泥也不成金。

以上是 T 社的故事概述,至於關於 R 與 W 集團的非法行為就另一個故事了(🍵

顧問

年初有找到很多的機會,例如在 C 社擔任顧問職,
或是接案,也算是個不錯的經驗,主要的發現如下。

  • 沒有識別專業能力的能力→如何確定軟體開發的產品如期如質?
  • 沒有正確分工的能力→大環境太偏向技能分工(ex:前後端、SRE、DBA etc…, 我認為應該更偏向需求端與實作端)
  • 沒有建立與管理流程的能力,版控流程、權限控管、需求流程

這剛好是我擅長且有經驗的,
資深的開發者的問題在停止學習,執著於自已的開發習慣,
資淺的開發太想炫技,而過度設計,兩者都需要透過管理手段去調控。

A 社相關

目前的事就先不多說,至少我開發的東西已經幫公司賺到 3000 萬以上,
遺憾的事是,幾個下屬想拉拉不起來,只好協議讓他離開,一切流程也合法合情,  
這也是我說的,有資金的人不見得有識別專業的能力,千里馬常有伯樂不常有。
其他一些甘苦還在進行式,至少比 T 社好多了,就不多談。

  • 主管技能學習中…
  • GCP 技術大躍進
  • ISO 認証學習中
  • Azure 技術學習中

生活

  • 潛水終於考到 AWO,下次想換個潛點了  
  • 跳舞方面
    • 跟知名的老師跳了一首,2023 足夠了
    • 上了幾個國際老師的課,不過還是沒有感到進步
      • Jo
      • Meti & Andante
      • Bianca and Nils (沒上課但是有跟 Bianca 跳到舞)
      • Lisa & Fabien
      • Dasha & Roman (有跟 Dasha 跳到舞)
      • Melanie & Jeremy
      • Chloe & Rico
      • Moondewti
      • Laura & Youngbo
    • 在誠品表演、嚐試一些空中動作 
    • 喜歡的樂手
      • Charlie Christian
      • YOASOBI
    • 喜歡的漫畫
      • 莽送的莉芙蓮
      • Völundio(休刊中)

     

  • 換了護照準備出國但是還不知道要去哪裡?
    • 打算再帶媽媽出國一次
    • 也想去倫敦看阿森納比賽
    • 也想再參加國外的 workshop
    • 不想變成只會希望而不行動的麵包師傅

展望

投資

Q1 總資產有望達到一個重大里程碑。下一個目標是持股資產達這個里程碑

英文

制定計劃中

工作

仍是目標全遠端/斜槓或接案

社交

毫無頭序,也應該制定計劃嗎???

健康

踢球?健身?跳舞

(fin)

[生活筆記] 修正 A 校的題目缺陷

導言

在 A 校擔任雲端助教一陣子,主要有幾個原因,
我也是資策會出身,所以我對轉職的學生可以感同身受,
我在教學的過程中,自已也會成長,很多時候可以學習到新知也得到成就感,
最後就是可以獲得額外的收入。

問題發現

這次是一個我有興趣的題目,簡單說 A 社利用 Replit 網站提供作業,
由學生進行撰寫,很聰明的整合方式,而且幾乎零成本。
而且我覺得最棒的是,他可以寫測試腳本,透過測試腳本,就可以驗收大部份的作業,加速批改的時間。

但是,這次同學的作業在執行時期,發生了異常掉入了一個無限廻圈的狀態
問題不難,是一個邊際值的問題。 應該可以加上測試保護,這是我的第一個直覺。
我去檢查了 A 校提供的標準答案,不出意外的也有相同的問題。

另外一個問題是,寫邊際值的測試案例不是基本的嗎?
查看了測試案例,竟然還真的沒有寫

問題排查

我選擇下載了 Replit 到地端開發,
在開始前先簡單描述題目,在一個限範圍內進行猜數字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const answer = Math.floor(Math.random() * 100) + 1
// start coding

let min = 1
let max = 100
let guess = Math.floor(Math.random() * 100) + 1
let count = 1

function getResult() {
while ( ) {
if ( ) {

} else if ( ) {

}
guess = Math.floor((max + min) / 2)
count ++
}
console.log( )
}

// 以下為測試檔,請勿更動
getResult()

module.exports = {
guess,
answer,
count,
getResult
}

這是很好的題目,可以同時使用到迴圈與判斷,也可以接觸 Math 模組。
我們來看一下測試案例,在 Replit 右下角的 Unit Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
test("", async function() {
const spy = jest.spyOn(console, 'log')
const {
guess,
answer,
count,
getResult
} = index;

getResult()
if (guess === answer) {
expect(count).toBeLessThanOrEqual(10)
}
});

測試很單純,當答案在 1~100 之間時,執行迴圈的次數不應該超過 10 次(其實 7 次內應該都猜得出來)
我們應該加上一些邊際測試。
例如 1 與 100 的案例,

1
2
3
4
5
6
7
8
9
10
11
12
13
it("Answer_is_1", async function() {
const spy = jest.spyOn(console, 'log');
const originalMathRandom = Math.random;
Math.random = jest.fn()
.mockImplementationOnce(() => 0.001)
.mockImplementation(() => originalMathRandom());
//console.log('now random is', Math.random());
const index = require('./index');
index.getResult();

// Clean up
spy.mockRestore();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
it("Answer_is_100", async function() {
const spy = jest.spyOn(console, 'log');
const originalMathRandom = Math.random;
Math.random = jest.fn()
.mockImplementationOnce(() => 0.999)
.mockImplementation(() => originalMathRandom());
//console.log('now random is', Math.random());
const index = require('./index');
index.getResult();

// Clean up
spy.mockRestore();
});

這裡注意到的是我們 mock 了Math.random,因為這才會影響我們的答案。

問題後的問題

當我們在測試案例為 100 時,會限入無窮迴圈,而 JavaScript 單緒的特性將無法離開這個測試,
雖然也不會報錯…但是測試將永遠跑不完。
這驅使我再加上一個測試案例,當執行次數超過 10 次時拋出例外。
而學生使用的範本,我希望儘可能不去修改它,
這裡要對 jest 與 javascript 要有足夠的理解才可以寫的好,
所幸在這個時代,有 AI 與 google 的加持下,很快就解決了。

最後的測試程式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
describe('Guessing Game', () => {
let originalMathRandom;
let spy;

beforeEach(() => {
// Save the original functions
originalMathRandom = Math.random;
spy = jest.spyOn(console, 'log').mockImplementation(() => {});
});

afterEach(() => {
// Restore the original functions
Math.random = originalMathRandom;
spy.mockRestore();
jest.resetModules()
});

it("Answer_is_1", async function() {
Math.random = jest.fn().mockReturnValue(0.001);
const index = require('./index');
index.getResult();
expect(index.answer).toBe(1);
});

it("Answer_is_100", async function() {
Math.random = jest.fn().mockReturnValue(0.999);
const index = require('./index');
index.getResult();
expect(index.answer).toBe(100);
});

it('guess under 10 times', () => {
Math.random = jest.fn().mockReturnValue(0.5);
const index = require('./index');
for(let i=0; i<9; i++) {
index.getResult();
}
expect(() => index.getResult()).not.toThrow();
});

it('should throw error if count is more than 10', () => {
const originalMathFloor = Math.floor;
Math.floor = jest.spyOn(global.Math, 'floor')
.mockImplementationOnce(() => Math.floor(Math.random() * 100) + 1)
.mockImplementationOnce(() => 1000);
const index = require('./index');
expect(() => index.getResult()).toThrow('超過10次了,請重新開始');

});


// Add more tests as needed for the getResult function
});

給學生的出題程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const answer = Math.floor(Math.random() * 100) + 1;

// start coding

let min = 1;
let max = 100;
let guess = Math.floor(Math.random() * 100) + 1;
let count = 1;

function getResult() {
console.log(`Guess number is ${guess}`);
while ( ) {
if ( ) {

} else if () {

}

count++;
if (count > 10) {
throw new Error('超過10次了,請重新開始');
}
}
console.log(`第${count}回合,您猜${guess},猜對了`);
}

// 以下為測試檔,請勿更動
module.exports = {
guess,
answer,
count,
getResult,
};

解答範本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const answer = Math.floor(Math.random() * 100) + 1;

// start coding

let min = 1;
let max = 100;
let guess = Math.floor(Math.random() * 100) + 1;
let count = 1;

function getResult() {
console.log(`Guess number is ${guess}`);
while (guess !== answer) {
if (answer < guess) {
max = guess; //猜太大取代最大值
console.log(`第${count}回合,您猜${guess},太大了,請猜介於${min}~${max}之間的數字`);
} else if (answer > guess) {
min = guess; //猜太小取代最小值
console.log(`第${count}回合,您猜${guess},太小了,請猜介於${min}~${max}之間的數字`);
}
guess = (max === min + 1) ? max : Math.floor((max + min) / 2);

count++;
if (count > 10) {
throw new Error('超過10次了,請重新開始');
}
}
console.log(`第${count}回合,您猜${guess},猜對了`);
}

// 以下為測試檔,請勿更動
module.exports = {
guess,
answer,
count,
getResult,
};

小結

整個課程的調整與測試改寫,大概花了我 4~12 小時處理。
在改制後,互動環節變少了,計時制改為定時制的給薪,也讓無法花太多的時間幫學生排查問題。
這題目我有興趣就順手解決了。
可惜的是,我拿不到任何費用。

也再一次印証 AI 的強大,未來的人材需要有更高的整合能力,
寫測試寫程式,讀技術文章賺取資訊落的錢應該會越來越難賺。
但是能高度整合的人應該會更為搶手。

(fin)

[實作筆記] GCP Armor 設定

前情提要

在加入負載平衡(load balancer)後,我們發現防火牆的某些規則失效了,
尤其是那些僅允許公司內網存取站台的規則。
這是相當重要的規則,因為我們的部分開發資訊與半成品儲存在這些機器上。

之所以建立了負載平衡(load balancer),有兩個原因
首先,我需要作後端 API 的版本切換,而因為使用的程式語言不同並部署在不同主機,
而 load balancer 透過路由規則將流量導向不同的機器群的機制非常適合。
第二,我們的正式環境一直有 load balancer,而測試環境沒有,趁這個機會將沙盒/測試環境的配置調整成一致。

問題

本來有設定某些防火牆的規則,在掛載 load balancer 後就失效了。
原因是規則會識別流量的 IP,而掛載後,所有的流量對於機器來說,所有流量都來自 load balancer 的 IP 了。
這樣的規則形同虛設,這個時候 Google Armor 就是一個不錯的替代方案

Google Armor Tips

設定上十分簡單,在 Cloud Armor 頁面上選擇 policies,
我的情況是在建立 load balancer 後,就已經自動建立,
所以就直接修改。

參考規則如下

Action Type IP Addresses/Ranges Priority
Allow IP addresses/ranges 5*.1**.***.205/32 999
10.140.0.0/20
Deny IP addresses/ranges 0.0.0.0/0 1,000
(block all)

一個是對指定來源 IP 與內網允許流量進來,一個是拒絕所有流量,這裡的設定與防火牆蠻像的。
接下來是目標的部份,要設定你的機器群,設定好套用,大約 10 分鐘內就會生效(實測不到3分鐘就生效了)

小結

Google Armor的主要優勢之一是其簡單易用的設定。
在Cloud Armor頁面上,我們可以輕鬆地設定我們的安全策略,包括允許特定IP範圍的流量進入,同時拒絕不受歡迎的流量。
這些設定反映在我們的參考規則中,確保了對特定IP和內部網路的控制,同時阻止不受歡迎的流量。

特別是對於我們使用負載平衡器進行後端API版本切換和環境配置調整的需求,Google Armor提供了一個理想的解決方案。
其能夠在不同機器群之間巧妙地分發流量,確保我們的應用程式在不同版本之間平穩運作,同時維持良好的安全性。

這樣的調整不僅解決了我們遇到的具體問題,也提升了整體系統的安全性和可靠性。

(fin)

[實作筆記] Hexo 7 升級的錯誤處理心得

前情提要

最近在對Hexo進行升級至7.0版本的過程中,遇到了一些錯誤與問題。
這篇部落格將記錄下這次升級的過程中所遇到的問題以及解決方法,希望對有需要的讀者有所幫助。

錯誤記錄

Hexo Action 錯誤

升級後,遇到了Hexo Action報錯的問題,錯誤訊息如下:

1
2
3
4
5
6
node:internal/modules/cjs/loader:1051
throw err;
^

Error: Cannot find module 'hexo-util/lib/spawn'
Require stack:

解決方式是查找相應的模組,更新配置文件,在本案中,hexo-util/lib/spawn 路徑不存在,應該改為 hexo-util/dist/spawn。

地端執行 Hexo d 時 Permission Denied

在地端執行Hexo d時,遇到了權限問題,無法提交到GitHub的問題。
暫時解決方式是將repository的協議由ssh改為https,暫時繞過了問題。

1
2
3
4
deploy:
type: git
repository: https://github.com/marsen/marsen.github.io.git
branch: master

後來因 https 需要提供帳號密碼,而這些資訊不適合簽入版本控制,故改回了 ssh,
為了解決相應的 SSH 連線問題,需配置 SSH 連線 .ssh/config
參考:

1
2
3
4
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa

YouTube Tag 無法處理

升級至Hexo 7.0後,發現內建的YouTube標籤無法使用,原因是Hexo 7.0中刪除了這些內建的標籤。
解決方式是引入安裝 hexo-tag-embed package。

Hexo 部署錯誤快取

在部署過程中,遇到了Hexo的快取問題,導致地端和CI都出現異常。
解決方式是清除 Hexo 的快取 hexo clean,完整 SOP 如下:

1
2
3
4
sudo rm -rf .deploy_git
hexo clean
hexo g
hexo d

使用 Docker 偵錯

Hexo Action本身是以容器去運行的,可以在本地端執行測試,不需推版
使用 Docker 進行 Hexo Action 時,進行偵錯的方法:

建置與執行

1
2
docker build -t hexo-action .
docker run -d hexo-action

觀察 logs 與 files 去偵錯,Docker Desktop 是很好的工具。

小結

這次Hexo 7.0的升級過程中,遇到了不少問題,但通過查找相應的解決方案,一一解決了這些問題。
在升級過程中,需要留意Hexo的官方文檔以及相關插件的更新,以確保能夠順利完成升級。

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - 錯誤處理

前情提要

在持續整合/持續交付 (CI/CD) 的過程中,我們常常會遇到一個問題:
當發生錯誤時,系統並不總是會拋出 exit 1 的錯誤碼。
這種情況下,即使發生錯誤,CI/CD 仍然會繼續執行,這可能導致部署了錯誤的版本上線,增加系統的不穩定性。

解決方法

為了解決這個問題,我們可以採取一些措施,確保在發生錯誤時 CI/CD 立即停止,並拋出 exit 1 錯誤碼。

1. 記錄錯誤信息到 output.log

首先,我們可以將所有的執行日誌輸出到一個文件,例如 output.log。這樣一來,
不管是哪個階段出現了問題,我們都能夠查閱這個文件,以便更好地理解錯誤的發生原因。

1
2
3
Copy code
# 在腳本中添加以下命令,將所有輸出寫入 output.log 文件
./your_script.sh > output.log 2>&1

2. 使用 grep 檢查錯誤

其次,我們可以使用 grep 命令來檢查 output.log 文件,查找關鍵字或錯誤模式。
如果發現了任何錯誤,我們可以採取相應的措施。

1
2
3
4
5
6
Copy code
# 使用 grep 查找關鍵字,並在發現錯誤時執行相應的操作
if grep -q "error" output.log; then
echo "Error found in output.log"
exit 1
fi

3. 發現錯誤時丟出 exit 1

最後,在檢查完錯誤後,如果發現了問題,我們應該明確地拋出 exit 1,這會通知 CI/CD 停止進一步的運行,
確保不會將有問題的版本部署上線。

1
2
3
4
5
6
Copy code
# 在發現錯誤時,明確地拋出 exit 1
if [ $? -ne 0 ]; then
echo "Error occurred. Exiting with code 1."
exit 1
fi

透過這些步驟,我們可以更好地管理 CI/CD 中的錯誤,確保系統的穩定性和可靠性。
同時,我們能夠更快速地響應和解決問題,減少部署錯誤版本的風險。

1
2
3
4
5
6
7
8
9
10
11
12
generate-qa:
stage: generate-qa
script:
- npm install
- npm run generate:qa | tee output.log # 可能出錯的命令,將輸出寫到文件
- grep -q "Error.*\[500\]" output.log && echo -e "\e[31m生成異常! Prerendering 發生 500 Error\e[0m" && exit 1
- echo "generated successfully"
artifacts:
paths:
- ./.output/public
rules:
- if: '$CI_COMMIT_BRANCH == "qa"'

小結

這些方法不僅有助於提高系統的穩定性和可靠性,還能夠加速問題的識別和解決過程,減少了部署錯誤版本的風險。
透過這些實踐,我們可以更加信心滿滿地運用 Gitlab CI/CD 與 GCP,確保順暢的開發和部署流程。

參考

(fin)

[工作筆記] 退出 Azure DevOps 的組織

前情提要

Azure DevOps 是一個由微軟開發的服務,提供開發團隊協作和快速交付軟體的解決方案。
它包含了版控、工作追蹤、持續整合/持續部署 (CI/CD) 等功能。
其中,我將重點使用其 Board 功能來進行工作項目的管理和追蹤。
然而,有一天我發現自己被不知名的人邀請進了一個 Azure DevOps 的 Organizations,
所以我開始尋找如何自行退出的方法。

解法

首先進入 dev.azure.com,點擊 user setting icon (這在畫面的右上角,是一個人的右下角有齒輪的圖案)。
點擊 Profile 進到以下頁面,可以看到提示如下:

1
2
You are currently subscribed to other communication regarding Visual Studio and/or Visual Studio Subscriptions.   
Please visit the complete Azure DevOps Profile Page to change those settings.

點擊連結到 Azure DevOps Profile Page

這裡就可以看到你的 Organization 並選擇離開

誤區

my account 也有 Organization 但是不可以隨意離開。
簡單來說,在微軟的 my account 中,Organizations 代表的是你所屬於的 Azure Active Directory (Azure AD) 組織。
這些組織可能是你的工作場所、學校或其他團體,他們使用 Azure AD 來管理員工或成員的身份和訪問權限。
這裡的組織並不等同於 Azure DevOps 中的 Organizations,並且不能隨意離開。

參考

(fin)

[踩雷筆記] 解決 GitHub 帳戶在 VS Code 中的管理問題

前情提要

當我使用 VS Code 時,我需要同時存取多個 GitHub 帳戶,
自已的 Github - 主要存取 VS Code 一些地端的設定值
公司的 Github - 有免費的 Copilot 這很好用。
兩個都我需要,我要作出大人的選擇。

實務上的困境

我可以同時登入兩組帳戶,但是無法達到我要的需求

登入兩組帳戶的方法

  1. 確保安裝了 Github Copilot 與 Github Pull Request and Issues 套件
  2. 如果有其它 Github 帳號已經在登入狀態的,都先登出,並重啟 VS Code
  3. 準備好兩個瀏覽器,分別登入公司與自已的 Github Account
  4. 點擊在左下的頭像 Icon (沒有頭像 Icon 的話在左側欄任一處點右鍵,將帳戶打勾)
  5. 選擇”使用 Github 登入,以使用 Github Copilot”
  6. 選擇登入公司帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟
  7. 回到 VS Code,重複第 4 步
  8. 選擇”使用 Github 登入,以使用 Github 提取要求和問題”
  9. 選擇登入自已帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟

如果你的預設瀏覽器是登入公司 Github 的帳號,就複製網址,貼到登入自已的 Github 帳號瀏覽器,反之亦然。
但是這個作法,實際上沒有什麼幫助,備份與同步設定與 Copilot 會共用同一組帳號
我並不需要 Github Pull Request and Issues 相關功能。

手動組態同步

早期 VSCode 有人寫了組態同步的擴充套件,但是目前內建在 VSCode 內部後不再維護了。
但是我需要的就是自已長期以來的使用的設定,所以可以先登入自已的帳號。
再登出後,登入公司帳號。缺點是需要手動處理。

安裝第二個 VSCode

這個方法也有很多不同的實作方式。
簡單說一個官方直接支援的方式。 VS Code Insider
這算是一個搶先試用版的 VSCode,也有其對應的風險。
但是你就可以在系統上安裝兩個 VSCode,並登入不同的帳戶。

花錢為自已的帳戶買 Copilot

這或許才是最大人的解法。
我們要的是”同步組態設定”與”Copilot”使用權。
根帳號本身其實沒有什麼關係。
資本主義大好,但就失去了一些童趣了。

參考

-https://tutorials.tinkink.net/zh-hant/vscode/copilot-usage-and-shortcut.html
-https://code.visualstudio.com/docs/?dv=osx&build=insiders

(fin)

[工作筆記] 問題,不重要不緊急,就永遠不作了嗎?

問題

最近我在公司引導大家一些敏捷方法的實作,
在這過程中討論了 PBI 排序的原則,價值和風險。
那麼問題來了,這樣有一些事情很小,但價值也不高,又沒有什麼風險,那不就永遠作不到了嗎??

回答的心路歷程

這是一個很好的提問,我反思一下常見的四象限模型,即「重要緊急矩陣」中,
我可以把重要對應到價值,緊急對應到風險,然後 A、B、C、D 四象限,
我們知道要先作 A、B 這樣我們 C、D 的事永遠都不作了嗎 ?

我分享一個故事如下:

有一位教授,他拿著大石頭、小石子、沙子和一個玻璃罐,
先放入大石頭,問學生滿了沒? 再來是小石子,再問學生滿了沒?
最後再倒入沙子,問學生滿了沒? 結果還是沒滿,還可以再放入水

你學到了什麼?
—常見的說法是要先處理重要的事情,順序很關鍵。

我們可以有一些反思,首先當然是重要的事先作(大石頭先放),
再來,你總是還有辦法找到一些空隙。
—時間就像乳溝一樣擠一擠就有了。

這是我當時的回答,
—如果你能守住重要的事,剩下的小事,你是有辦法找到空隙塞進去的。

回答後的反思

我要怎麼知道可不可以塞進去??
這就是透明度的重要性,在 Scrum 或看板方法都有提出。
而我們可以在 Scrum 的每日例會使用看板方法(現行主流的作法),
加上每次迭代所行成的 TimeBox,正好可以對應這個故事中玻璃罐。
有趣的是,我沒想過如果玻璃罐不是透明的話,教授的問題還有意義嗎 ?
正是透過每日例會與看板方法,讓我們可以透明的掌握進度(瓶子剩多少空間/你剩多少時間),
所以你可以判斷是不是可以再塞下石頭或沙、水。

TimeBox

它是一種任務和時間管理的方法,將任務分成小塊,每塊都有一個簡短而固定的時間,以確保高優先級的任務能按時完成。

看板方法

它包括將工作可視化、限制同時進行的工作(WIP)、管理流程、明確陳述流程政策、實施回饋循環以及以協作方式改善。
這些原則和工具都教導我們要優先處理最重要的事情,這是成功的關鍵。

看板方法我還會聯想到限制理論(Toc),但就不過度展開了。

(fin)

[生活筆記] 潛水日誌

20230916

一潛(導潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 14:08 |潛水時間:41 |出水時間: 14:49
能見度: 10m |平均水深: 4.8m |最大深度: 10.5m |水溫: 26.4
起始壓力: 200 |結束壓力: 70 |SCR: 3.17 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

時隔半年再次下水
第一潜稍嫌緊張
首次體驗美灩山
無浪無流,嘗試三角、四角導潜
浮力控制不當,未注意深度
未能找到原位

二潛(放呆)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 16:11 |潛水時間: 57 |出水時間: 17:08
能見度:8m |平均水深:5.1m |最大深度:11.5m |水溫: 26.8
起始壓力:200 |結束壓力:100 |SCR: 1.75 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

第二潛是與小夥伴伴潛屬於放呆行程,比較沒有那麼緊張,
算是複習了一下背滾式與跨步式入水,
不過小夥伴的問題有點多,一個是有人被海膽刺到膝蓋,
另兩個小夥伴二級頭跟 BCD 卡住而不自覺,直到教練去救援,
回程有看到黑色相間類似蛇的生物

三潛(導潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 17:30 |潛水時間:38 |出水時間: 18:08
能見度: 5m |平均水深: 7.1m |最大深度:11.8m |水溫: 26.5
起始壓力:200 |結束壓力:100 |SCR: 2.63 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

這次練習導潛主要是跟著教練,並繪製海圖,
方向感本來就不好的我,加上水深這個緯度,
其實是個蠻大挑戰,我只知道大概的路徑是一個狹長的 U Turn,
試著認地形,入水後右側是壁,左側是斜坡,前進20米左右會出現沙地,
這裡教練會稍作轉向,然後出現一個更深的地方,大約有到 11 米
之後我就有些迷航了,可能是在附近作了一個四角或三角的繞圈
海圖繪製比例失恆,所幸未來還有好幾次的潛水機會

四潛 (夜潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 19:03 |潛水時間: 53 |出水時間: 19:56
能見度: 12m |平均水深: 5m |最大深度: 11.9m |水溫: 26.3
起始壓力:200 |結束壓力:50 |SCR: 2.83 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

最擔心的夜潛反而是最美的一潛,作好安全工作後再下水其實不會有什麼心理壓力,
除了教練外還有一個陪潛的前輩,看到很多生物但是叫不出名字,
過程中有點小意外,前輩以伏地魔之姿突然從下方出現,害我撞向礁石同時被海膽刺了,
所幸以前有被刺過的經驗,知道不會有生命危險,所以我沒有驚慌,但上岸後手上還是多了 4 個黑點,

20230917

一潛(高氧)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 9:51 |潛水時間:35 |出水時間: 10:26
能見度: 10m |平均水深:16.2m |最大深度:25.5 |水溫: 25.6
起始壓力:200 |結束壓力:100 |SCR: 2.85 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

突破個人最深的記錄,沒有什麼感覺,下水點的魚群很多,
但深一點的地方就沒有魚了,看到很多三點蟹的空殼,
聽說是漁船上拋下來的,另外撿了一些垃圾

二潛(高氧)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 11:07 |潛水時間: 45 |出水時間: 11:52
能見度: 10m |平均水深: 11.8 |最大深度: 25.8 |水溫: 25.7
起始壓力: 200 |結束壓力: 100 |SCR: 2.22 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

再次突破個人最深的記錄到 25.8,浮力的控制還是很差,到深處會揚沙,
突中遇到一團揚沙大隊,簡直是我,
回程時有看到小丑魚

三潛(放呆)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 14:47 |潛水時間: 37 |出水時間: 15:24
能見度: 8m |平均水深: 5.1 |最大深度: 8.6 |水溫: 26.1
起始壓力: 200 |結束壓力: 100 |SCR: 2.70 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

看小夥伴考試,感覺大家很慌張,不過也都通過了,沒有到 11 米處的沙地
覺得有遇到流,但是教練是很清鬆就踢過去了,有種提早回程的感覺

四潛 (夜潛)

1
2
3
4
5
地區: 東北角美灩山
入水時間: 18:54 |潛水時間: 51 |出水時間: 19:45
能見度: 12m |平均水深: 5.1 |最大深度: 11.2 |水溫: 25.9
起始壓力: 200 |結束壓力: 100 |SCR: 1.96 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

看到最多生物的一次,饅頭海星、海蛞蝓跟他的卵、海鰻、河豚、龍蝦
獅子魚、還有鼻子長長的不知什麼魚、黑的紅的、睡覺的、龍蝦等…
微型生物也很多,但是我看不太到,要很靠近峭壁,所以中心浮力控制要很重要。

20230918

一潛(打浮力帶)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 09:04 |潛水時間: 53 |出水時間: 09:57
能見度: 8m |平均水深: 6.3 |最大深度: 8.4 |水溫: 25.2
起始壓力: 200 |結束壓力: 50 |SCR: 3.65 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

第一次打差點拉不住,後面就好多了,
不過看了紀錄,發現深度起伏很大,
中心浮力沒有控制好,應該至少有打了10次以上

二潛(打浮力帶)

1
2
3
4
5
地區: 東北角龍洞四號
入水時間: 10:18 |潛水時間: 40 |出水時間: 10:58
能見度: 8m |平均水深: 6.4 |最大深度: 12.2 |水溫: 24.9
起始壓力: 200 |結束壓力: 50 |SCR: 3.75 Bar/min
天氣: 晴 |浪況: 無浪 |目的: 訓練 |方式: 岸潛

覺得很難控制趴姿,看了錄影,其實還不差,就是一直會停腳,
中心浮力控制不好外,還有旋轉的問題,所以一直忍不住踢腳,
不僅耗氣,看起來也很好笑,打氣只要二級頭向上就好,不用按壓

(fin)

[工作筆記] 採蘋果

前情提要

公司有三台 Macbook pro 2017 年款,普遍都有電池的問題,
為此研究了一下在台灣舊機換新機的策略。

折抵

選擇好你的新機,在「加入購物袋」前,找到「加入換購方案」,依指示輸入郵遞區號、選擇製造商 Apple 後
輸入序號後選擇相關的硬體設備。
就會出現一個換購的金額,再繼續完成你的購物袋即可。

企業商店

企業採購的話可以有累積的金額優惠,如果滿足到累積的金額(一年內 5000 美金),就可以以優惠的方式來做訂購,
需要打電話(見文末參考),使用統編建立企業商店。
其它方式與折抵一樣。
訂單成立後可以刷卡或是匯款,刷卡可以立即看到訂單進度,
而匯款後需要再打電話(0800-020-021)確定訂單進度。

折抵的部份會再出貨後 14 天來回收舊機器,應該有足夠的時間轉移資料。

參考

(fin)

Please enable JavaScript to view the LikeCoin. :P