โพสต์นี้ตอนแรกทำเป็นภาษาอังกฤษ แต่อยากป้ายยาเพื่อนๆพี่ๆน้องๆชาวไทย เลยนั่งเขียนใหม่
การเป็น Python developer นี่ ต้องมีคนเซ็งกับการจัดการ Package กันบ้างแหละ 😓
หลายครั้งที่…
เราทำงานเป็นระบบระเบียบก็แล้ว
มีการจัดการ virtual environment ก็แล้ว
ทำ Docker image เพื่อ dev/deploy งานเป็น Container ก็แล้ว
ก็ยังอาจจะมีปัญหาอยู่ดี
หรือถ้ามาจากภาษาอื่น ก่อนมาเขียน Python นี่คือจะยิ่งรู้สึกเลยว่า
การใช้ pip
+ virtualenv
หรือแม้กระทั้งใช้ conda
ในการจัดการ Package ใน Python คือสู้ใครไม่ค่อยไหวเลย
เส้าเนอะ 🥹🥹😭
แต่ไม่ได้แปลว่า เราจะต้องเส้าไปตลอดครับ
ผมเลยมาเขียน blog นี้ทิ้งไว้
เพื่อป้ายยาคนอื่นต่อในอนาคต
pipenv สิ
pipenv
เป็นเครื่องมือที่ใช้ในการจัดการ Package
คือมันมีส่วนผมของ pip
+ virtualenv
+ conda
แต่พ่วงมาด้วย 👇👇👇
ลูกเล่นหลากหลาย
การแยกระหว่าง Package ที่ใช้งานจริง กับ Package ที่ใช้ตอน Dev/Test (เหมือนที่ภาษาอื่นมี dependencies กับ dev dependencies) อันนี้ช่วยลดขนาด Docker image ได้ด้วย เพราะตอนจะใช้จริงเราก็เลือกลงแค่ Production
การกำหนด Script ที่ใช้งานบ่อยๆไว้เป็น snippets ให้เรียกใช้ง่ายๆไม่ต้องพิมพ์ยาว
การ Run script โดยอ่านไฟล์ .env ก่อนอัตโนมัติ
การกำหนด Python version ของ Project นั้นๆ
การเลือกลง Package ตาม OS ที่ใช้งาน บางอย่างลงใน linux แต่ไม่ลง windows เผื่อบางทีใครเอาของเราไปใช้ต่อ แต่เค้าไม่ run docker อันนี้ก็ล่วยลดอัตราการแตก 55
การสร้างไฟล์ Lock เพื่อป้องกันการเพี้ยนของ Package version (Lock ถึงระดับ Hash ของ Package นั้นๆเลยครับ) และป้องกันปัญหา Outdate หรือ Compatibility ในอนาคตได้
ข้อดีแบบรวมๆ
ทั้งหมดนี้ ใ ช้ ง า น ง่ า ย ม า ก
ประหยัดเวลากับงานที่ต้องเขียนคำสั่งใน CLI
ลดพื้นที่ที่ต้องใช้ในการ Deploy งานได้จริง
ปลอดภัยกับการ Deploy งานในระยะยาว หรืองานบางอย่างที่คนอื่นดึงไปใช้ร่วมกันกับทีมได้
Blog นี้ก็จะ ป้ายยา ยกตัวอย่างการทำงานให้ดูแบบครบพอสมควร
ในการยกระดับ Workflow ในการทำงานของพวกเราชาว Pythonian
มาเริ่มลองใช้งานกัน
ลองทำแต่ละขั้นตอนตามนี้ดู จะช่วยให้เห็นภาพในสิ่งที่ผมอธิบายไปข้างบนมากขึ้น
1. ติดตั้ง pipenv
ก่อน
ก่อนขั้นตอนนี้คือเราต้องมี pip
ก่อนนะครับ
ถ้ามีแล้ว ก็ติดตั้ง pipenv
ผ่าน CLI ได้เลย 👇
pip install pipenv --user
2. เริ่ม Project
สร้าง Folder ขึ้นมา 1 Folder ครับ แล้วสั่งคำสั่งใน CLI ตามนี้ครับ 👇
pipenv install
ตอนนี้ pipenv
จะทำการสร้าง Pipfile ขึ้นมาใน Folder ของเราครับ
แต่ในไฟล์จะยังไม่มีอะไร
ขั้นตอนนี้ เป็นขั้นตอนที่เราสามารถเลือก Python version ได้ครับ
เปลี่ยนวิธีเขียนเป็น 👇
pipenv --python 3.8
เปลี่ยนเลข version ข้างหลังได้ตามใจเลยครับ
ตัว pipenv
จะทำการสร้าง virtual environment ให้
โดยใช้ Python version ตามที่กำหนดไว้ (แต่ต้องติดตั้ง pyenv ไว้ก่อนนะครับ)
3. ติดตั้งและจัดการ Packages ต่างๆ
Format เหมือนใช้ pip
เลยครับ 👇
pipenv install <package1> [<package2> [...]]
ในที่นี้ผมลองยกตัวอย่างเป็น neo4j ละกัน กำลังเขียนงานอยู่พอดี 👇
pipenv install neo4j
อันนี้ถ้าอยากจะกำหนด Version ของ package ก็สามารถทำได้นะครับ
ทำเหมือน pip
นั่นแหละ เช่น 👇
pipenv install neo4j==5.10.0
ตอนนี้เข้าไปดู Pipfile
จะเห็นว่ามีการเปลี่ยนแปลงแล้วครับ
แล้วจะมี Pipfile.lock
เพิ่มมาด้วย จะเหมือนที่เล่าไว้ด้านบน
ก็คือเก็บ hash แล้วก็ version เอาไว้ในนี้แหละ
ทีนี้ถ้าเราจะลง Package เอาไว้สำหรับตอน dev งานอย่างเดียว ก็ไม่ยากครับ 👇
pipenv install --dev black
เติม --dev
เท่านี้เลย
เวลาเอาไปใช้ที่อื่น หรือเวลาทำ Dockerfile
เราจะใช้คำสั่ง 👇
pipenv sync --categories packages
ตัว pipenv
จะทำการลง package จาก Pipfile.lock
แต่เลือกเฉพาะส่วนที่อยู่ในหัวข้อ [packages]
ใน Pipfile
ครับ
ส่วนถ้าจะให้ sync แบบรวม dev package ด้วย
(เช่น เพื่อทำ Test, Lint เพื่อความมั่นใจอีกครั้งบน CI/CD pipeline)
อันนี้จะมีคำสั่งลัดไม่ต้องพิมพ์ยาวคือ 👇
pipenv sync -d
ตัวอย่าง Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
fastjsonschema = "==2.18.0"
neo4j = "==5.10.0"
orjson = "==3.9.2"
uvloop = {version = "*", markers = "sys_platform == 'linux' or sys_platform == 'darwin'"}
azure-servicebus = "*"
azure-identity = "*"
aiohttp = "*"
sanic = {version = "*", extras = ["ext"]}
numpy = "*"
pandas = "*"
asyncio = "*"
geopy = "*"
[dev-packages]
pre-commit = "==3.3.3"
mypy = "==1.5.0"
black = "*"
isort = "*"
[requires]
python_version = "3.8"
python_full_version = "3.8.4"
[scripts]
type-lint = "mypy --install-types --non-interactive --config mypy.ini ./src"
format-isort = "isort --profile black -q ./src"
format-black = "black ./src -q"
สังเกตตรงท่อน uvloop
, sanic
จะเป็นการกำกับพิเศษครับ
เพื่อบอกว่า uvloop
จะถูกติดตั้งต่อเมื่อไปใช้บน linux
และ sanic
จะติดตั้งเป็น sanic[ext]
แทน
นอกจากนี้
-
[packages]
คือ Package หลัก -
[dev-packages]
คือ Package ใที่ใช้แค่ตอน dev -
[requires]
อันนี้ถ้าเราเลือก Python version หรือตั้งค่าอะไรเพิ่มเติมก็จะมีมาให้ครับ -
[scripts]
นี่คือตัวเด็ดเลยครับ เป็น snippets ที่ผมบอกนั่นแหละ
4. Activate virtual environment
pipenv shell
อันนี้จะช่วยให้เวลาเราเรียกคำสั่งเช่น python -m ... ...
หรือ python xxx.py
ตัว pipenv
จะทำการ load .env
ให้เราเลย
ไม่ต้อง config เพิ่ม
ไม่ต้องติดตั้ง dotenv
แล้วไปเขียน code ให้เรียกอ่าน
ส่วนถ้าจะ Deactivate ก็แค่พิมพ์ใน CLI ว่า 👇
exit
หรือจะให้ load .env
โดยไม่ activate shell ก็ไม่มีปัญหา 👇
pipenv run <command>
เช่น
pipenv run python app.py
ก็ได้เหมือนกันครับ อันนี้ตัว pipenv
จะใช้ virtual environment ที่เราติดตั้งไว้
แล้วก็ load .env
ให้เหมือนกัน แค่ต้องเขียน pipenv run
นำหน้าทุกครั้ง
การสั่ง pipenv shell
ทำให้เราไม่ตั้งเขียน pipenv run
ซ้ำๆในกรณีนี้
5. การเขียน Script ไว้เรียกใช้ซ้ำ
ตามที่ได้เห็นใน Pipfile
ข้างบนไปครับ 👇
[scripts]
type-lint = "mypy --install-types --non-interactive --config mypy.ini ./src"
format-isort = "isort --profile black -q ./src"
format-black = "black ./src -q"
บางคำสั่งมันยาวไปหน่อย มานั่งเขียนซ้ำทุกครั้ง หรือทำไฟล์แยกก็อาจจะไม่สะดวก
บางคำสั่งเราก็ congif กันผ่านการ set Environment
ซึ่งอย่างที่รู้กันว่า pipenv
load .env
ให้เสมอ
เพราะฉะนั้นชีวิตก็ง่ายขึ้นมากฮะ
สำหรับคำสั่ง type-lint
ที่ผมเขียนไปข้างบน
ทั้งหมดที่ผมต้องทำในครั้งถัดไปเหลือแค่นี้ 👇
pipenv run type-lint
สวยงามมมม
ทีนี้เราก็จะพูดได้ว่า
ส่งท้าย
ไม่รู้ว่าเขียนได้เห็นภาพ หรือทำให้คนอ่านเข้าใจได้มากน้อยแค่ไหนครับ
แต่ผมลองใช้หลายอย่างนะ ก่อนจะมาเจอ pipenv
ก็ใช้ poetry
ซึ่งก็ไม่ได้แย่นะครับ poetry
ใช้จัดการกับ project
ที่สร้างขึ้นเพื่อเป็น python package เลย
แต่ถ้าจะตอบโจทย์งาน dev/deploy ผมว่าตัวนี้แหละ
ไว้ผมหาเวลาได้ อยากเขียนเรื่อง pre-commit
อันนี้หลายคนที่ผมเคยคุยด้วยยังไม่เคยใช้เหมือนกัน
ก่อนจะ commit อะไร
เราสามารถเอาขั้นตอนที่เราต้องทำซ้ำๆ มา automate ได้
เช่น
format code ให้สวย
ตรวจ bug ตรวจ types ทำ test
ช่วยให้ชีวิตดีขึ้นในหลายด้านอยู่เหมือนกันครับ
เรียนรู้การใช้งานอื่นๆของ pipenv
มีอะไรเด็ดๆอีกเยอะอยู่นะครับ ลองไปตำกัน