吾生也有涯,而知也無涯。以有涯隨無涯,殆已!已而為知者,殆而已矣!
1994年4月20日,中國第一根64K國際專線接入國際互聯(lián)網(wǎng),說“想要世界的寶藏么?如果想要的話,那就去網(wǎng)上找吧,我把所有的一切都放在那里。”于是,水木清華、搜狐、網(wǎng)易,等等、等等,掀起了中國互聯(lián)網(wǎng)的熱潮,大互聯(lián)網(wǎng)時代就此展開。
我的上一篇文章How to build?寫于三月之前,介紹如何零基礎(chǔ)開始學(xué)習(xí)PYTHON,那時候我入職兩月,現(xiàn)在還差一月轉(zhuǎn)為正式員工,值此機會,從技術(shù)角度剖析一下助理PYTHON工程師的工作,也讓這篇文章作為入門者的技術(shù)指南,如果你能在每一項技術(shù)能力前面打勾,你一定是一名成熟的python web工程師!
工作范疇
- 具備將產(chǎn)品經(jīng)理的產(chǎn)品理念快速、有效的轉(zhuǎn)化為產(chǎn)品價值的全部技術(shù)能力
- 對于產(chǎn)品的生命周期有一定認(rèn)識,并能夠因此來控制自己代碼的復(fù)雜性
- 有開放式工作環(huán)境的素質(zhì)意識,具備持續(xù)“學(xué)習(xí)”的學(xué)習(xí)能力
工作1:技術(shù)能力
1.1 基本能力
軟件工程,是個很有意思的名字。十八世紀(jì),歐洲創(chuàng)造了“工程”一次,本來含義是有關(guān)兵器制造、具有軍事目的的各項勞作,后擴展到許多領(lǐng)域,如建筑屋宇、制造機器、架橋修路等。軟件·工程并無二致,甚至不需要車床吊車等物理硬件,只要會想(敢于類比與聯(lián)想,讀史使人明智)、會寫(運用編輯器輸入代碼,vim是不錯的選擇)、會問(靈活的使用Google,科學(xué)上網(wǎng))、會生活(與同事搞好關(guān)系,辦公室至少9小時呢)。
當(dāng)一個程序員,不僅僅是實現(xiàn)功能代碼,還要有一點美感,就像建房子。如果封裝不優(yōu)雅,房子外表很難看;如果接口不優(yōu)雅,房門都很難進;如果抽象層不優(yōu)雅,房子根本沒法裝修。有一點對“美感”的追求,對工程的敬畏之心,就像電鋸驚魂中的工程工具(殺人的美學(xué)),會讓我們的工作事半功倍。
1.2 運維能力
說到運維,就是一種管理的能力,管理計算機系統(tǒng),管理數(shù)據(jù)庫,管理應(yīng)用配置,讓一切都流程化、標(biāo)準(zhǔn)化并自動化。
- 計算系統(tǒng)?;趉ubernetes寫dockerfile,基于成熟的docker系統(tǒng)創(chuàng)建、銷毀容器。DOCKER讓系統(tǒng)自動化
任何系統(tǒng)問題都能用“重啟”的方式解決,如果不行,那就重啟兩次。云是大勢,所以只要我們能弄出最基本的系統(tǒng)image,比如macOS、阿里云,那么作為程序員的我們就能夠一展身手。
當(dāng)然,理解操作系統(tǒng)是很有必要的,不要浪費或過度使用機器性能,注重sql語句的優(yōu)化,進程的使用 - 數(shù)據(jù)庫。DBA讓數(shù)據(jù)庫自動化
- 應(yīng)用配置。CMDB讓應(yīng)用自動化
- 生產(chǎn)環(huán)境。我們要學(xué)會利用以上,必要時候開發(fā)以上,學(xué)會起docker,學(xué)會和DBA溝通,學(xué)會起CMDB,以及學(xué)會管理自己的生產(chǎn)環(huán)境!
- 基本cmd命令,比如yum,mkdir,touch,cd,rm,>,grep,ps,top,w,nohup,set,crontab等等;
- 基本編輯器vim,會配置使用vim(用vundle來管理插件),或者基本ide atom;
- 基本解釋器,python環(huán)境管理pipenv,
pipenv install,pipenv shell; - 基本代碼管理git,pull,push,checkout,rebase
- 基本數(shù)據(jù)庫管理,mongo,mysql, els的啟用,migrate,export,import
- 基本業(yè)務(wù)管理,能夠預(yù)估開發(fā)feature的時間,能夠管理開發(fā)的輕重緩急,能夠?qū)I(yè)務(wù)細(xì)節(jié)反復(fù)推敲
- 基本個人管理,能夠健康,能夠“有愛”
就個人或小組開發(fā)而言,掌握以上應(yīng)該能讓你非常舒服地做一個開發(fā)工程師,所謂工欲善其事,必先利其器。
1.3 PYTHON能力
說到PYTHON,很多人都會寫,語言很簡單,但工程師之間工資又各有不同,這是為什么呢?為了回答這個問題,不妨上拉勾網(wǎng)搜索了一下“金主”們對工程師的要求。
搜索詞為'python',篩選為工資‘25k-50k’以及‘50k以上’,我隨機選取了第一頁的兩個公司


