# 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.
> 讀取標準輸入 並將最後五行寫入標準輸出
>
> 
> 修正為 `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:
>
> 
:::info
**This is a series of transformations:**
directory name
→ list of files
→ list with line numbers
→ sorted list
→ highest five + total
→ highest five
:::

### 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

:::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 拆解

### 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)`

- 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

```
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.

- 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**)

2. design diagram shows class hierarchies(類別的層次結構) => grow into wall-covering monstrosities => make the application more brittle

### Don’t Pay Inheritance Taxt
- three techniques that mean you never need to use inheritance again:
**1. Interfaces and Protocols**(介面和協定)

- 用Class Car實作drivable, locatable的行為
- Drivable and Locatable are what Java calls interfaces; other languages call them protocols
- Interfaces are defined like this:

- 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:


> 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

- The Account class carries all of the persistence class’s API around with it.
- an alternative using delegation:

- 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.

:::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)