---
# System prepended metadata

title: Topic 30 - 31
tags: [The Pragmatic Programmer]

---

# Topic 30 - 31
###### tags: `The Pragmatic Programmer`
## Topic 30 Transforming Programming
### intro and example
- When we think about design, we rarely think about **creating transformations**. Instead we worry about classes and modules, data structures and algorithms, languages and frameworks.
- 1970s example: write a program that lists the five **longest (having the largest number of lines)** files in a directory tree.

### solved

`$ find . -type f | xargs wc -l | sort -n | tail -6 | head -5`

> `find . -type f` 
> 
> Write a list of all the files (-type f) in or below the current directory (.) to standard output.
> 將目前目錄（.）中或以下的所有檔案(-type f)寫入標準輸出

> `xargs wc -l`
> 
> Read lines from standard input and arrange for them all to be passed as arguments to the command wc -l. 
> The wc program with the -l option counts the number of lines in each of its arguments and writes each result as “countfilename” to standard output.
> 從標準輸出中讀取多行 並將它們全部作為參數傳遞給命令 wc -l
> 帶有 -l選項的wc程式會計算每個參數中的行數
> 並將每個結果以行數檔案名稱的格式 寫入標準輸出

> `sort -n`
> 
> Sort standard input assuming each line starts with anumber (-n), writing the result to standard output.
> 假設標準輸入每行都以數字（-n）開頭 進行排序
> 並將結果寫入標準輸出

