Skip to content

zh

在技術角色中的有效領導力

作為一名軟件工程師,你可能最終會提升到領導職位。然而,你很快就會發現,僅憑技術專業知識並不足以在科技行業取得成功。您還必須每天管理各種問題和危機。壞消息是,你最初可能並不具備有效領導團隊所需的管理質素。好消息是,擁有開放的思維和持續學習,你可以隨著時間的推移發展這些技能。

首先,你需要理解基本的領導原則。作為一名初級成員,你的重點主要是完成分配的任務。隨著你在職位中的提升,你需要承擔更大的責任,參與跨功能團隊活動,接手項目管理職責,並考慮公司的整體策略。"主管"這個頭銜是什麼意思?這意味著提供方向,知道您的目的地,並引導他人前往。因此,我的建議是保持好奇心。嘗試理解您公司的決策過程,並始終對學習和提問保持開放的態度。

成為一名領導者並不一定意味著要強勢或極度外向。研究顯示,有六種不同的領導風格,每種風格適合不同的情況。這些包括:

  1. 強制型領導 - 在危機中有效。
  2. 權威型領導 - 通過願景激勵他人。
  3. 附屬型領導 - 著重團隊團結。
  4. 民主型領導 - 建立共識。
  5. 教練型領導 - 致力於個人成長。
  6. 節奏型領導 - 設定績效標準。

理解你的領導風格可以幫助你適應各種場景。沒有一種通用的解決方案;您需要根據團隊在不同階段的需求調整您的風格。

要成為一個有效的領導者,你必須了解自己和你的團隊成員。每個成員都有他們自己的優點和弱點,你的角色是指導團隊實現其目標。這涉及到設定目標,建立一個團結的團隊,清晰地溝通,並與利益相關者協作。在解決內部衝突時,公正至關重要。認可和獎勵積極的貢獻,同時解決任何對團隊產生負面影響的問題。首先,通過身教來領導。你的行動比你的話語更響亮,使你成為他人的榜樣。

管理一個團隊需要能力和情商。您需要理解每個成員的獨特需要並處理團隊內各種工作風格、關係和衝突。你的溝通應該是正式和尊重的,樹立起互相尊重和合作的環境。

要成為科技行業的領導者,您不僅需要技術技能,還需要有看到未來的能力,展現決心,展示誠信和承諾,散發自信,並能有效地溝通。除此之外,您應該展現創造力,激勵您的團隊,促進合作,並保持真實。

我希望您會發現本文對於發展成為一個有效領導者所需的自我覺察能力有所幫助。在某些時候,你需要挺身而出,特別是當緊急問題出現時。你不必等待上級的許可,他們可能並不最適合處理這種情況。主動尋求你需要的資源。記住,人們常常過於聚焦於他們自己的責任而忽視了你的需求。鑑於全球領導力的短缺,我鼓勵你主動出擊,應對我們所有人所面對的迫切挑戰。

作為軟體開發人員的溝通重要性

讓我解釋為什麼軟體開發人員需要有良好的溝通能力。盡管這似乎是不言而喻的,但這個技能對你的職業生涯影響極大。作為一名團隊領導,你的溝通技巧在工作面試、進度評估和評價中都非常重要。你絕對不希望自己在競爭中處於劣勢。有許多情況下,良好的溝通技巧至關重要,包括:

如何進行良好的示範:在設計和構建一個產品時,你必須定期向你的團隊和主要的利害關係人展示已完成的工作。在敏捷軟體開發中,每個迭代都是不可或缺的。無論你正在構建什麼產品——無論是一個應用程序、一個網站,還是一個實物——精心執行的演示會改善跨團隊的協作,建立與持份者的信任,提高團隊士氣,並允許團隊根據反饋和變化進行調整。即使對於像API和後端服務這樣更具挑戰性的主題,這一點也是如此。

在跨功能團隊中工作:我們幫助組織建立產品和服務,以滿足他們所處行業的快速變化需求。我們的跨功能團隊、客戶產品擁有者、工程師和設計師需要定期進行產品演示,以有效地溝通、慶祝進步,並快速提供價值。

在這一篇文章中,我收集了為什麼演示重要以及如何進行出色演示的見解和技巧。

演示幫助我們建造更好的產品:定期的演示為團隊提供了一個短期的反饋迴圈,讓團隊能夠快速調整並確保他們正在建造正確的產品。他們也提前將重複的努力或依賴關係表面化,突出了廣泛項目中跨區域合作的機會。

提高團隊士氣:我們在當前的項目中每兩週進行一次團隊演示。這些會議通常會引導出跨團隊對以前未考慮過的問題的討論,從而在問題成為障礙之前快速解決。