可是看出,對于‘初級玩家’公司主要看你“會不會”,也就是0和1的區(qū)別;而對于‘中級玩家’公司主要看中你“會不會分析,能不能優(yōu)化”,也就是1和10的區(qū)別;至于‘高級玩家’,我想只會PYTHON是不行的。那么我的這篇文章,一方面總結(jié)一下我半年的學(xué)習(xí)成果,希望能夠把知識從0到1真正落到實處,便于以后從1到10不斷進步;另一方面,借著分享交流的互聯(lián)網(wǎng),希望各位同行能夠指出我工作學(xué)習(xí)中的短板,幫助我不斷改進。
1.3.1 Clean Code
我在上篇文章中推薦在HackerRank做完全部python習(xí)題,并且在LeetCode上繼續(xù)訓(xùn)練。不斷刷題能極大的增強我們寫單個函數(shù)、算法的能力,訓(xùn)練我們的思維能力,但對我們寫"工程項目"卻鮮有幫助。因為每一題的context都不一樣,容易養(yǎng)成重復(fù)造輪子、代碼不整潔的壞習(xí)慣,在我入職的第一個月,因為壞習(xí)慣被反復(fù)批評,之后我仔細(xì)讀了《Clean Code》一書,情況有所好轉(zhuǎn)。所以,請務(wù)必注意代碼的測試、抽象層、命名規(guī)范、參數(shù)、Exception等。
訓(xùn)練方法:《Clean Code》,要有好代碼的smell
訓(xùn)練成果:厲害的程序員寫出機器能讀懂的代碼,好的程序員寫出人能讀懂的代碼。
# 保齡球積分,從第0輪到第10輪,已知每一輪的擊倒情況,求總分
def score_frame(frame=10):
score = 0
ordinal_ball = 0
for current_frame in range(frame):
if is_strike(ordinal_ball):
score += 10 + next_two_balls_for_strike()
ordinal_ball += 1
elif is_spare(ordinal_ball):
score += 10 + next_ball_for_spare()
ordinal_ball += 2
else:
score += two_balls_in_frame()
ordinal_ball += 2
return score

1.3.2 Flask
整潔代碼是基礎(chǔ)中的基礎(chǔ),接下來掌握的是web框架。要想熟練使用Flask,知識上要求對網(wǎng)絡(luò)會話層、表示層和應(yīng)用層有了解,從Client端輸入URI并發(fā)送請求的一瞬間,網(wǎng)絡(luò)通過自上而下的OSI結(jié)構(gòu),傳輸層(TCP)--- 網(wǎng)絡(luò)層(IP) --- 數(shù)據(jù)鏈路層 --- 物理層, 路由(識別IP),然后,Server端與之建立TCP連接,拿到request對象,梳理業(yè)務(wù)邏輯,返回response對象,經(jīng)過同樣的一系列過程到Client端接受數(shù)據(jù)(如果是瀏覽器則會渲染頁面)。這背后所有的事情,就是一個web工程師的工作所在。
訓(xùn)練方法:《Flask Web開發(fā),基于python的web開發(fā)實戰(zhàn)》,上篇文章已經(jīng)推薦過了
訓(xùn)練成果:能夠獨立編寫并部署一個滿足業(yè)務(wù)需求的web應(yīng)用

