顯示具有 計算機概論 標籤的文章。 顯示所有文章
顯示具有 計算機概論 標籤的文章。 顯示所有文章

面向過程 vs 面向對象

https://zhuanlan.zhihu.com/p/28427324

本文以設計五子棋程式為例,比較「面向過程」與「面向對象」的差異、優缺點。

總結來說,兩種思想各有優勢,不同的需求使用不同的方法和設計模式即可,實務上往往是混合使用的。




学习编程, 基本功是掌握编程语言,但编程的本质是逻辑,所以编程思维的培养也很重要。面向过程和面向对象是两种重要的编程思想,下面讲述一下这两者的区别和优缺点比较。

1. 面向过程

面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数。



举个例子,下五子棋,面向过程的设计思路是首先分析解决这个问题的步骤:

(1)开始游戏(2)黑子先走(3)绘制画面(4)判断输赢(5)轮到白子(6)绘制画面(7)判断输赢(8)返回步骤(2) (9)输出最后结果。

用函数实现上面一个一个的步骤,然后在下五子棋的主函数里依次调用上面的函数(不同的编程语言有不同的调用方法,我这里写的是直接调用):

下五子棋{

开始游戏();

黑子先走();

绘制画面();

判断输赢();

轮到白子();

绘制画面();

判断输赢();

返回到 黑子先走();

输出最后结果;

}

可见,面向过程始终关注的是怎么一步一步地判断棋局输赢的,通过控制代码,从而实现函数的顺序执行。

2. 面向对象

在日常生活或编程中,简单的问题可以用面向过程的思路来解决,直接有效,但是当问题的规模变得更大时,用面向过程的思想是远远不够的。所以慢慢就出现了面向对象的编程思想。世界上有很多人和事物,每一个都可以看做一个对象,而每个对象都有自己的属性和行为,对象与对象之间通过方法来交互。面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个对象在整个解决问题的步骤中的属性和行为。



在下五子棋的例子中,用面向对象的方法来解决的话,首先将整个五子棋游戏分为三个对象:

(1)黑白双方,这两方的行为是一样的。

(2)棋盘系统,负责绘制画面

(3)规则系统,负责判定犯规、输赢等。

然后赋予每个对象一些属性和行为:

(4)第一类对象(黑白双方)负责接受用户输入,并告知第二类对象(棋盘系统)棋子布局的变化,棋盘系统接收到了棋子的变化,并负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

可以看出,面向对象是以功能来划分问题,而不是以步骤解决。比如绘制画面这个行为,在面向过程中是分散在了多个步骤中的,可能会出现不同的绘制版本,所以要考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘系统这个对象中出现,从而保证了绘图的统一。


3. 优缺点比较

面向过程

优点:

流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果,具体步骤清楚,便于节点分析。

效率高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。

缺点:

需要深入的思考,耗费精力,代码重用性低,扩展能力差,后期维护难度比较大。

面向对象

优点:

结构清晰,程序是模块化和结构化,更加符合人类的思维方式;

易扩展,代码重用率高,可继承,可覆盖,可以设计出低耦合的系统;

易维护,系统低耦合的特点有利于减少程序的后期维护工作量。

缺点:

开销大,当要修改对象内部时,对象的属性不允许外部直接存取,所以要增加许多没有其他意义、只负责读或写的行为。这会为编程工作增加负担,增加运行开销,并且使程序显得臃肿。

性能低,由于面向更高的逻辑抽象层,使得面向对象在实现的时候,不得不做出性能上面的牺牲,计算时间和空间存储大小都开销很大。



举例说明两者的优缺点,比如在五子棋游戏中增加悔棋的功能。在面向过程中,从输入到显示再到最后判断的整个步骤都要改动,甚至函数的调用顺序也要改动,而在面向对象的设计中,只需在棋盘系统中增加一个回溯的功能就可以了,黑白双方和规则系统的属性和行为都不需改动。这个例子说明了面向对象程序设计中代码间的相关性低(低耦合特性),使得代码很容易被复用和扩展,同时也说明了面向过程的代码重用性低、扩展能力差。