反饋至關重要:不要猶豫根據反饋來調整你的演示格式,確保你的團隊和利害關係人都能受益。

強化與持份者的關係:演示有助於吸引持份者參與開發過程,從而建立信任並展示有價值的軟體逐步交付。

團隊發展:演示讓團隊成員有機會提升演示技巧並與利害關係人更密切互動。它們提供了一個千載難逢的機會讓開發者,特別是那些處於職業生涯初期的人,來磨練他們的演示技巧。

一些進行出色產品演示的技巧:

  • 放大視野:總是提供上下文。確保設置場景並專注於用戶利益。
  • 講一個故事:通過分享你已經克服的挑戰和你所學到的東西來吸引觀眾。
  • 慢下來,保持簡單:以觀眾能跟上的速度演示,並避免行話。
  • 準備得足是關鍵:要始終排練並預先準備好你的演示,以保持與觀眾的互動。

總的來說,良好的溝通至關重要。進行有意義的對話,分享有價值的觀點。保持積極的態度來建立自信,特別是如果你是內向的。

至於公開演講,想像你正在跟朋友聊天。要真誠,聆聽你的觀眾。記住,你怎麼說一些事情通常比你說什麼更具有紀念性。尤其是如果英語不是你的母語,說話要慢。這些技巧對我有用,我希望對你也有用。下次,帶著目的說話、放慢速度、並深呼吸。讓我知道你的想法,或許現在你理解溝通的重要性,我們可以合作。

在Visual Studio Code中設定Python的自動格式化

我正在寫Python代碼,並遇到了格式化問題。這些格式問題可能會使代碼審查變得複雜,並對使用自動工具來檢測這些問題產生影響。幸運的是,當你將格式化工具集成到您的代碼編輯器中以在保存時自動修復這些問題時,生活會變得容易許多。這就是如何做的:

  1. 首先,安裝Google的yapf格式化工具:
pip install yapf
  1. 接著,打開你的Visual Studio Code編輯器。如果你使用的是Mac,按“Command + Shift + P”,如果你在Linux上,按“Ctrl + Shift + P”。在搜索欄中輸入"Open settings (JSON)"並添加以下行:
"python.formatting.provider": "yapf"
  1. 如果你希望你的代碼在保存時自動格式化,而不僅僅是在編輯器內部接收提示,也可以添加這個設置:
"editor.formatOnSave": true
  1. 如果你希望使用你的項目的.style.yapf而不是全局樣式,則添加以下行:
"python.formatting.yapfArgs": ["--style", ".style.yapf"]

現在你可以測試自動格式化功能。例如,如果你的Python文件末尾沒有新行,然後你保存它,格式化工具將自動為你修正這個問題。

如何使用Chrome遠程桌面在AWS實例上安裝Ubuntu桌面

在如今以雲端為中心的世界中,許多資源已被移至雲端,例如相片、檔案和伺服器等。那麼為何不將您的桌面環境也移到雲端呢?想像一下,不再需要帶著一台重型筆記本。您可以從任何薄型客戶端(例如帶有鍵盤的平板)在任何地方訪問您的計算能力。透過AWS實例,結合Ubuntu桌面和Chrome遠程桌面就可以實現這一點。雖然還有其他解決方法,如AWS工作區或VNC連接,但Chrome遠程桌面提供的延遲最低且性能最接近原生桌面。以下是如何設置的方法:

  1. 登錄AWS控制台,並使用Ubuntu Server AMI啟動一個實例。

  1. 實例啟動後,SSH登錄到您的Ubuntu服務器。更新包管理器並安裝wget:
sudo apt update
sudo apt-get install --assume-yes wget
  1. 下載Chrome遠程桌面套裝軟體並安裝它:
wget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb
sudo dpkg --install chrome-remote-desktop_current_amd64.deb
sudo apt install --assume-yes --fix-broken
  1. 安裝桌面GUI環境。

在測試了各種不同的發行版本後,我發現Xfce在網路較慢的情況下表現最佳:

sudo DEBIAN_FRONTEND=noninteractive apt install --assume-yes xfce4 desktop-base
  1. 配置Chrome遠程桌面預設使用Xfce:
sudo bash -c 'echo "exec /etc/X11/Xsession /usr/bin/xfce4-session" > /etc/chrome-remote-desktop-session'
  1. 安裝xscreensaver作為預設的Xfce鎖屏程序的替代品,因為它不與遠程桌面兼容:
sudo apt install --assume-yes xscreensaver
  1. 禁用顯示管理器,因為沒有連接的顯示器:
sudo systemctl disable lightdm.service
  1. 將您的用戶賬戶添加到Linux群組,然後註銷:
sudo usermod -a -G chrome-remote-desktop $USER
logout
  1. 在您的本地筆記本瀏覽器上,打開Chrome遠程桌面的無頭模式。按照步驟設置另一部電腦。您可能會在您的AWS實例中複製此類命令:
DISPLAY= /opt/google/chrome-remote-desktop/start-host
--code="4/xxxxxxxxxxxxxxxxxxxxxxxx"
--redirect-url="https://remotedesktop.google.com/_/oauthredirect"
--name=
  1. 最後,您可以遠程連接到您的Ubuntu桌面了。

    額外的提示:您可以顯示屏幕保護程序,儘管這並不必要。

您現在可以使用任何設備,從任何地方訪問您的桌面環境。這種設置對於隨時需要訪問完整開發工具集的軟體工程師特別有用。

如何使用macOS在外部驅動器上安裝Ubuntu

如果你在使用Mac硬體,但也想要運行Ubuntu,你可以在外部硬碟上安裝Ubuntu,而不會冒著刪除你的macOS安裝的風險。下面是如何在不搞砸你的引導裝載器的情況下進行操作:

  1. 將你的外部SSD/HDD插入。打開磁碟工具並將其格式化為MS-DOS(FAT)

  2. 打開終端窗口並運行: diskutil list

這將幫助你找到你的外部硬碟的標識符,例如,在這個示例中是disk2。

  1. 下載並安裝VirtualBox: VirtualBox網站

  2. 運行以下兩條命令並以管理員權限啟動VirtualBox:

sudo VBoxManage internalcommands createrawvmdk -filename bootcamp.vmdk -rawdisk /dev/disk2
sudo /Applications/VirtualBox.app/Contents/MacOS/VirtualBox
  1. 選擇“新建”然後點擊“專家模式”。選擇“使用現有的虛擬硬碟文件。”

  1. 在“系統”標籤中,勾選“啟用EFI(僅限特殊OS)”。

  2. 在“儲存”標籤中,將Ubuntu ISO文件掛載到虛擬機。 你可以從這裡下載Ubuntu ISO文件。

  3. 啟動虛擬機並進行Ubuntu安裝。

  4. 一旦安裝完成,你就可以從驅動器啟動了。 對於Mac,你也需要降低安全級別並允許從外部媒體啟動。要做到這一點,在你看到蘋果標誌後立即按住Command-R以啟動macOS恢復。

  5. 重新啟動你的Mac並按住選項鍵。你現在可以選擇你的驅動器擁有EFI標籤。

享受在Apple硬體上使用Ubuntu!請注意,你可能需要解決一些驅動問題,但希望這個指南能讓你的過程更容易。

如何修復 AWS Amplify Angular App 中的“拒絕存取”錯誤

當您在 AWS Amplify 上部署您的 Angular 應用程式時,第一個登陸頁面可以正常載入。然而,如果您在您的路由器中定義了一條路徑並嘗試存取它,您可能會遇到一個“拒絕存取”的錯誤:

要解決這個問題,首先導航至 AWS 控制台,然後選擇“重寫和重定向”。接著,加入一條新的重寫和重定向規則。點擊“開啟文字編輯器”並插入以下的規則:

[
  {
    "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>",
    "target": "/index.html",
    "status": "200",
    "condition": null
  }
]

添加這條規則後,嘗試再次存取您的 URL。現在應該可以按預期工作了。

如何將您的Android應用程式寫入後台執行模式作為服務

在某些情況下,您可能會遇到一個問題,那就是當用戶將應用程式置於背景模式或鎖定屏幕後幾分鐘,您的應用程式的功能就會消失。這可能導致用戶體驗變差,例如藍牙設備從您的應用程式中斷開,或者數據同步到服務器中斷。用戶可能會抱怨您的應用程式的連接性和穩定性。

首先,為了解決這個問題,您需要了解Android應用程式活動生命周期。當用戶切換到另一個應用程式,例如Facebook,而不是使用您的,您的應用程式活動將被終止,並觸發 onDestroy() 方法。然而,這種行為對於Android系統是有利的,因為它可以幫助釋放未使用的記憶體和管理電池壽命,但對於您的應用程式來說,可能會有問題,因為其狀態和功能可能會丟失。

下一步是重構您的應用程式,將如藍牙連接等背景功能分離為服務。服務是一種應用程式組件,能夠在後台執行持久運作,獨立於使用者介面。下面是一個服務的代碼範例:

import android.app.Service

class MyService : Service() {

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
      // 在此擺放你的服務邏輯
    }

    override fun onDestroy() {
      // 在此清理你的服務邏輯
    }

}

