網路難,難於上青天 - 用部件化的方式簡化網路程式設計 - 王巍
===
{%hackmd FGRWt1UuTFKk0wSbGgg-SA %}
## YouTube
{%youtube Xk4HZfW6vK0 %}
## Slide
{%speakerdeck onevcat/wang-lu-zhi-nan-nan-yu-shang-qing-tian-iplayground-2019 %}
## 網路不難
以前
NSURLConnection
JSON: stig/json-framework
UITableView
* 網路框架/封裝:
- AFNetworking
- Alamofire
- Moya
### Lean from scratch
Code: URLSession.shared.dataTask(request: Request)
* HTTP Client - Request/Response
(Data?, URLResponse, error)
上面太醜了,下面來封裝
HTTPResponse<T: Codable>
- HTTPRequest: 將 xxx, method 進行封裝
- Client
- HTTPResponse
### 改良 - Response
Result<HTTPBinPostResult, Error>
使用 Result Type 將 Reponse 回應封裝起來
### 改良 - Request
Response Type用 **associatedtype** 和Request合起來
```Swift
protocol Request {
associatedtype Response: Decodable
var url: URL { get }
var method: HTTPMethod.POST { get }
var parameters: [String: Any] { get }
...
}
```
## 網路請求是什麼
- get
- post
client ?
- 請求
- 回應
## 網路很難
> 現實是殘酷的 (放大)
### Case1 - Request
* Get 不能塞body,怎樣處理
* 找BuildRequest -> 改良決定 ``"Content-Type"``
**閱讀 ReadRFC3986**
### Case2 - Response
* 沒有 token (403 Forbidden)
### Case3 - Client
#### Retry
一直加東西
#### 更新 token
繼續加東西
#### 資料轉換
一直加一直爽,建造長城 GO!
## 網路不應該很難
* SRP 單一職責原則
> 不要全扔到一個地方。你的代碼庫,不是垃圾場。
> 連垃圾都需要分類!!
- client 的職責
1. 配置請求
2. 處理回應
### Content Adatpter
新增Adapter來處理資料等,像是前面提到的那幾個問題(Httpmedthod & ContentType)
為 Request 配置 [RequestAdapter]
### 抽象: Response Decision
用決策 Decision來抽象化
- continue
- restart
- error
- done
```Swift
protocol Decision {
func shouldApply<Req: Request>()
func apply<Req: Request>()
}
```

### 添加 Decision 實作
### 為Request配置[Decision]
> 代碼內在的純潔,
> 能讓生活充滿甜蜜和喜悅
> 外在沒有變、內在大不同
## 優勢
* 元件化 **清晰**
* 純函數 **可測試**
* 基於protocol **靈活**
* 更多決策 **可擴展**
* 細粒度控制 **可操作**
## 最後最後的總結
1. 代碼**分類**從我做起
2. **組合** > 繼承,**描述** > 指令
3. 無從下手時,先**思考**和**抽象**
4. 不斷重構,保持活力
https://github.com/onevcat/
https://github.com/onevcat/ComponentNetworking
https://github.com/line/line-sdk-ios-swift
###### tags:`iPlayground2019` `keynote`