macOS 快捷鍵

多重桌面
Control + 向上鍵
Control + 向左鍵
Control + 向右鍵

資料夾或文件
command+delete (丟到垃圾桶)
command+C (複製)
command+V (貼上)

處在中文輸入法的情況時
shift+, (逗號等等標點符號)
shift+. (句號等等標點符號)
其餘標點符號依此類推

擷取畫面
command+shift+3 (擷取全螢幕)
command+shift+4
(拖移十字線 以選取要擷取的螢幕範圍。 若要移動所選範圍,請在拖移時按住空白鍵。 若要取消拍攝截圖,請先按下Esc(Escape)鍵。)

另外還有『擷取軟體視窗,有陰影』、『擷取軟體視窗,無陰影』、『固定擷取大小,移動擷取區域』、『固定擷取長度或寬度,移動另一邊大小』,詳閱
https://www.bnext.com.tw/article/41237/mac-screen-capture-keyboard


容器化的微服務開發

https://columns.chicken-house.net/2017/05/28/aspnet-msa-labs1/


  1. 微服務架構(概念說明)
  2. 實做基礎技術: API & SDK Design
  3. 架構師觀點 - 轉移到微服務架構的經驗分享
    • Part #1 改變架構的動機; 2017/05/09
    • Part #2 實際改變的架構案例; 2017/05/20
    • Part #3 實際部署的考量: 微服務基礎建設; 2017/07/11
  4. 基礎建設 - 建立微服務的執行環境
    • Part #1 微服務基礎建設 - Service Discovery; 2017/12/31
    • Part #2 微服務基礎建設 - 服務負載的控制; 2018/06/10
    • Part #3 微服務基礎建設 - 排隊機制設計; 2018/12/12
    • Part #4 可靠的微服務通訊 - Message Queue Based RPC; 2019/01/01
    • Part #5 非同步任務的處理機制 - Process Pool; 2020/02/15
    • (計畫) 微服務基礎建設 - Service Mesh;
    • (計畫) 微服務基礎建設 - Circuit Breaker;
    • (計畫) 微服務基礎建設 - Log Tracking & Auth;
    • (計畫) 微服務基礎建設 - 版控, CI/CD, 容器化部署;
  5. 案例實作 - IP 查詢服務的開發與設計
  6. 建構微服務開發團隊


架構師觀點: 你需要什麼樣的 CI / CD ?

https://columns.chicken-house.net/2017/08/05/what-cicd-do-you-need/



文章目录



Architecture: MVP, MVC, MVVM

https://dotblogs.com.tw/regionbbs/2011/09/29/compare_to_mvp_mvc_mvvm

最近 MVC (Model-View-Controller) 和 MVVM (Model-View-ViewModel) 在微軟圈成為顯學,ASP.NET MVC 和 WPF 的 Prism (MVVM Framework) 功不可沒,MVC 和 MVVM 在概念上都是基於分層的,將呈現 (presentation) 與資料 (data) 分開的設計架構,M 和 V 基本上不是問題,但將這兩個整合的中間這層可就有很多的學問,另外,除了 MVC 和 MVVM 外,還有一個叫做 MVP (Model-View-Presenter) 的架構,這三個的設計概念非常類似,很容易會讓人傻傻分不清楚 ...

我們先來看各個架構的設計原則好了。