from flask import Flask, request, jsonify
from models import get_question_analysis
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():
return 'hello world'
@app.route('/api', methods=['POST'])
def api():
data = request.get_json()
question = data['question']
question_analysis = get_question_analysis(question)
return jsonify(question_analysis)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)
1.3.3 AioHttp
一步通,則步步通,能夠?qū)W會一個框架,其他的框架就不難了。Flask的底層是werkzeuk,基于CGI(通用網(wǎng)關(guān)接口,Common Gateway Interface)的WSGI在業(yè)務(wù)受到了異步的挑戰(zhàn),ASGI應(yīng)運而生。AioHttp的框架,支持python asycio,能極大的提高API的性能(與flask框架下API性能的差異,請移步我的測試文章)。
訓(xùn)練方法:AioHttp Git,Asyncio Doc,永遠(yuǎn)不要忘記源碼和doc
訓(xùn)練成果:能夠獨立編寫并部署一個滿足業(yè)務(wù)需求的web應(yīng)用,理解并掌握python的異步語法
from aiohttp import web
from models import get_question_analysis
async def index(request):
return web.Response(text='Hello World')
async def api(request):
data = await request.json()
question = data['question']
question_analysis = await get_question_analysis(question)
return web.json_response(question_analysis)
app = web.Application()
app.add_routes([web.get('/', index),
web.post('/api', api)])
if __name__ == '__main__':
web.run_app(app, host='0.0.0.0', port=5000)
Parallelism introduces new challenges in writing correct code, particularly in the presence of shared, mutable state.
1.3.4 MONGO
對于一個助理工程師,不懂框架,你也能形成生產(chǎn)力,可以做一個寫數(shù)據(jù)庫增刪改查的cool boy。如果一個工程師不會操作數(shù)據(jù)庫,那就連“刪庫跑路”的“黑暗森林威懾”都建立不起來...所以無論怎樣,這個得會。我們有兩種操作mongodb的方式,一種是ODM(Object-Document Mapper),如mongoengine;另一種則是超有名的pymongo。
訓(xùn)練方法:MongoEngine文檔,PyMongo文檔
訓(xùn)練成果:熟練對mongo表進行增刪改查,能夠?qū)ongo表查詢進行一定程度的優(yōu)化
# 更改user_info這張表中的user_id為‘test’的年齡為22
# mongoengine
from mongoengine import Document, connect
from config import MONGO_URI
connect(host=MONGO_URI, alias='default')
class UserInfo(Document):
user_id = StringField(required=True)
age = IntField()
UserInfo.objects.get(user_id='test').update(age=22)
# pymongo
from config import MONGO_URI, DB
from pymongo import MongoClient
client = MongoClient(MONGO_URI)
collection = client[DB]['user_info']
collection.update({'user_id': 'test'}, {'age': 22})
簡單分析一下二者的優(yōu)缺點:
- mongoengine允許我們定義一套模式,然后把所有的值都匹配到我們定義的schema上,這種schema更加清楚和明確,個人感覺比字典更容易操作,用dot notation更像OOP,而pymong返回的是一個dict,操作時困難的多,很多時候有點丑
- mongoengine相當(dāng)于在你和pymongo之間加了map層,所以會對性能有微乎其微的影響,在進行很簡單的查詢時顯得有些沒有必要
1.3.5 MYSQL
noSQL和SQL的取舍總是要不斷斟酌。操作mysql我們也有兩種方式,ORM的sqlalchemy,以及pymysql
訓(xùn)練方法:SqlAlchemy文檔,PyMySql文檔
訓(xùn)練成果:熟練對mysql表進行增刪改查,能夠?qū)ysql表查詢進行一定程度的優(yōu)化
# 向user_info這張表中存入一條姓名為‘test’,年齡為22的數(shù)據(jù)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from config import MYSQL_URI
Base = declarative_base()
engine = create_engine(MYSQL_URI, echo=False)
Session = sessionmaker(bind=engine)
session = Session()
class UserInfo(Base):
__tablename__ = 'user_info'
user_id = Column(String(80), nullable=False)
age = Column(Integer(), nullable=True)
session.add(UserInfo('test', 22))
session.commit()
ORM的用途非常非常廣,使用起來很優(yōu)雅,但如同flask框架一般,深入探究它的使用方法和場景需要大量的篇幅,會在以后的文章中繼續(xù)分享,希望感興趣的同學(xué)自行探索,也可以在評論區(qū)有更多交流。
1.3.6 Abstraction
Computer programs consist of instructions to either: Compute some value Or Carry out some action
有了框架和數(shù)據(jù)庫,剩下的就是“操作”了,也就是業(yè)務(wù)邏輯的編寫。如果使用命令式編程,實現(xiàn)業(yè)務(wù)不是一件困難的事情,那么代碼的區(qū)別就彰顯了工程師們的抽象水平。百多行的函數(shù);沒有層次感的代碼;命名不規(guī)范的代碼;概率編程;google編程,等等,不一而足。優(yōu)秀的工程師,對抽象一定有自己的理解!
訓(xùn)練方法:多想,多看
訓(xùn)練成果:至少能夠從“只看到了”函數(shù),到“看到了”項目,從細(xì)節(jié)到系統(tǒng)
# 表示有理數(shù),并計算其平方
# 表示方法
def rational(n, d):
return [n, d]
def numerator(x):
return x[0]
def denominator(x):
return x[1]
# 操作方法
def square_rational(x):
return mul_rational(x, x)
def square_rational_violation_once(x):
return rational(numerator(x) * numerator(x), denominator(x) * denominator(x))
def square_rational_violation_twice(x):
return [x[0] * x[0], x[1] * x[1]]
# 表示方法 2
def rational(n, d):
def get(index):
if index == 0:
return n
elif index == 1:
return d
return get
def numerator(x):
return x(0)
def denominator(x):
return x(1)

