The Issue About Using MPChangeRepeatModeCommand

Apple’s MediaPlayer framework has two APIs in iOS 10 to let you control your player’s repeat mode (to repeat a song, or a list, and so on) and shuffle mode (sequential or shuffle play) with CarPlay. They are MPChangeRepeatModeCommand and MPChangeShuffleModeCommand.

We tried to integrate these two APIs into our product, KKBOX’s audio app on iOS, but then we removed them, since they are conflicting with some popular in-car system.

Continue reading

Posted in Code, iOS | Tagged , | Leave a comment

使用 Slather 產生 iOS/Mac 專案的單元測試覆蓋率報告

在 Xcode 6 以及之前的版本中,如果你使用蘋果內建在 Xcode 當中的 OCUnit/XCUnit 等測試框架撰寫單元測試的話,Xcode 會在測試的過程中產生 gcc 格式的覆蓋率(coverage)報告,叫做 gcda (意思是 gcov data file)檔案;如果我們想將產生測試覆蓋率的流程整合到 Jenkins 等持續整合系統中,我們可以用 gonvr 等工具,將測試報告轉換成 XML 或 HTML 格式,這將我們就可以在系統中,看到每個 build 的覆蓋圖表,以及覆蓋率變化的趨勢。

但是在 Xcode 7 之後,蘋果將 gcc 的工具換成 llvm 的工具,這種幾年前的方案便變得不敷使用。在 Xcode 7 中,雖然我們可以指定要求產生 gcc 格式的覆蓋率檔案,似乎可以與我們過去的工作流程相容,但是產生出來的結果非常不準確;而蘋果的立場大概是,反正 Xcode Server 可以正確顯示覆蓋率報告,如果你用的不是 Xcoder Server,他們就不管了。而現在要將 Xcode 7 中 llvm 工具產生出來的報告,轉換成 XML/HTML 等格式,我們大概會選擇 Slather

Slather 是一套用 Ruby 開發的 command line 工具,是 llvm-cov 工具的前端,我們可以使用 gem install slather 指令安裝。

Continue reading

Posted in Code, iOS, Mac | Tagged , , , , , | Leave a comment

使用 Groovy 語言自動操作 Jenkins

有時候我們會發現,當我們想要做一些事情的時候,光透過 Jenkins 的 Web GUI 介面很難做到,而會想知道 Jenkins 是不是有 API 可以讓我們操作,比方說。

  • 我們在一個 Jenkins 主機上面跑了很多 build job,然後我們享用另外一個頁面 / app,彙整每個 build 的狀況,像是列出我們指定範圍內的 job 中失敗的 job。
  • 或是,我們有好幾個單元測試的 job,我們想要知道這些 job 最近幾次 build 的覆蓋率是多少。
  • 批次刪除:因為某個緣故,我們可能一次失敗了好幾次,我們想把這些失敗的 build 全部刪掉,但如果只從 Jenkins 的 Web GUI,卻只能夠一筆一筆刪除,這點再 Jenkins 的官方論壇上經常有人討論,但是 Jenkins 官方並沒有加入這個功能的計畫。

Jenkins 並沒有提供我們所習慣的 Web API,但是我們可以透過要求 Jenkins 執行特定的腳本(script ),達到上面我們想要做的事情,而如果我們想要撰寫自己的 client,讀取 Jenkins 上的資料,或是其他的操作,也可以透過 HTTP Post 的方式,把腳本送到 Jenkins 上執行。—說起來這還頂危險的,如果沒有對 Jenkins 加上保護,等於可以讓人很容易就破壞了整套 Jenkins 上的資料,所以,不管怎樣,Jenkins 主機都應該放在內網,而且加上密碼保護。

我們使用 Groovy 語言撰寫 Jenkins 上的腳本,Groovy 是一套可以讓我們操作 Java 物件的物件導向腳本語言,要學習這套語言,最快的方式應該是去 Learn X in Y minutes 網站上,參考 Learn Groovy in Y Minutes 這一篇。