首先是 MVC,顧名思義,MVC 是將 Model, View 和 Controller 分離,讓彼此的職責 (responsibility) 能夠明確的分開,這樣不論是改 M, V 還是 C,都可以確保另外兩層可不用做任何修改,同時這樣的分層也可以加強程式的可測試性 (testability),View 和 Model 基本上是相關的,但它們並不會有直接的相依關係,而是由 Controller 去決定 Model 產生的資料,然後丟給 View 去做呈現,也就是說,Controller 是 Model 和 View 之間的協調者 (coordinator),View 和 Model 不能直接溝通,以確保責任的分離。而 Controller 可以只是一個繫結 Model 和 View 的小類別,也可以是大到包含 Workflow, Enterprise Services 或是做為外部系統的 Proxy Services 等的邏輯系統,MVC 各元件是可以分離的組件,也可以是分離的系統 (當然要設計一些機制在相互溝通)。


再來是 MVVM,MVVM 的架構一樣是 M, V 分離,但中間是以 VM (ViewModel) 來串接,這個 ViewModel 比較像是 View 的一個代理程式,它負責直接對 Model 做溝通,而 View 可以透過一些機制 (ex: Events, Two-way Databindings, ...) 來和 ViewModel 溝通以取得資料或將資料拋給 Model 做存取等工作,ViewModel 也可以作為和外部系統的代理程式,例如 Web Service 或是 REST Service 或是 Enterprise Services 等等,不過它和 MVC 不同的地方,就是 ViewModel 和 View 的黏合度比較高,因為 View 必須要透過 ViewModel 才可以取得 Model,而 ViewModel 又必須要處理來自 View 的通知訊息,所以雖然職責一樣分明,但是卻不像 MVC 那樣可以擴展到整個系統元件都能用。如果 MVVM 要和 MVP 比較的話,MVVM 會比 MVP 更靈活一點。

接著是 MVP,MVP 一樣也是職責分明,且 Model 與 View 分離的架構,但是這個 P (Presenter) 和 ViewModel 就很類似,不過就如同 Presenter (主持人) 這個字所代表的意義,所有主控 View 呈現的工作,都是由 Presenter 來做,而 View 本身只是 Presenter 所要使用的舞台而已,所以 View 原則上會相依於 Presenter,但是為了要做到關注點分離 (SoC 原則),所以在 View 和 Presenter 間都會加入一個介面 (ex: IView),然後以 IoC 的方式將 View 注射到 Presenter 中,而 Presenter 就使用介面所定義的方法去操控,而 View 就透過介面所定義的方法去呈現介面即可。但也因為受限於介面,所以 Presenter 只能依介面定義的動作去回應與處理,而不能再做更多的延伸功能,除非更改 View 的介面。

由上面各個架構的討論,我們可以得到以下的結果:


  1. MVC 架構適合於大型系統,它可以分層且可以在實體層面切割為不同的機器或服務,只要彼此間具有適當的通訊協定即可。
  2. MVVM 架構適合像 XAML 這種與程式碼無關 (code ignorance) 的使用者介面設計,只要 View 中下特定的指令與 ViewModel 串接,就可以享有 ViewModel 溝通的功能,而 ViewModel 只需做一些特別的介面實作,即可平順的和 View 溝通。
  3. MVP 架構適合集中由程式碼決定 View 動作的應用程式,而 View 只需要實作特定的介面即可,不需要太複雜的工作,但 Presenter 則可能會受限於 View 介面的動作,而無法做更進一步對 View 的控制。

最後我想提的是,MVC 的包容度比 MVVM 和 MVP 要來的高,在 MVC 的 V 層,可以再進一步的包含 MVVM 或 MVP 的實作,而 C 層也可以使用 MVP (V 是輸出的資料) 來進一步切割資料的流動與輸出,M 層則可以類似 MVVM 的架構,當 V (元件) 有資料的異動時,VM 即可自動偵測到並更新 Model (資料庫)。當然,要用什麼樣的架構去設計,端看當時的系統環境與需求來決定,而不是只想著要用同一種架構去做所有的系統。


將 Object 序列化為 Json 時,攤平 Json string 欄位

https://blog.yowko.com/not-serialize-json-string/