用了一個簡單的例子來解釋表示層和操作層(完全不一樣的表示層,但是操作層卻完全一樣),龐大的系統(tǒng)必然存在著細(xì)小的抽象。我們只要能夠掌握抽象的方法,再配合leetcode中的算法知識,那么所有的業(yè)務(wù)邏輯必然迎刃而解。
1.3.7 lib/site-packages
框架 -> 數(shù)據(jù)庫 -> 抽象,我把技術(shù)內(nèi)容分成了這三塊,那其實還有一些邊角料。python為人稱道的就是大量好用的包,所以python工程師經(jīng)常被說成調(diào)包的。在工作中當(dāng)然也會直接調(diào)包,比如smtp和beautifulsoup,這兩個太常見了。
import requests
from bs4 import BeautifulSoup
url_head = 'http://www.itdecent.cn/u/1f167239855b'
HTML = requests.get(url_head).text
soup = BeautifulSoup(HTML, 'lxml')
soup.find_all()
1.3.8 widgets
最后的最后,在項目開發(fā)的過程中,一定會和公司業(yè)務(wù)有聯(lián)系,也一定會發(fā)生很多bug,更會有一些奇奇怪怪的需求。為了應(yīng)對各種各樣的事情,python工程師集成了大量好用的工具,比如elastic-search,sentry,kafka, memcache等等,這種Client/Server的構(gòu)架很好用,也是微服務(wù)的雛形。