接著,連往你的 Jenkins 主機的 /script 目錄下,就可以看到一個文字輸入區域,在這邊可以輸入你要執行的程式碼,你也可以從 Manage Jenkins -> Script Console 進入這個畫面。而如果你要用自己的 HTTP client 要求 Jenkins 執行指定的工作,也可以把要執行的程式,post 到主機的 scriptText 路徑即可。

Continue reading

Posted in Uncategorized | Leave a comment

KKV Programming Contest 2016

2016/11/11,有一群愛台灣的人進電影院看李安導演的比利‧林恩的中場戰事 Billy Lynn’s Long Halftime Walk 。有更多人受到商人的鼓吹與店家的特惠活動,在當天貢獻了不少商業行為,買了不少東西,活絡了市場。然後有一群來自 KKBOX 子集團 – KKV (KKStream & KKTV) 的人,窩在台北的一個角落,他們有的是在寫程式 PK;有的下注手指彩卷。至於喝 Orion 啤酒、聽台灣的故事,聆聽現場的演奏,則是每個人共同享受這個下午時光的方式。
是的,我要記錄的就是我們這一群人下午的一個小故事…

哥來拍照的

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

緣起

KKStream 與 KKTV 在今年的 3 月正式宣佈成立,以 KKBOX 集團子公司的形式問世。是個好理由,可以來做點什麼不一樣的,平衡一下每天工作之餘的左右腦,順道把大家帶離開辦公室(這才是重點)。於是,我說,我們來辦個程式設計比賽吧。KKV Programming Contest 2016!

上半年就提出要來個程式設計比賽,然後一路發懶,拖到下半年,驚覺到再不捲起袖子來執行,就要跳票了!趕緊號召人組成籌備組,相較於 PyCon Taiwan 的籌備,我們運氣比較好,彈指間就處理好了金援、場地、攝影、娛樂,以及最重要的人手。

不好意思 其實我想押自己 😆

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

Steve : 撒💰囉

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