在不同系統間透過 Json 來交換資料是很常見的設計,甚至在某些系統上還可以見到將 Json string 儲存在屬性中,當然有人會質疑這樣就失去強型別的好處,不過會這樣使用就是希望達到 schema-free 的彈性:在一開始未能完整設計但又是非核心常用的內容可以被保留下來。

將某些述敘用內容轉為 Json string 放在屬性值中保存,在系統間的溝通完全沒有問題,不再會因為上下游系統想要改屬性名稱或是增減屬性定義就需要每個系統跟著調整,不過在 log 時就不是那麼好閱讀,Json 有一部份的好處就是人眼可以直接看得懂,但物件屬性值如果是 Json string 在 log 輸出時會被重複 serialize,而加上跳脫符號(\)。

How to make sure that string is valid JSON using JSON.NET


Cache 和 Buffer 都是緩存,區別為何?

1、Buffer(緩衝區)是系統兩端處理速度平衡(從長時間尺度上看)時使用的。它的引入是為了減小短期內突發I/O的影響,起到流量整形的作用。比如生產者——消費者問題,他們產生和消耗資源的速度大體接近,加一個buffer可以抵消掉資源剛產生/消耗時的突然變化。

2、Cache(緩存)則是系統兩端處理速度不匹配時的一種折衷策略。因為CPU和memory之間的速度差異越來越大,所以人們充分利用數據的局部性(locality)特徵,通過使用存儲系統分級(memory hierarchy)的策略來減小這種差異帶來的影響。

3、假定以後存儲器訪問變得跟CPU做計算一樣快,cache就可以消失,但是buffer依然存在。比如從網絡上下載東西,瞬時速率可能會有較大變化,但從長期來看卻是穩定的,這樣就能通過引入一個buffer使得OS接收數據的速率更穩定,進一步減少對磁盤的傷害。

4、TLB(Translation Lookaside Buffer,後備緩衝器)名字起錯了,其實它是一個cache。


Buffer 的主要目的是進行流量整形,把突發的大數量較小規模的 I/O 整理成平穩的小數量較大規模的 I/O,以減少響應次數(比如從網上下載電影,你不能下一點點數據就寫一下硬盤,而是積攢一定數量的數據後才一整塊一起寫,不然硬碟都要被玩壞了)

RPC (Remote Procedure Call) 遠程過程調用,遠端程序呼叫

https://www.zhihu.com/question/25536695

https://zh.wikipedia.org/wiki/%E9%81%A0%E7%A8%8B%E9%81%8E%E7%A8%8B%E8%AA%BF%E7%94%A8


RPC, 遠程過程調用直觀說法就是A通過網絡調用B的過程方法。

通信中的協議是你自己規定的,比如你可以規定說當A向B發送數字1, B就打印hello world, 並返回數字1給A, 如果發送數字2,B就打印hello, guy.並發送數字2給A。

這就是一個簡單的RPC示例,實際上natty就是乾這個的,只不過它提供一套框架給你,讓你可以定義自己的規則,實現B裡面的函數。

我們來想一想,當A要把數字1發送給B要怎麼辦呢,你需要用socket,B是server, A是client, B執行完以後再把1通過socket寫回即可。你可以用AUPE書中的例子很容易就構建出來。

問題到這裡,應該就結束了,事實上就是這麼簡單,那為什麼需要RPC框架呢?

當你給B發送1或者2就可以區分函數方法,但是你不可能寫100個函數打印100個字符,你需要在發送1的時候,再接著發送一個字符串,這樣B只要實現一個通用的print函數就夠了。

我們繼續思考,當你想發送一個數字比如65534給B的時候,我們知道socket是按照字節接受數據的,一個字節最大為255也就是0xff, 如果要發送65534你有兩種方法,第一把65534當作5個字符6,5,5,3,4然後讓socket接受5個字符。第二,你可以把65534變成二進制0xfffe, 這樣你可以先發送一個0xff再發送一個0xfe,也就是先發一個255再發一個254再拼裝。