1.3.9 behave && selenium
OK,做完所有工作,臨近上線,我的PM一定會在旁邊大喊三聲:測試!測試!測試!自動化測試是所有穩(wěn)定系統(tǒng)的標(biāo)配,unittests和doc tests不必多提,這里介紹一種BDD工具,behave和selenium。
功能: 自動測試
場景: 頁面點擊
假如 我在登陸頁面
當(dāng) 輸入賬號、密碼并點擊登陸
那么 我在個人主頁
from behave import given, when, then
from selenium import webdiver
driver = webdrivear.Chrome(driver_path, chrome_options=chrome_options)
@given('我在登陸頁面')
def login_in(context):
driver.get(login_url)
assert is_at_page(LOGIN_PAGE)
@when('輸入賬號、密碼并點擊登陸')
def send_key(context):
driver.find_element_by_id(ACCOUNT).send_keys(KEYS)
dirver.find_element_by_id(CONFIRM).click()
@then('我在個人主頁')
assert is_at_page(HOME_PAGE)
如果你覺得測試沒有必要,那你一定沒有寫過測試!
1.3.10 CI && CD
OK,順利通過測試,合并到master,此時應(yīng)該有一套能夠自動集成、自動部署的機制,用python起一個監(jiān)控master分支的服務(wù),一出現(xiàn)合并操作,就使用ssh協(xié)議重啟原服務(wù)。
至此,整套python web開發(fā)后端流程的技術(shù)要點都清晰了,希望以后能夠繼續(xù)成長、分享,也希望閱讀到這里的伙伴多多交流、給予指導(dǎo)。
1.4 前端能力
互聯(lián)網(wǎng)行業(yè)注重T型人才的培養(yǎng),所謂的T型人才就是橫向了解,縱向發(fā)展,所以web開發(fā)往往看重全棧的能力。
- HTML。標(biāo)記性語言,就用jinja模版吧。
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
CSS。樣式語言,就用bootstrap吧。
{% extends 'bootstrap/base.html %}JS。動態(tài)交互,就用ajax吧。
$("#botton").on("click",function(){
$.ajax({
url: 'http://www.baidu.com',
type: 'GET',
success: function(data){
};
})
})
如果你不滿足于如此簡單的前端知識,也可以主動將vue框架融合到我們的頁面中。前端語言還是有很多奇技淫巧,好看的頁面比后端開發(fā)更容易獲得成就感。
1.5 數(shù)據(jù)能力

但凡python工程師,大都會一點數(shù)據(jù)分析。那我感覺呢,有數(shù)據(jù)比沒數(shù)據(jù)強,用數(shù)據(jù)驅(qū)動的PM比只有PM驅(qū)動靠譜。
- 數(shù)據(jù)提取。
- 從雜亂的打點數(shù)據(jù)中,用技術(shù)取出結(jié)構(gòu)化的數(shù)據(jù)
- 數(shù)據(jù)分析和挖掘。
- 可以用random forest分析feature
- 可以用OLS直接預(yù)測模型
- 還有一些教育上的模型如BKT,IRT
- 數(shù)據(jù)驅(qū)動。
- 可視化模型結(jié)果,并寫分析報告
- 數(shù)據(jù)理解
- 以上所有技術(shù)都可以很快學(xué)會,無外乎調(diào)包調(diào)參,但理解和分析才是重點
- 在不能獨立、全方面分析問題時,建議先養(yǎng)成科學(xué)的思維習(xí)慣(不要連貝葉斯都沒搞明白就妄圖進軍數(shù)據(jù)分析...)
工作2:架構(gòu)能力
我經(jīng)驗較少,這部分的理解還需要不斷加強,所言也不過拾人牙慧,暫且一放(代碼的經(jīng)驗、不一樣的設(shè)計模式、業(yè)務(wù)生命周期的理解能力)
工作3:學(xué)習(xí)能力
- Junior Programmer,想從碼農(nóng)成長為工程師,要進步!
- 工作中有很多可以學(xué)習(xí)的點,優(yōu)化一段代碼、發(fā)布一個發(fā)送郵件的package、上coursera課程,要學(xué)習(xí)!
- 學(xué)習(xí)和工作是很辛苦的,寫了一天代碼頭昏腦脹,還要再看兩個小時英文文檔,要勇敢!
終于在周一發(fā)版了,本來告訴自己每周日要發(fā)布一篇文章的,最近熬夜看TI,時間和精力完全跟不上。算是全面總結(jié)了工作中的一些事情吧,比較基礎(chǔ),深入鉆研也有些東西,嗯,共勉,加油!