要使用此服務,您還需要在您的 AndroidManifest.xml 中定義它。這是一個例子(將名稱替換為您的服務的套件名稱):

<application>
    ...
    <service android:enabled="true" android:name="com.victorleungtw.myapp.services.MyService"></service>
</application>

此外,要在您的活動中啟動此服務(例如在 Activity.onCreate() 中),請添加以下行:

startService(Intent(this, MyService::class.java))

並在您希望停止服務的地方,包括此行:

stopService(Intent(this, MyService::class.java))

實施這些更改後,您的應用程式將有更好的結構,但還不能在背景中無限期運行。為了實現這一點,您還需要在您的服務中添加兩個方法:

class MyService : Service() {
    // ... 現有的代碼

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val channelId =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    createNotificationChannel("my_service", "My Background Service")
                } else {
                    // 如果是較早的版本,則不使用頻道ID
                    ""
                }

        val notification: Notification = Notification.Builder(this, channelId)
                .setContentTitle("Title")
                .setContentText("Text")
                .build()
        startForeground(2001, notification)

        return START_STICKY
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(channelId: String, channelName: String): String {
        val channel = NotificationChannel(channelId,
                channelName, NotificationManager.IMPORTANCE_NONE)
        channel.lightColor = Color.BLUE
        channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        service.createNotificationChannel(channel)
        return channelId
    }
}

在這裡,創建了一個通知,通知用戶該應用程式繼續在背景中運行。它可能看起來像這樣:

就是這樣。現在您的用戶可以進行多任務操作,例如瀏覽Facebook,同時您的應用程式繼續在後台運行,保持藍牙連接,同步用戶數據,播放音樂或執行其他取決於您的應用程式功能的任務。

Android應用內瀏覽器的注意事項

當您正在開發一個網頁應用時,您需要考慮到瀏覽器的兼容性問題。我在開發過程中並未對Android應用內瀏覽器進行測試,但在正式上線以後出現了問題,導致數千次的交易失敗。我並不能從日誌中清楚地找出問題的根源,因此我花了一些時間來解決。我在這裡記錄下了這個問題,希望可以節省您未來的除錯時間。

當您的終端用戶透過第三方的Android應用內瀏覽器來訪問您的網頁應用時,您無法控制這個webView,因為它是由第三方提供的。如果setJavaScriptEnabled方法設置為false,那麼您就陷入了絕境。如果你有幸使前端代碼依舊能加載,請注意setDomStorageEnabled的設置預設為false。如果您參考官方文檔:

Android WebSettings setDomStorageEnabled Method

這個布爾標誌設定DOM存儲API是否啟用。預設值為false,表示WebView將停用DOM存儲API。當它嘗試訪問瀏覽器中的localStorage對象時,此設定可能會阻止您的代碼執行。

MDN Web Docs on localStorage

解決方案很簡單:在執行代碼之前,添加一個條件來檢查localStorage是否可用。這個問題不會產生有意義的錯誤消息,使得除錯變得特別困難,尤其是當您需要在Android應用內瀏覽器中模擬問題時。

複製此問題的一個技巧是下載以下工具:

Android WebView Test App on Google Play

此應用程式非常實用,因為它可以讓您在Android應用內瀏覽器中查看控制台日誌。

另一個通過服務器日誌進行故障排除的技巧是檢查請求頭部的User-Agent Strings。您可以通過檢查下面的範例頭部中的wv字段來識別WebView的請求:

Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.65 Mobile Safari/537.36

我希望這篇文章能對您有所幫助,並節省您處理這一特殊注意事項所需的時間。

解釋 Angular 錯誤:'Expression Changed After It Has Been Checked'

我的一位同事在開發 Angular 前端應用程序時遇到了一個錯誤訊息,錯誤訊息為:

ExpressionChangedAfterItHasBeenCheckedError:Expression在檢查之後已更改。先前的值:'null',當前的值:'true'。

這個錯誤發生在他開發一個從第二頁導航回第一頁的後退按鈕功能時。第一頁已經渲染過一次,並需要以不同的初始值重新渲染。

這個錯誤的根本原因在於Angular的變更檢測機制。每次操作後,Angular都會將用於該操作的值存儲在組件視圖的 oldValues 屬性中。一旦所有組件都已經檢查過,Angular就會啟動下一個摘要週期。但是,它不進行操作,而是將當前值與上一個週期存儲的值進行比較。

值得注意的是,這種額外的檢查只在開發模式中發生。Angular從組件樹的頂部到底部強制執行單向數據流。一旦父組件的變更已經被處理,就不允許任何子組件更新父組件的屬性。