另外在拼裝這255和254的時候,我們知道不同體系結構的CPU字節序是不一樣的,因此,你需要解決大端小端字節序的問題。否則對於一個32位機器上,65534作為一個int型可能會是0xfffe0000,或者0x0000feff,這取決於你如何發送和打包它。

對於相對複雜的RPC, 我們發送的一個數據包往往既包含字符串又包含數字,這樣我們就需要把他們切割開來然後分別解碼編碼。

這個部分就叫做序列化反序列化,在高級一點的RPC框架中,甚至可以做到把一個類從A扔給B.用到的還是這個方法,只是把類這個類型也放進去了。

對於腳本語言比如Lua,你甚至可以把編譯過後的字節碼發給遠程,然後在B用Lua虛擬機執行。

所以對於一個完整的RPC框架底層往往是socket搭配序列化反序列化的工作。

問題到這裡,一個RPC分析應該也結束了, 實際上要想把一個RPC做穩定了,還有幾個問題。

首先,要想讓一個RPC能夠更高效,往往做到讓A可以連續向B發送請求,這就要求在協議解析的時候區分兩個包,在TCP分包的時候這裡有個問題叫做半包和粘包。

另外B也無需在返回完函數1以後再返回函數2,這就要求在返回的時候,A能夠區分開來,這就要求在協議裡面加入session.

高效的寫法不但在編解碼和協議設計理念,還需要在編寫socket server時候,盡可能降低阻塞調用,用異步來做,這有一大推開源方案,比如libev.netty就是一個這樣異步的RPC通信框架。

當然,在實際項目中,我們只是需要解決實際問題,完全沒必要從頭構建,你可以選一個通信協議比如protobuf/JSON/msgpack/thrift等等再找他相關的RPC庫使用即可。





RPC:远程调用。通过RPC框架,使得我们可以像调用本地方法一样地调用远程机器上的方法:

1、本地调用某个函数方法

2、本地机器的RPC框架把这个调用信息封装起来(调用的函数、入参等),序列化(json、xml等)后,通过网络传输发送给远程服务器

3、远程服务器收到调用请求后,远程机器的RPC框架反序列化获得调用信息,并根据调用信息定位到实际要执行的方法,执行完这个方法后,序列化执行结果,通过网络传输把执行结果发送回本地机器

4、本地机器的RPC框架反序列化出执行结果,函数return这个结果

服務調用端 (本地機器)

服務提供端 (遠程機器)

單一 RPC 無法實現 push,即推送服務。理由是,RPC 是client 調用 server獲取數據,是一個完整的過程,實現不了server調用client。解決方案:讓client 既可以調用server上的RPC服務,反之client本身也成為一個RPC服務讓Server來調用。


比如說 Java Netty 是在TCP(Socket)層對nio進行封裝的框架,在RPC框架中可用於解決網絡傳輸問題。

現在流行的微服務框架(dubbo、spring cloud等),實際上就是各種各樣的RPC框架

1. Netty只是網絡通信框架,目的是讓你用最少的代碼構建出足夠支撐網絡通信的功能。

2.完成RPC 需要兩個協議: 對象序列化協議 和 調用控制協議



==>
早期單機時代,一台電腦上運行多個進程,大家各干各的,老死不相往來。假如A進程需要一個畫圖的功能,B進程也需要一個畫圖的功能,程序員就必須為兩個進程都寫一個畫圖的功能。這不是整人麼?於是就出現了IPC(Inter-process communication,單機中運行的進程之間的相互通信)。 OK,現在A既然有了畫圖的功能,B就調用A進程上的畫圖功能好了,程序員終於可以偷下懶了。

到了網絡時代,大家的電腦都連起來了。以前程序只能調用自己電腦上的進程,能不能調用其他機器上的進程呢?於是就程序員就把IPC擴展到網絡上,這就是RPC(遠程過程調用)了。現在不僅單機上的進程可以相互通信,多機器中的進程也可以相互通信了。