> `tail -5`
> 
> Read standard input and write just the last five lines tostandard output.
> 讀取標準輸入 並將最後五行寫入標準輸出
> 
> ![](https://i.imgur.com/KXz6HBS.png)

> 修正為 `tail -6 | head -5`
> 
> last line : the total number of lines in all the files
> We can strip last line off by requesting one more line from tail, and then ignoring the lastline:
> 
> ![](https://i.imgur.com/sWUjiLu.png)

:::info
**This is a series of transformations:**
directory name
→ list of files
→ list with line numbers
→ sorted list
→ highest five + total
→ highest five
:::
![](https://i.imgur.com/2j1PUGL.png)

### intro conclusion
- A series of transformations like **an industrial assembly line**: feed raw data in one end and the finished product (information) comes out the other.
- And we like to think about all code this way.

### main topic

> **Programming Is About Code, But Programs Are About Data**
- the easiest way to find the transformations is to start with the **requirement** and determine its inputs and outputs.
- This is a top-down approach. (從上往下建構的方法)

example: word games
input: a set of letters
output: is a list of three-letter words, four-letter words, or five-letter words
![](https://i.imgur.com/RjzmHJg.png)

:::info
The anagram finder breaks down into four separate transformations:

step 0 : Initial input
step 1 : All combinations of three or more letters
step 2 : Signatures of the combinations
step 3 : List of all dictionary words which match any of the  signatures
step 4 : Words grouped by length
:::

### Step 1 拆解

![](https://i.imgur.com/8FdRcDy.png)

### using Elixir in this case

```
defp all_subsets_longer_than_three_characters(word) do      
  word  
  |> String.codepoints()  
  |> Comb.subsets()  
  |> Stream.filter(fn subset -> length(subset) >= 3 end)  
  |> Stream.map(&List.to_string(&1))
end
```

:::info

**What’s with the |> Operator?** **管道運算子**
- name: pipeline operator (or forward pipe or pipe)
- func: All it does is **take the value on its left and insert it as the first parameter of the function on its right**

`arg |> func` is equivalent to `func(arg)`

![](https://i.imgur.com/T5n4grP.png)

- pros:
(1) more than just syntactic sugar (automatically thinking in terms of transforming data) : each time you see |> you’re actually seeing a place where data is flowing between one transformation and the next.
(2) greatly improves the readability of our code.

**Language X Doesn't Have Pipelines**
- Pipelines have been around for a long time, but only in niche languages (Elm, F#, Swift, Clojure, R and Haskell)
- Thinking in transformations doesn’t require a particular language syntax: it’s more a philosophy of design. 
- Write them as a series of assignments (寫成一系列賦值的動作):
```
const content = File.read(file_name);
const lines   = find_matching_lines(content, pattern)
const result  = truncate_lines(lines)
```
### conclusion
- It's not an official JavaScript member yet（still in stage 2 ）. 
- Babel plugin, which will let us use pipeline operators right now before the pipelines reach stage 3 or 4. 
- create our own piping function
:::

### Step 2 拆解 : convert the subsets into signatures

![](https://i.imgur.com/WIR9QKd.png)

``` 
defp as_unique_signatures(subsets) do  
  subsets
  |> Stream.map(&Dictionary.signature_of/1)
  end
```

### Step 3 拆解 : remove the nils and flatten the nested lists into a single level
each signature gets mapped to the list of known words with the same signature, or nil if there are no such words
```
defp find_in_dictionary(signatures) do
  signatures  
  |> Stream.map(&Dictionary.lookup_by_signature/1)
  |> Stream.reject(&is_nil/1)  
  |> Stream.concat(&(&1))
  end
```

### Step 4 拆解 :  grouping the words by length
```
defp group_by_length(words) do  
  words  
  |> Enum.sort()  
  |> Enum.group_by(&String.length/1)
  end
```
### Final Step : Putting It All Together
```
def anagrams_in(word) do
 word    
 |> all_subsets_longer_than_three_characters()    
 |> as_unique_signatures()    
 |> find_in_dictionary()    
 |> group_by_length()
 end

```
### conclusion：WHY IS THIS SO GREAT?
:::info
if you are a object-oriented programmer :
hide data --> 
encapsulating(封裝) it inside objects --> 
a lot of coupling --> 
OO systems be hard to change
:::

> **Don’t Hoard State; Pass It Around**
* Instead of little pools of data spread all over the system, think of data as a mighty river, a flow.
* The data is no longer tied to a particular group of functions, as it is in a class definition
* we can greatly reduce coupling: a function can be used (and reused) anywhere its parameters match the output of some other function.
* there is still a degree of coupling, but in our experience it’s more manageable than the OO-style of command and control.

**ERROR HANDLING?**
- **basic convention: we never pass raw values between transformations**, Instead, we wrap them in a data structure (or type) which also tells us if the contained value is valid.
- How you use this concept is language specific.

**First, Choose a Representation**
We need a representation for our **wrapper** (the data structure that carries around a value or an error indication **攜帶值或錯誤指示的資料結構**). 

```
iex(1)> File.open("/etc/passwd")
{:ok, #PID<0.109.0>}
iex(2)> File.open("/etc/wombat")
{:error, :enoent}
```
**Elixir for example:**
- functions tend to return a tuple containing either {:ok, value} or {:error, reason}
- use the :ok/:error tuple as our wrapper when passing things through a pipeline

**Then Handle It Inside Each Transformation**

Q: Let’s write a function that returns all the lines in a file that contain a given string, truncated to the first 20 characters.

* input:  a file name and a string to match
* output: either an :ok tuple with a list of lines or an :error tuple with some kind of reason.
```
def find_all(file_name, pattern) do
File.read(file_name)  
|> find_matching_lines(pattern)  
|> truncate_lines()
end
```
**With error checking by Elixir’s pattern matching**
```
defp find_matching_lines({:ok, content}, pattern) do 
content
|> String.split(~r/\n/)  
|> Enum.filter(&String.match?(&1, pattern))  
|> ok_unless_empty()
end

defp find_matching_lines(error, _), do: error

# ----------

defp truncate_lines({ :ok, lines }) do
lines
|> Enum.map(&String.slice(&1, 0, 20))  
|> ok()
end

defp truncate_lines(error), do: error

# ----------

defp ok_unless_empty([]),     do: error("nothing found")
defp ok_unless_empty(result), do: ok(result)

defp ok(result), do: { :ok, result }
defp error(reason), do: { :error, reason }
```
### Final conclusion
* Thinking of transforming programming can be **a liberating approach to programming.**
* It takes a while to get used to, but once you’ve developed the habit you’ll find your code becomes cleaner, shorter, and flatter.


## Topic 31 Inheritance Tax
### intro and history
- Do you program in an object oriented language? Do you use inheritance? If so, stop! It probably isn’t what you want to do.
> You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
- Inheritance first appeared in Simula 67 in 1969.
- **prefix classes** : the `link` is a prefix class that adds the functionality of linked lists. => `link` would be a parent class（父類別）.
```
link CLASS car;
    ... implementation of car
link CLASS bicycle;
    ... implementation of bicycle
```
The `link` part was viewed as being a container (a form of polymorphism) : cars and bicycles both implemented the `link` interface because they both contained the `link` code.
- After Simula came Smalltalk.
- Simula (inheritance was a way of combining types) =>  C++ and Java
- Smalltalk (inheritance was a dynamic organization of behaviors) => as Ruby and JavaScript
### intro conclusion
- now OO developers use inheritance for one of two reasons: 
1. who don’t like typing =>  add common functionality from a base class（基礎類別） into child classes（子類別）
2. who like types => express the relationship between classes: a Car is-a-kind-of Vehicle.

### PROBLEMS USING INHERITANCE TO SHARE CODE
>  Inheritance is coupling.

![](https://i.imgur.com/JBG0dUQ.png)

- example flow
1. calls my_car.move_at
2. invoked method: the parent of Car(Vehicle)
3. if API changes: move_at becomes set_velocity, and the instance variable @speed becomes @velocity.
4. expected to break clients of Vehicle class. But the top-level is not (using a Car) => it still breaks

- inheritance's pros and cons
1. is a way of defining new types => **the multiple inheritance(多重繼承)**：A Car maybe a kind of Vehicle, Asset, InsuredItem(保險標的), LoanCollateral(擔保品) and so on. (**most current OO languages don’t offer multiple inheritance**)
![](https://i.imgur.com/R3HxYdw.png)
2. design diagram shows class hierarchies(類別的層次結構) => grow into wall-covering monstrosities => make the application more brittle
![](https://i.imgur.com/rsstSAE.png)

### Don’t Pay Inheritance Taxt 
- three techniques that mean you never need to use inheritance again:

**1. Interfaces and Protocols**(介面和協定)

![](https://i.imgur.com/8g9tO3E.png)
- 用Class Car實作drivable, locatable的行為
- Drivable and Locatable are what Java calls interfaces; other languages call them protocols
- Interfaces are defined like this:

![](https://i.imgur.com/7xC5N1W.png)

- any class that implements Drivable must implement the two methods getSpeed and stop,  and a class that’s Locatable must implement getLocation and locationIsValid. => Car will only be valid if it includes all four of these methods
- we can use interfaces as types => If Car and Phone both implement Locatable, we could store both in a list of locatable items：

![](https://i.imgur.com/L1T20Rc.png)

![](https://i.imgur.com/EisypOq.png)

> Prefer Interfaces to Express Polymorphism
- Interfaces and protocols give us polymorphism without inheritance

**2. Delegation**(委派)
- Inheritance => create classes => objects have large numbers of methods => If a parent class has 20 methods => subclass wants to make use of just two =>  other 18 callable methods

![](https://i.imgur.com/0JYqDcB.png)
- The Account class carries all of the persistence class’s API around with it.
- an alternative using delegation:

![](https://i.imgur.com/SPTCvTa.png)

- now expose none of the framework API to the clients of our Account class

:::info
Delegation v.s. Inheritance
- 繼承的主角是父類，子類繼承父類方法；委派(無子父類關係)主角為委派方，將自己的一部分對象委派給另一個方法執行
- 子類只需要複用父類中部分方法時 => 使用委派 (子類不需繼承其父類中對其無用的方法)
- 委派方無法更改被委派方的代碼，繼承的子類可以重寫父類的方法

:::

**3. Mixins and traits**（混合和特性）
> merging functionality between existing things and new things 合併現有內容和新內容
- we want to extend classes and objects with new functionality without using inheritance. => create a set of these functions(函式集合), give that set a name, and then somehow extend a class or object with them.
- a new class or object that combines the capabilities of the original and all its mixins.

![](https://i.imgur.com/3kgoZNz.png)
:::info
- 實現多重繼承的一個技巧
- 在層次上具有單一繼承一樣的樹結構，同時又可以實現功能的共享（方法是：把共享的功能放在Mixin 類中，再把Mixin 類插入到樹結構裡
:::

## reference


[pipeline-operator](https://cloudemployee.co.uk/blog/code/all-you-need-to-know-about-pipeline-operator-and-piping-in-javascript)
[Delegation and Inheritance](https://blog.csdn.net/weixin_44160014/article/details/107209315?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-107209315-blog-45510325.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-107209315-blog-45510325.pc_relevant_recovery_v2&utm_relevant_index=1e)