Elixir - Ngôn ngữ được viết bằng macros
Macro không những là một trong những viên gạch giúp bạn meta-program với Elixir, mà nó còn là công cụ giúp Elixir meta-program … chính nó nữa.
Như các bạn đã biết, như các bạn chưa biết, như các bạn đã biết mà giả bộ chưa biết, tuần vừa rồi tui đã làm khuynh đảo làng blog nước nhà bằng cách tung chức năng “chém gió” để thay cho Disqus như trước đây, mà không tốn một đồng server nào cả.
Đúng là quảng cáo hơi bỉ ổi vô liêm sỉ chút, nhưng mà tui đã làm điều đó như thế nào?
Tất nhiên như mọi phần mềm trong thế giới Midgard của vũ trụ Marvel, bạn phải đặt ra yêu cầu trước khi tiến hành thiết kế và phát triển, dù cho đó chỉ là một chức năng nhỏ. Làm việc không có mục tiêu thì y như tay không đánh giặc vậy.
Tui đã tự biên, tự diễn ra mục tiêu và đặt ra 3 câu hỏi cho mục tiêu đó: Thay thế chức năng comment bằng Disqus trên blog bằng chức năng tự xây dựng.
Không. Lý do là vì tui thích thế. Bạn muốn tranh luận/khen ngợi/đánh giá thì bạn vui lòng tiết lộ danh tính.
Điều này đòi hỏi người dùng phải đăng nhập, nhờ đó ta có câu hỏi thứ hai.
Không có form đăng ký. Cái tui ghét nhất trên đời này là form đăng ký .
Tui phân vân giữa Facebook và Twitter. Sau khi cân nhắc kĩ lưỡng cuối cùng tui chọn Github. Vì Quần Cam là blog lập trình, nên việc người dùng có tài khoản Github gần như là điều tất nhiên.
Tiêu chí của tui là không tốn tiền server (bạn có thể xem cách tui xây dựng blog qua bài viết Tôi đã tiết kiệm $5 mỗi tháng với Heroku như thế nào?). Nhà nghèo thì ta chơi cách của nhà nghèo.
Vì blog tui chạy trên Heroku, tui không thể sử dụng Postgres hay một DBMS nào (mà không tốn tiền) cả. Heroku Postgres cho miễn phí 10,000 dòng đầu tiên, cơ mà tui nghĩ lỡ sau này tui nổi tiếng, 10,000 dòng là không đủ . Với lại phải lo backup/restore này nọ, phiền phức lắm.
Tui sử dụng Github Gist. Hẳn bạn rất ngạc nhiên vì sao lại là Github Gist đúng không? Đọc tiếp nhé .
Như đã nói ở trên, có hai phần cần được hiện thực cho chức năng “chém gió”: đăng nhập và bình luận.
Flow đăng nhập rất đơn giản theo chuẩn OAuth của Github (như hình).
Người dùng chọn đăng nhập, website redirect họ sang Github và đòi quyền truy cập một số thông tin theo scope
(như email, read/write repo, v.v). Quần Cam không đòi scope gì cả, vì tui chỉ cần định danh, tui lấy các thông tin khác của bạn … để làm gì.
Sau đó server sẽ trao đổi để lấy access token của người dùng từ Github API, và trả token về cho web browser. Vì token không có scope, nó chỉ truy cập được chính những gì public trên tài khoản Github của bạn, nên tui cũng không mã hóa hay mã toán nó làm gì cả.
Web browser nhận được access token và thông tin người dùng (tên và avatar) và tiến hành lưu lại trong localStorage. Lần sau khi website được load, nó sẽ kiểm tra từ localStorage để biết bạn đã đăng nhập chưa.
Thế là xong phần đăng nhập.
Khi bạn chứng thực tài khoản trên website X với OAuth provider Y, thường X sẽ đính kèm các quyền truy cập đọc/ghi trên Y mà họ cần. Việc nhắm mắt bấm “chấp nhận” là rất nguy hiểm, dễ khiến bạn để lọt những thông tin nhạy cảm. Cứ tưởng tượng bạn đi tập gym mà thằng chủ phòng gym đòi truy cập số điện thoại của gấu bạn. Thay vì “chấp nhận”, hãy tán ngay tên đó một bạt tai. Mà nếu nó “đô” quá thì thôi, tha cho nó một lần đi.
Khi bạn bình luận, browser sẽ submit nội dung lên server cùng với access token của bạn.
Server sẽ kiểm tra access token của bạn với Github API. Nếu hợp lệ, nó sẽ lưu comment của bạn vào một ETS table.
ETS (Erlang built-in Term Storage) là một in-memory key-value storage ship cùng với Erlang/OTP. Bạn có thể hiểu nôm na là với Erlang/OTP, bạn được cung cấp sẵn một hệ thống Redis.
Tất nhiên khi một user khác truy cập vào bài viết, comment cũng được đọc ra từ ETS.
ETS còn cho phép bạn cấu hình read concurrency và write concurrency. Ví dụ như tui cấu hình non-concurrent write và concurrent read, cho phép tốc độ truy cập đọc các bình luận nhanh hơn.
Như nói ở trên, comment được lưu trong một in-memory storage, có nghĩa là nếu Heroku hứng lên tắt server, mọi công sức comment của bạn sẽ hoàn toàn lạc trôi. Vì vậy tui phải lưu chúng nó ở một nơi nào đó.
Như giới thiệu, nơi ấy tên là Github Gist. Cứ mỗi 2 phút, một Erlang process sẽ tiến trích xuất và đồng bộ toàn bộ comment lên một file trên Gist. Bạn có thể xem file đó ở đây.
Thao tác đồng bộ này hoàn toàn không ảnh hưởng đến tốc độ truy cập của người dùng. Hệ thống vẫn cho phép họ đọc comment bình thường mà không cần phải lock hay block storage (như tui đã nói ở trên, non-concurrent write và concurrent read).
Chắc bạn cũng đã đoán ra, mỗi lần restart (khi tui viết bài mới chẳng hạn, hay Heroku trở chứng bật tắt dyno), hệ thống sẽ tiến hành đọc file Gist, và import lại toàn bộ comment vào ETS.
Lưu dữ liệu trên Gist còn có một điểm cộng: nó là một Git repository, mọi revision đều được lưu lại. Tức là dữ liệu tự nhiên được backup mà không tốn một đồng cắc bạc nào cả. Cám ơn Github!
Bởi vì tui không tìm thấy lý do nào để giấu cả. Tất cả comment của bạn đều được định danh và đều được hiển thị, trừ một số comment khó nhìn quá thì tui xóa. Cơ mà blog chạy gần 2 năm rồi, chưa có comment (xấu) nào cả.
Như thường lệ, bài viết này không giúp bạn tăng lương, cơ mà tui hy vọng nó có thể:
Như bạn thấy, với Elixir/Erlang xây dựng một robust concurrent system trở nên dễ dàng hơn bao giờ hết. Với một ngôn ngữ khác, có thể tui đã phải tự implement in-memory storage (tốn công) hoặc sử dụng Redis (tốn tiền), hoặc tìm một giải pháp khác.
Bạn có thể xem thêm các bài viết về Elixir với tag #elixir trên blog.
Trời ơi làm ơn comment đi mà.
Nghe có vẻ đao to búa lớn, cơ mà cái tui định nói là cái ai cũng biết: một developer tốt phải hiểu vấn đề và tool của mình.
Có nhiều bạn mới vào nghề hay đặt câu hỏi như “Mình có một vấn đề X, vậy thì mình nên dùng gem/framework Y gì?”. Đó là một câu hỏi vô dụng và là một suy nghĩ lối mòn. Y là một phần mềm do anh/chị/bạn Z viết ra để giải quyết vấn đề λ nào đó của họ. Việc phụ thuộc vào giải pháp ăn liền có thể sẽ khiến bạn sa vào cảnh “ép vấn đề vào khuôn khổ của giải pháp”.
Nôm na như ví dụ thô thiển dưới đây, đi là giải pháp giúp bài trừ chất thải sau khi ăn ra khỏi cơ thể. Bây giờ vì cây của bạn bị héo, bạn bắt bản thân phải ăn thật nhiều để có bón cho cây, nghe hoàn toàn vô lý đúng không?
Trong khi bạn nên tự hỏi bản thân: Giải pháp cho vấn đề X lần lượt là A, B, C gì? Ưu nhược điểm của A, B, C là gì? Với tool Y mà tui đang có, tui sẽ hiện thực chúng lần lượt như thế nào?
Vậy làm sao để hiểu vấn đề và hiểu tool? Chỉ có một cách thôi là học đi đôi với hành. Bạn muốn giỏi toán thì bạn phải đọc thật nhiều công thức và giải thật nhiều bài toán. Bạn muốn giỏi Java thì bạn phải đọc thật nhiều Java documentation và làm thật nhiều Java.
Vkl ông Quần Cam, nói như ông thì tui cũng nói được.
Ờ thì ở đời, nói thì dễ, làm mới khó.
Nếu bạn thắc mắc vì sao không xài Disqus cho nhanh thì tham khảo bài viết này nhé.
Macro không những là một trong những viên gạch giúp bạn meta-program với Elixir, mà nó còn là công cụ giúp Elixir meta-program … chính nó nữa.
Giới thiệu RFC7234 và một số kỹ thuật tăng tốc web với HTTP/1.1 Caching.
Bài viết giới thiệu về IO data, Vectored I/O và tối ưu hóa hệ thống dùng Elixir bằng cách tận dụng Vectored I/O.
Đọc cái 1 thấy giống như đá xoáy blog mình
hay a
hay a
@huytd: trả lời ờ có làm bạn đau lòng không? 😢
kaka
Bài viết hay và assmin có dọng văn dí dỏm quá :satisfied:
broswer
viet sai kia` ong quan cam oi@duykhoa: ờ, cơ mà YOLO đi.
Sao assmin lại sài cái quần màu cam ???
@haconglinh1990 bạn vừa đặt câu hỏi bí mật quốc gia đó.
Test một cái comment thật dài
>>>>>>>>>>>>>>>>
EDITED: Admin đã xóa bớt text vì comment chiếm quá nhiều chỗ.
Ủa vậy bạn lưu gist lại vào đâu để khi heroku resart thì dùng gist để load lại ?
@duongnv1996 Mình lưu comment trên memory. Sau một khoảng thời gian nhất định (như 5 phút) thì mình upload file này lên Github Gist. Khi Heroku restart, mình sẽ load lại từ file gist vào memory.
Ủa lỡ trước 5p server tự dưng restart, là mất comment của mình chăng? 😨
@jinhduong mình (chính xác là Erlang VM) có trap exit signal từ Heroku, khi nhận được tín hiệu, hệ thống sẽ sync lại với Heroku lần cuối.
Nếu việc sync này fail, một con bot chạy bằng cơm sẽ nhập lại comment của bạn vào file gist. 😁
Thấy nó quái quái thế nhỉ? gist github có giới hạn gì không bác?
@huynhduckhoan nó là file, nên file càng to thì càng chậm thôi. Cơ chừng chừng nào to thì mình tính tiếp. Ahihi.
đẹp
texxt
Ko biết có phải bug k 🤔
Thank anh!
Đọc thấy muốn cmt phải dùng github nên gắng tạo cái account để vào spam cho rách cái quần cam =))
Test
bác thiệt đáng eo quá đi :3