要知道實現RPC很麻煩呀,什麼多線程、什麼Socket、什麼I/O,都是讓咱們普通程序員很頭疼的事情。於是就有牛人開發出RPC框架(比如,CORBA、RMI、Web Services、RESTful Web Services等等)。

OK,現在可以定義RPC框架的概念了。簡單點講,RPC框架就是可以讓程序員來調用遠程進程上的代碼一套工具。有了RPC框架,咱程序員就輕鬆很多了,終於可以逃離多線程、Socket、I/O的苦海了。

Netty、Mina是遊戲行業做服務器開發的Java程序員用的比較多的PRC框架。據說互聯網公司用的也比較多。這兩行業都有高並發量的、長連接、分佈式、異步通訊、大數據量等特點。 Netty這種RPC框架封裝和優化了Java NIO和異步網絡編程的一些繁瑣的細節,一方面可以讓開發者專注於業務邏輯的實現,一方面只需要調用Netty封裝的API就可以很快編寫出高性能的服務器。



==>
先说说原理。

本地过程调用
RPC就是要像调用本地的函数一样去调远程函数。在研究RPC前,我们先看看本地调用是怎么调的。假设我们要调用函数Multiply来计算lvalue * rvalue的结果:
1 int Multiply(int l, int r) {
2    int y = l * r;
3    return y;
4 }
5 
6 int lvalue = 10;
7 int rvalue = 20;
8 int l_times_r = Multiply(lvalue, rvalue);
那么在第8行时,我们实际上执行了以下操作:
  1. 将 lvalue 和 rvalue 的值压栈
  2. 进入Multiply函数,取出栈中的值10 和 20,将其赋予 l 和 r
  3. 执行第2行代码,计算 l * r ,并将结果存在 y
  4. 将 y 的值压栈,然后从Multiply返回
  5. 第8行,从栈中取出返回值 200 ,并赋值给 l_times_r
以上5步就是执行本地调用的过程。(20190116注:以上步骤只是为了说明原理。事实上编译器经常会做优化,对于参数和返回值少的情况会直接将其存放在寄存器,而不需要压栈弹栈的过程,甚至都不需要调用call,而直接做inline操作。仅就原理来说,这5步是没有问题的。)

远程过程调用带来的新问题
在远程调用时,我们需要执行的函数体是在远程的机器上的,也就是说,Multiply是在另一个进程中执行的。这就带来了几个新问题:
  1. Call ID映射。我们怎么告诉远程机器我们要调用Multiply,而不是Add或者FooBar呢?在本地调用中,函数体是直接通过函数指针来指定的,我们调用Multiply,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个 {函数 <--> Call ID} 的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查一下这个表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
  2. 序列化和反序列化。客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。
  3. 网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而gRPC干脆就用了HTTP2。Java的Netty也属于这层的东西。
所以,要实现一个RPC框架,其实只需要把以上三点实现了就基本完成了。
Call ID映射可以直接使用函数字符串,也可以使用整数ID。映射表一般就是一个哈希表。
序列化反序列化可以自己写,也可以使用Protobuf或者FlatBuffers之类的。
网络传输库可以自己写socket,或者用asio,ZeroMQ,Netty之类。

最后,有兴趣的可以看一个小而精的RPC库 tinyrpc(hjk41/tinyrpc),对于理解RPC如何工作很有好处。



==>
我们在做一个访问量不大的项目的时候,一台服务器部署上一个应用+数据库也就够了.

那么访问量稍微大一点之后呢,为了解决用户反馈的卡,反应慢的情况,我们就上集群.架设nginx,部署多个服务,由nginx负责把请求转发到其他服务上,这样就解决了用户说的卡慢问题.

过了一段时间之后呢,我们发现数据库已经扛不住了,应用服务完好,数据库有时候宕机. 那这个时候呢,我们就上数据库读写分离,再架设几台数据库服务器,做主从,做分库分表. 然后数据库也不宕机了,服务又恢复了流畅.