要解決上述問題,可能的解決方案包括使用異步更新,如 setTimeout,或者在 ngAfterViewInit() 的生命週期鉤子中手動觸發變更檢測,利用 _changeDetectorRef.detectChanges()ChangeDetectorRef 類提供以下五種方法:

抽象類 ChangeDetectorRef {
 抽象 markForCheck(): void;
 抽象 detach(): void;
 抽象 detectChanges(): void;
 抽象 checkNoChanges(): void;
 抽象 reattach(): void;
}

通過利用這些方法,您可以手動運行變更檢測並更新子視圖。我的同事很高興發現錯誤在這種解釋之後得到了解決。

使用Karma為Angular組件撰寫單元測試案例

我想為你的Angular網頁應用程序編寫單元測試。加速生產時間並不能成為積累技術債的合理理由。以下是一些開始的有力理由:

  1. 單元測試幫助盡可能早地識別問題,尤其是當多個團隊在同一個代碼庫上工作,不經意地引入了錯誤。避免在深夜接到生產支持的電話是一個值得追求的目標。

  2. 測試使您能夠自信地重構代碼,確保您的應用程序繼續按預期運行。您可以將您的代碼分割為可管理的,可測試的單元,而不是處理一個龐大的系統。

  3. 您公司的政策可能要求某種程度的代碼覆蓋率,通常為80%或更高。

如果你是新手,你可能不知道如何開始,或者為什麼這個重要。幸運的是,Angular讓它變得很容易。開始,只需在您的項目目錄中運行以下命令:

npm run test

這將在本地主機的9876端口打開一個Chrome瀏覽器窗口。

Image 1

點擊"Debug"按鈕以啟動測試。

Image 2

此時,由於我們還沒有寫任何測試,所以不會有任何測試運行。但是,您可以開始撰寫測試用例以覆蓋特定的,獨立的代碼片段。例如,讓我們考慮一個login.component.ts檔案,其中包含一個login()方法,該方法將一個布爾標誌從假轉為真:

export class LoginComponent {
  isLogon = false

  login() {
    this.isLogon = true
  }
}

接下來,創建一個名為login.component.spec.ts的檔案以撰寫您的測試用例。如下所示撰寫您的第一個測試用例:

import { async, ComponentFixture, TestBed } from "@angular/core/testing"
import { LoginComponent } from "./login.component"

describe("LoginComponent", () => {
  let component: LoginComponent
  let fixture: ComponentFixture<LoginComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LoginComponent],
    }).compileComponents()
  }))

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
  })

  it("should be able to log on", () => {
    component.login()
    expect(component.isLogon).toBeTruthy()
  })
})

在您的describe()函式中,您將找到測試用例。每個案例都在其自己的it()函式中。這裡的目標是測試isLogon標誌在觸發login()方法後是否變為真。

Image 3

您的第一個測試用例應該通過!如果另一個開發者修改了您的代碼,您的測試將捕獲它:

Image 4

在現實世界的情境中,您可能會向服務器發送API呼叫。但是,在您的測試期間重要的是不要真的撥打API。您應該用stub數據模擬您的API呼叫。

例如,讓我們加強我們的LoginComponent以進行服務呼叫:

import { AuthenticationService } from "../../services/authentication.service"

export class LoginComponent {
  constructor(private authenticationService: AuthenticationService) {}

  isLogon = false

  login() {
    this.authenticationService.login().subscribe(
      data => {
        this.isLogon = true
      },
      error => {
        this.isLogon = false
      }
    )
  }
}

現在,您的測試將會失敗,因為AuthenticationService尚未注入我們的測試環境。我們可以如下所示修復這個問題:

import { async, ComponentFixture, TestBed } from "@angular/core/testing"
import { LoginComponent } from "./login.component"
import { AuthenticationService } from "../../services/authentication.service"
import { of } from "rxjs"

const stubData = {
  username: "testing",
}

class FakeAuthenticationService {
  login() {
    return of(stubData)
  }
}

describe("LoginComponent", () => {
  let component: LoginComponent
  let fixture: ComponentFixture<LoginComponent>
  const newFakeAuthenticationService = new FakeAuthenticationService()

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LoginComponent],
      providers: [
        {
          provide: AuthenticationService,
          useValue: newFakeAuthenticationService,
        },
      ],
    }).compileComponents()
  }))

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
  })

  it("should be able to log on", () => {
    component.login()
    expect(component.isLogon).toBeTruthy()
  })
})

您的測試用例現在應該通過!

Image 5

這個例子為了演示的目的而簡化,但是重要的要取的是,你不應該避免撰寫單元測試。