接下來的一個難題,是要怎麼讓整個活動成功。整個活動叫 KKV Programming Contest 2016 (#kkvcodecontent),活動報名頁有兩種組別,分別是競賽組以及歡樂組。
競賽組負責程式設計比賽以及吃喝玩樂;歡樂組參與手指彩卷(感謝 Vicky)以及吃喝玩樂。

我們成功的偷拐搶騙,組了 18 隊競賽組,一組至多兩人,但想要獨挑大梁的也可以一人參賽。

我賭 ____ (咦?

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

目標

整個活動的目的很簡單,就是:

  • 離開辦公室。
  • 程式設計比賽。
  • 非競賽組的人也可以同樂。
  • 愈刺激愈好,愈好玩愈好。
  • 替接下來的 KKV Hackathon 來個暖場。

嚴肅點說的話,就是想把我學生時代的 ACM ICPC 的感覺,帶進我們的團隊。ACM ICPC 是大學時期,有幸跟著同學一起參與的一個年度活動。五個小時,八個題目,一台電腦,一組四個人,同時只能三位進場,旁邊有小點心,每完成一題就有一顆氣球,可以一路從區域賽比到世界總冠軍賽,題目都很難,不乏數學,資料結構,演算法比重很高的題目,而且對程式的執行效率非常要求。

ACM ICPC 的活動,是個非常特殊的一個過程。雖然可以同時有三位團員進場,但是只有一台電腦可以用,而且題目多達八題,難度是那種你五個小時內解不完的程度,挑戰性十足,不是目前網路上的面試考題所可以比擬的。

於是你為了在這種限制下勝出,就會發展出不同的團隊合作方式,其中像是 paper coding, pair programming, printed implementation for algorithms, cooperation of different fields of questions, … 就現在軟體產業來看,是會覺得非常詭異的一種比賽的。它一方面強調考題的困難度,而且情境是要求你自己從無到有刻出來,沒有什麼 library 可以用。另一方面,它又只給你一台電腦,讓你的隊友想幫你都很困難,隊友甚至無法幫你 google 或是上 stackoverflow!?事實上,在那個時代,stackoverflow 根本還沒有出現!聰明如你,一定會覺得辦這種程式比賽要幹麻,一點用處都沒有,還不如辦個 hackathon 比較有意義。

但如果我換個方式說明,你可能就不會這麼想了。大家都知道 Google 是一家非常優秀的公司對吧?雖然有 Facebook, Amazon, Apple, Microsoft, Twitter, Netflix 等這些一樣非常厲害的公司,但是一但聊到「比較硬派的軟體公司」或是「基礎技術比較深厚的公司」時,大部分人應該會覺得還是 Google 拔得頭籌的吧?那你知道有個叫 Google Code Jam 的活動嗎?!

Google Code Jam is an international programming competition hosted and
administered by Google. The competition began in 2003 as a means to
identify top engineering talent for potential employment at Google.
The competition consists of a set of algorithmic problems which
must be solved in a fixed amount of time.
Competitors may use any programming language and development environment to obtain their solutions.

In 2008, over 11,000 people from more than 128 countries competed for
prize money totaling over $80,000, including a top prize of $10,000.

wikipedia

KKV 並不是要這麼不務實,喊著要朝向 Google 為目標發展,但實際上卻只做著技術整合的公司。相反的,KKV 更像是在朝向商業成功的同時,持續花力氣在某些領域深耕,同時以各種形式來提醒自己,我們是一群要求在技術上有不同觀點與堅持的公司。某種程度上,是傳承著 KKBOX 這家以「技術著手,產品著眼」的公司文化的一群人。

競賽規則

  • 會一次收到三封 codility 的邀請函(題組)。點開聯結,就差不多開始了。
  • 只能有一台電腦,同時開啟三封信來比賽。
  • 總共有 18 (3組 * 6) 題,不用擔心太快就沒事了。
  • 比賽時間總計 137’(是個質數)。
  • 可以選擇最擅長的程式語言比,但你的英文一定要 Ok。
  • 每題只能 submit 一次,多多善用 test run。
  • 每一題的得分是 0~100,總分 1800,最高分得獎。
  • 每完成 [1, 3, 5, 10, 15, 18] 題,就有一顆氣球!60 分算完成。
  • 拿到所有組的第 [10, 30, 50] 顆氣球的組別,一樣有獎!
  • 不欣賞作弊行為,但是,我們也不阻止互相騷擾的行為 :D

不要說我沒努力

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

至於歡樂組規則呢…這點我們就跳過,當作營業祕密吧 :D

發🎈的小女孩

A post shared by KKV Programming Contest 2016 (@kkvcodecontest) on

場地

感謝後台Backstage Café的協助,在這個舒適的場地,渡過了一個下午。

現場演奏

天空下 by 盧芸

另一首安可曲(忘了名字) by 盧芸

沒 Youtube ;p

阿春仔伊阿嬤 by 進錕

228 by 進錕

沒 Youtube ;p

黃昏的故鄉 by 進錕

母親的名叫台灣 by 進錕

沒 Youtube ;p

回顧與反思

我想…我們這樣硬是拿 codility 來作為程式競賽的系統,應該算是及格了。codility 原本只是 KKBOX 集團拿來做為輔助面試時的一個工具:主考官出幾題程式題目,應徵者在規定的時間內,上機 live 解答,整個過程都會被錄下來。它目前有約 15x 個題目,其中 coding 與 algorithm 是比較適合,加起來約有 100 題可以挑選。這些題目支援的程式語言很多,從 C/C++/Java/JavaScript/Python/PHP 到 Go/Scala/Swift 2&3 都有。

美中不足的,是一個題組只能有 6 題,這也是為什麼我們的比賽規則要求選手要一次開三個題組。如果以 codility 一個 credit 約台幣 200 元來看,
我們這一次的活動用掉了 18 * 3 * 200 = 10,800 TWD :D

另一個非常不 ok 的,是每一個題目你只能送件一次,這點與 ACM ICPC 很不同 :p要求參賽者每一題只能送件一次,有點太嚴苛~

另一個讓人覺得有點可惜的,是啤酒實在太少了!有競賽組的同事表示,沒有啤酒他無法專心下來寫 code…更有表演的進錕自己掏腰包買杯冰啤上台表演的…

對了,我有沒有提到,整個活動能完成,全歸功於所有 KKV 成員?!

參考

原文刊登在KKV Programming Contest 2016 on Drake’s weblog

Posted in Events | Tagged , , | Leave a comment

Your Delegation Methods Might Not Be Called In Swift 3

One of the most obvious changes in Swift 3 is its naming convention. Apple also renamed lots of methods when releasing Xcode 8.

To make new Swift APIs to be compatible with existing Objective-C APIs, Swift compiler converts Swift 3 methods to corresponding Objective-C selectors, but sometimes such conversion does not happen.

The worst case is, you implement a delegation method, but it is never be called, and you do not know why.

Continue reading

Posted in Code, iOS, Mac | Tagged , , , , , | Leave a comment

Upgrade to Xcode 8

Xcode 8 was out along with iOS 10, watchOS 3, tvOS 10 and macOS 10.12 Sierra last month. We spent a couple of days to upgrade our development environment and build machines of our continuous integration system to Xcode 8, just like many other developers do.

It was not as easy as just to click on the “Upgrade” button in Mac App Store. Things might be broken and need to be fixed. Upgrade is always somehow painful, but a yearly routine.

On the other hand, Apple added several additional validations that validates your new uploaded builds on iTunes Connect. If you cannot pass these validations, your builds will be invalid and you cannot complete app submission.

You may want to read our experience before upgrading to Xcode 8. We also suggest you to upload some new builds recently to see if you can pass these new validations.

Continue reading

Posted in Code, iOS, Mac | Tagged , , , , | Leave a comment

KKBOX 的 WWDC 2016 讀書會影片

KKBOX 今年也舉辦了 WWDC 影片的讀書會,我們挑選了一些我們比較有興趣的主題,在公司內分享。您可以從下方找到我們的讀書會錄影,以及每場讀書會對應的 WWDC 官方影片。

Continue reading

Posted in Code, iOS, Mac | Tagged , , , | 2 Comments

KKBOX 的音樂檔案儲存技術

前情提要

時間拉回到 2013 年,KKBOX 在當年的 COSCUP 曾介紹過如何使用 MogileFS 這套 DFS(Distributed file systems),儲存其音樂服務的各種檔案。

Slide: 全台灣最宅的科科科技如何利用 MogileFS 儲存數千萬個音樂檔案
錄影:

現在的狀況

時隔三年,雖然各間雲端服務商都有提供可靠的儲存技術可以使用,但 KKBOX 還是繼續使用原本的 MogileFS 來儲存大量的音樂檔案,隨著串接的唱片及版權公司逐年增加,音檔數量一直不斷成長。2013 年突破 1,000 萬首,2016/8/1 最新公布的數字(賀!KKBOX曲庫國際級水準 擴增至超過3000萬首歌!)是 3,000 萬首,這是取得授權上架的數字,實際上 KKBOX 後端的曲庫數量是超過這個數字。

MogileFS 規模

  • 儲存伺服器超過 75 台。
  • 總硬碟超過 2,300 顆。
  • 總儲存空間超過 10 PB
  • 使用 8 個機櫃。

Metadata Database

儲存檔案 Metadata 的 Database 技術沒有變化,依然使用 MySQL 搭配 HeartbeatDRBD 達到 High Availability

Tracker

Tracker 原本利用部分 storage server 分擔 replicate 工作,但遇到效能問題,所以改使用 4 台 dedicated 的伺服器負責 Tracker 角色。

每台 Tracker 都是兩張 1Gbps NIC 設定 802.3ad 模式的 Linux Bonding。

Storage Server 硬體規格

  • 系統碟用 2 顆 500GB SATA 硬碟設定成 RAID 1
  • 36 顆 6TB WD 紅標硬碟儲存 MogileFS 檔案。
  • 兩張 1Gbps NIC 利用 Linux Bonding Driver 設定標準 802.3ad 模式 LACP。
  • 一台 storage server 有 200TB 的空間。
  • 一機櫃 10 台 storage server 能提供 2PB 空間。

網路架構

  • tracker 和 storage server 都是兩條 1Gbps LACP 接到 Top-of-Rack 的 L2 Switch。
  • 每台 Top-of-Rack 都是兩條 10Gbps 光纖 LACP 到資料中心的 Core Router。

三年來的使用心得

優點

  • 成本相較企業級儲存解決方案(NetApp, EMC, …)低。
  • 容易擴充,KKBOX 從最一開始的 3 台 data node 逐漸成長到現在的超過 75 台。
  • 直接使用 NginxWebDAV module 包裝磁碟讀寫行為,能提供很高的效能,實際使用上能輕易的吃滿 storage server 的 2Gbps 頻寬。

缺點

  • 沒有自動 rebalance 的功能,在擴充容量後需要自行下指令 rebalance,讓各台間的磁碟使用量一致。
  • MogileFS 策略上會優先往磁碟使用量低的 device 寫入新資料,在平常的寫入量就不低的情況下,新增的 data node 數量太少,就容易有磁碟 I/O 及網路傳輸瓶頸。
Posted in Uncategorized | 3 Comments

Open source our Marco Polo DNS Daemon

Today we open source Marco Polo DNS Daemon.

KKBOX provides music services over 6 regions, including Taiwan, Hong Kong, Singapore, Malaysia, Japan, and Thailand. We deploy technologies to improve performance and user experience. We build serveral data centers in Taiwan, and partner with EdgeCast, Akamai, and CloudFront to make sure our users get best performance.

We implemented algorithms in API-level to select best server or CDN vendor for delivering audio data. API-level algorithms gave us flexibility to dispatch clients.

However, there is still something we cannot control in API-level, like image service. We want to dispatch clients to different data centers or CDN vendors in DNS-level.

Marco Polo DNS Daemon is a DNS server written by Perl, which can return different CNAME results based on client’s DNS resolver IP address and edns-client-subnet information. This allows us to control traffic by country code and AS number.

For example, we want to use country code and expect it returns a CNAME record to test.kkcube.com:

$ dig test.kkcube.com.country.mp.kkcube.com @8.8.8.8

And it returns:

;; ANSWER SECTION:
test.kkcube.com.country.mp.kkcube.com. 20 IN CNAME TW.test.kkcube.com.

Which is because I am in Taiwan. And if you want to use AS number:

$ dig test.kkcube.com.asn.mp.kkcube.com @8.8.8.8

Then it will return:

;; ANSWER SECTION:
test.kkcube.com.asn.mp.kkcube.com. 20 IN CNAME  3462.test.kkcube.com.

Which AS3462 belongs to my ISP, HiNet. Now you can setup test.kfs.io CNAME to test.kkcube.com.country.mp.kkcube.com, and setup another DNS record for TW.test.kkcube.com to accelerate Taiwan’s clients.

Please feel free to give us feedback in GitHub.

Posted in DNS | Tagged , , , , , , , , , , , , , | Leave a comment

Android at Google I/O 2016 上集

Google I/O 2016 結束一段時間了,今年總共放出影片 182 部,其中和 Android 相關的影片有 65 部,為了要快速了解今年本部門的守備範圍內有哪些新東西,大家分著把影片看過一輪後再與彼此分享,順便各自寫了些摘要分享出來給國內的 App 開發者們。

Android at Google I/O 2016 中集
Android at Google I/O 2016 下集

Continue reading

Posted in Uncategorized | 2 Comments