又过了一段时间,公司事业增增日上,服务访问量越来越高,且大部分都是查询, 吸取之前宕机且为了办证数据库的健壮性,我们这个时候又加上了缓存, 把用户高频次访问的数据放到缓存里.

后来,项目功能越来越多,整个项目也愈发庞大,修改一个类就需要全盘上传,切换nginx重启,这样的发布流程越来越长,越来越繁杂.然后我们开始把模块拆分,用户信息分个项目,订单系统分一个项目.这样就达到了,用户模块代码修改的时候,只需要更新用户信息服务就好了.但是还是需要切换顶层的nginx.把要重启的服务的流量切到可用服务上. 这个时候我们就想到了RPC

那么RPC解决了什么呢? 所有的服务在启动的时候注册到一个注册机里面,然后顶层处理在接收到nginx的请求时,去注册机找一个可用的服务,并调用接口. 这样子呢,在不加新功能的时候,顶层处理服务我们就不需要动了? 那修改了用户信息项目的时候,我们只需要一个个更新用户信息项目的服务群就好了?

这样的话,无论是扩展还是服务的健壮性都妥妥的了?


==> 你妈妈电脑系统出问题了,你使用qq远程助手,帮她修复系统,这中间,你做的每一步都可以理解为一个rpc调用,本质上就是想操作你本机的代码一样调用远程机器上的代码


編程哲學:Python

用过 Python的人,基本上都知道在交互式解释器中输入 import this 就会显示 Tim Peters 的 The Zen of Python。

The Zen of Python, by Tim Peters


Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


Python之禅 by Tim Peters

优美胜于丑陋(Python 以编写优美的代码为目标)

明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)

简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)

复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)

扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)

间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)

可读性很重要(优美的代码是可读的)

即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)

不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)

当存在多种可能,不要尝试去猜测

而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)

虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )

做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)

如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)

命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)

技術選型

新技術不斷地冒出,這意味著機會並伴隨著風險,如何評估是否採用呢?

Hype Driven Development: https://blog.daftcode.pl/hype-driven-development-3469fc2e9b22

Good practices

So if we can’t rely on what the internet says and opinions of other people, then how to make clever decisions? Here come some good practises:

Test and research before you decide:

Spikes — learn about your technology not from blogs, but from experience. Take 1 or 2 days to build a prototype of a new functionality in the new technology, before you make the decision. Let the team analyse pros and cons. You might take a couple of competitive technologies and let different parts of the team builds prototypes with different technology.

Hackathon is a great way to build awareness of a team on tradeoffs of different technologies. Take 1 or 2 days for the whole team to hack all the technologies that are on the rise and look tempting to use. That will allow the team to make clever decisions on its own and take decisions based on their own experience.

When to go?

In principle when the return on investment is huge. Most technologies are created to solve a particular problem. Do you have that problem? Is it a big problem? Will it save a lot of time? Will the use of the technology pay back the cost of the entrance curve and rewriting? What if we initially slow down development by the factor of two? Or four? Is it still worth it?

Great teams are allowed more — some teams are just faster than others at delivering the value. They get bored with what they do more easily. These teams can introduce new technologies more often. That’s no excuse not to use spikes and do hackathons. On the other hand, if the team has troubles delivering — proceed with caution.

Hire the right people:

Strong technical background is your friend — people who know different paradigms, understand the theory of programming (e.g. algorithms, concurrency) and have good engineering culture tend to hype less.

Experience — hype is stronger with young developers. With years people who have seen many technologies and been in troubles many times tend to get more balanced views of picking technology.

位運算

知乎論壇的相關討論:https://www.zhihu.com/question/34021773
Swift 運算符:http://www.runoob.com/swift/swift-operators.html
C++ 運算符:http://www.runoob.com/cplusplus/cpp-operators.html


有1000個一模一樣的瓶子,其中有999瓶是普通的水,有一瓶是毒藥。任何喝下毒藥的生物都會在一星期之後死亡。現在,你只有10隻小白鼠和一星期的時間,如何檢驗出那個瓶子裡有毒藥?
https://zhuanlan.zhihu.com/p/24375080
解法思維:3線-8線解碼器


在編寫程式碼中使用位運算的場合:

權限管理、聯合表示多個bool值、狀態壓縮、嵌入式系統內用於設置寄存器、用於檢測或設置各種Flag、底層的編程、Hash演算法、加密、IP位址、顏色轉換、狀態位、UTF字符處理等。

不同位上的1代表不同的意義,讓不同的設置值和諧共存,互不干擾。

有些時候讓程式表達更清晰,比如表示2的n次方時。

遊戲開發,設計怪物屬性,一開始很簡單,後來陸續加入了是否是boss,是否主動攻擊,是否抗眩暈,是否抗沉默等屬性。
一般程序員的做法是狂加字段,然而位運算一個字段就搞定了。
用位运算来叠加和筛选各种状态。

涉及硬體编程时,C语言有位域。


知乎論壇回答里面说位运算符有用的有道理,说用位运算符装B的其实也有道理。因为双方都站在不同的立场上看问题。

位运算符一般是用作flag组合,确实有用,感觉也就是位运算符唯一有用的地方,其他方面的应用都有替代性了。

而说位运算符装B也确实有道理,因为用位运算符能提高运行效率,但是增加了可读性的难度和维护的成本。我记得公司摊派了个任务,维护很久以前离职员工用C++写的一个游戏大厅联网的俄罗斯方块。因为策划提出新的需求和需要解决历史遗留下来的BUG,我发现核心代码是一段二维数组和穿插着大量对这个二维数组进行操作的位运算符,包括行方块的消除,行方块的下移等等操作。看懂是没问题,但是耗费了我大量的时间。然后我在这个基础上增加了新功能,比如道具对行方块的上移,方块的投影等等,出现大量的新BUG。然后发email给那个离职程序员看,他说他五年前写的,现在也忘记了没精力去分析解释给我看。我一气之下重写了核心部分,浪费了我好几天时间。我从来不去指责别人写的代码好坏,因为每一段代码的产生都可能背后都有故事,但是我想说用位运算符的同学做人留一线日后好相见。


C艹有bitset,其实就是位运算的封装,不过可读性更佳


位运算在嵌入式系统的编程中,有很广泛的应用。无论是在底层控制IO口的电平,还是在应用层面设置某个状态变量的特定位状态,又或者是在通信接口的软件设计中,都是经常使用的。熟练的运用位运算的技巧,是嵌入式软件工程师的必备技能。


接手的项目要和别的设备通讯,协议是自定义的,比如前两个字节是命令,第三个字节是包序号第四个字节和第五个字节的前四位是设备型号,第五个字节的后四位是设备识别码。取前四位比较容易,直接data[4] / 16就可以,后四位想了好久都没想明白怎么取。就差用if...else判断了。直到我在项目里看到了一句  (data[4] & 0xF0)>> 4




Electron (software framework)

Electron(最初名為 Atom Shell)是 GitHub 開發的一個開源框架。它允許使用Node.js(作為後端)和Chromium(作為前端)完成桌面 GUI 應用程式的開發。Electron 現已被多個開源 Web 應用程式用於前端與後端的開發,著名專案包括 GitHub 的 Atom 和微軟的 Visual Studio Code。

一個基礎的 Electron 包含三個檔案:package.json(後設資料), main.js(代碼)和 index.html(圖形化使用者介面)。框架由 Electron 可執行檔(Windows 中為 electron.exe、macOS 中為 electron.app、Linux 中為 electron)提供。開發者可以自行添加標誌、自訂圖示、重新命名或編輯 Electron 可執行檔。

https://en.wikipedia.org/wiki/Electron_(software_framework)
https://electronjs.org


程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...