ORM có còn là một anti-pattern không?
(github.com/getlago)- ORM thường bị chỉ trích là “đồ chơi cho startup”, nhưng vấn đề thực sự nằm ở cách sử dụng sai hơn là bản thân ORM
- Đồ thị đối tượng và bảng quan hệ là hai mô hình khác nhau nên sẽ phát sinh sự không tương thích mô hình, nhưng chỉ riêng điều này khó có thể xem ORM là anti-pattern
- Tranh luận về việc vi phạm SRP và SOC là có cơ sở, nhưng ORM vốn là một lớp trừu tượng để kết nối hai mô hình dữ liệu, nên khó đánh giá chỉ dựa trên việc có vi phạm nguyên tắc hay không
- Vấn đề hiệu năng thường phát sinh từ pattern kết hợp dữ liệu bằng logic của ngôn ngữ host hơn là từ ORM, và có thể giảm bớt bằng các tính năng giống SQL của ORM
- Lý do cốt lõi khiến Lago chuyển các truy vấn Active Record sang SQL thô không phải là tốc độ mà là khả năng quan sát và debug; với các truy vấn lớn, chuyển sang SQL thô có thể có lợi trong thực tế
Quan điểm cơ bản khi nhìn nhận các chỉ trích về ORM
- ORM thường bị công kích là “anti-pattern”, nhưng kết luận rằng bản thân ORM là xấu thì khá phóng đại
- Cũng như các lớp trừu tượng khác, ORM không hoàn hảo và có thể gây ra một số mất mát về khả năng quan sát cùng chi phí hiệu năng
- Lago đã gặp vấn đề khi phụ thuộc vào Active Record, ORM của Ruby on Rails, và từ đó xem xét lại cách phụ thuộc vào ORM
- Kết luận nghiêng về việc nên xem ORM là một lớp trừu tượng có ưu và nhược điểm rõ ràng, chứ không phải là phải loại bỏ ORM
Khác biệt giữa mô hình đối tượng và cơ sở dữ liệu quan hệ
- Các đối tượng mà ORM xử lý gần với đồ thị có hướng, trong đó các nút trỏ đến nút khác
- Bảng trong cơ sở dữ liệu quan hệ gần với đồ thị vô hướng, trong đó dữ liệu được liên kết hai chiều thông qua khóa chung
- ORM có thể mô phỏng đồ thị vô hướng, nhưng cấu hình và hành vi không phải lúc nào cũng đơn giản
- Đối tượng
Usercó thể thiếu mảngPosts - Các thực thể trong mảng
Postscó thể không có tham chiếu ngược về cùng đối tượngUser - Ngay cả khi có tham chiếu ngược, đó có thể là một đối tượng được sao chép chứ không phải cùng một đối tượng
- Đối tượng
- Ví dụ, ORM có thể trả về các bài viết của người dùng dưới dạng mảng, nhưng không đưa vào từng bài viết tham chiếu ngược đến người dùng trong vai trò tác giả
- Sự không tương thích này là một phê bình mang tính học thuật hợp lý đối với ORM, nhưng trong vận hành thực tế, vấn đề lớn hơn thường bộc lộ ở cách sử dụng cụ thể
Tranh luận về SRP và SOC
-
Nguyên tắc đơn trách nhiệm (SRP)
- ORM bị chỉ trích là vi phạm nguyên tắc đơn trách nhiệm (SRP)
- Vì nó có thể khiến một lớp hoặc một tầng đảm nhận nhiều vai trò cùng lúc
- Thực hiện cơ sở dữ liệu và transaction
- Biểu diễn record
- Định nghĩa quan hệ
- Tạo và chạy migration
- Tuy nhiên, mục đích của ORM vốn là kết nối hai mô hình dữ liệu khác nhau, nên khó phủ nhận ORM chỉ vì một số vi phạm nguyên tắc
-
Tách biệt mối quan tâm (SOC)
- ORM cũng có thể làm mờ nguyên tắc tách biệt mối quan tâm (SOC)
- SOC là nguyên tắc cho rằng một thành phần hạ tầng chỉ nên có một mối quan tâm
- Vì ORM chuyển việc quản lý cơ sở dữ liệu sang phía backend, nên có thể xem là có khả năng vi phạm SOC
- Tuy vậy, ngày nay các thành phần hạ tầng và pattern lập trình cũng thường kết hợp nhiều vai trò vì hiệu năng, độ trễ và tổ chức code
- Bộ tổng hợp CPU trong cơ sở dữ liệu OLAP
- Backend-frontend ở edge
- Monorepo
Vấn đề hiệu năng thường đến từ cách sử dụng hơn là từ ORM
- Chỉ trích rằng ORM luôn kém hiệu quả phần lớn là sai
- Nhiều ORM có thể hoạt động hiệu quả hơn rất nhiều so với suy nghĩ của lập trình viên
- Vấn đề là ORM khiến việc kết hợp dữ liệu bằng logic của ngôn ngữ host như JavaScript hay Ruby trở nên dễ dàng
- Trong ví dụ TypeORM, pattern xấu là truy vấn trước các tác giả thuộc một công ty nhất định, rồi truy vấn lại bài viết của từng tác giả, sau đó lưu riêng từng bài viết
- Cách tốt hơn là dùng
createQueryBuilder()của TypeORM để xây dựng một truy vấn cập nhật duy nhất - Trong lần refactor SQL tính phí của Lago, cũng không có khác biệt hiệu năng giữa phiên bản Active Record và SQL thô
- Vì đã sử dụng nhiều tính năng kết hợp dữ liệu của Active Record, nên truy vấn cũ vốn đã ở trạng thái được tối ưu
- Việc viết lại bằng SQL thô nghiêng về mục tiêu đảm bảo khả năng quan sát hơn là cải thiện hiệu năng
Khi ORM thực sự có thể trở nên chậm
- ORM không phải lúc nào cũng hiệu quả như SQL thô, và trong một số tình huống có thể khá kém hiệu quả
- Vấn đề đầu tiên là ORM có thể tạo ra overhead tính toán lớn khi chuyển đổi kết quả truy vấn thành đối tượng
- TypeORM được nhắc đến như một ví dụ cho vấn đề này
- Vấn đề thứ hai là khi duyệt quan hệ một-nhiều hoặc nhiều-nhiều và gửi nhiều lượt request khứ hồi tới cơ sở dữ liệu
- Pattern này được gọi là vấn đề N+1
- Thêm N truy vấn con vào 1 truy vấn ban đầu
- Trong ví dụ Prisma, khi truy vấn lồng nhau người dùng, bài viết và bình luận, mỗi bình luận có thể phát sinh một request cơ sở dữ liệu mới
- N+1 thường xuất hiện trong ORM, nhưng nếu dùng data loader thì có thể gộp N+1 truy vấn thành 2 truy vấn
- Phần lớn các vấn đề phổ biến của ORM có thể tránh được nếu tận dụng đầy đủ các tính năng của ORM
Vấn đề lớn hơn là khả năng quan sát và debug
- Điểm yếu lớn nhất của ORM là khả năng quan sát
- Vì ORM về bản chất là trình xây dựng truy vấn, nên ngoài các trường hợp như lỗi kiểu dữ liệu thô rõ ràng, nó không phải là bên truyền lỗi cuối cùng
- Khi SQL trả về lỗi, ORM phải diễn giải lỗi đó rồi truyền lại cho người dùng
- Active Record gặp khó ở điểm này, và đây cũng là lý do Lago refactor truy vấn đăng ký tính phí
- Khi kết quả khác với kỳ vọng, phải lặp lại quy trình sau
- Kiểm tra truy vấn SQL đã được render
- Chạy lại SQL đó
- Chuyển lỗi SQL trở lại thành thay đổi trong Active Record
- Quy trình qua lại như vậy làm suy yếu mục đích ban đầu của việc dùng Active Record để tránh phải tương tác trực tiếp với cơ sở dữ liệu SQL
Đánh giá thực tiễn
- Nếu dùng đúng cách, ORM có thể đạt hiệu quả gần với SQL thô
- Nhiều vấn đề phát sinh khi không dùng các tính năng giống SQL của ORM mà phụ thuộc quá nhiều vào cấu trúc logic của ngôn ngữ host
- Nếu các truy vấn lớn gây khó cho lập trình viên và cản trở việc debug, chuyển sang truy vấn SQL thô có thể là một khoản đầu tư đáng giá
- Hầu hết ORM đều cung cấp chức năng chạy truy vấn SQL bên trong ORM
1 bình luận
Ý kiến trên Hacker News
Tôi đã dùng ORM từ khi Hibernate vừa mới xuất hiện trên Java, nhưng lúc nào cũng thấy nó dở
Cái lợi ích kiểu “có thể đổi sang cơ sở dữ liệu khác” giờ nhìn lại gần như là điều nhảm nhí, và trên thực tế chẳng ai dùng như vậy cả
Nói rằng “không cần biết SQL” cũng sai, và với những ứng dụng không tầm thường sống lâu thì cuối cùng vẫn phải chỉnh từng truy vấn ở mức chuỗi
Tôi cho rằng tầng dữ liệu nên được làm theo kiểu tạo và nội suy từng truy vấn bằng SQL dạng chuỗi, và càng gần với raw JDBC thì càng tốt
Lập luận rằng ORM hỗ trợ “mô hình miền” cũng là một lý do tệ, vì mô hình miền đó rốt cuộc lúc nào cũng trở thành mô hình miền nghèo nàn với logic trống rỗng
Nghĩ đến khoảng thời gian bị lãng phí vào ORM, XML, annotation và việc debug SQL được sinh ra là chỉ muốn khóc
Phần dễ vốn đã dễ rồi nên tôi không mấy quan tâm, mà ngược lại đã có rất nhiều lần công việc khó hơn gấp triệu lần vì phải chiến đấu với chính ORM vào đúng khoảnh khắc tệ nhất, khi truy vấn đổ vỡ vì quy mô
Query builder không hoàn toàn giống ORM, nhưng tôi thích bài https://gajus.medium.com/stop-using-knex-js-and-earn-30-bf41... và trở thành fan của những công nghệ kiểu Slonik
Nó cung cấp 90% những gì tôi muốn, như tự động bind kết quả vào object và kiểm tra kiểu mạnh, nhưng vẫn cho phép chỉ đơn giản viết SQL bình thường
Tôi cũng không hiểu nổi suy nghĩ cho rằng SQL là một ngôn ngữ thần bí khó nhằn. Nó cũ kỹ nên có khuyết điểm, nhưng học SQL vẫn tốt hơn là học ngôn ngữ truy vấn riêng do công cụ ORM tạo ra
Hồi đó nếu nói ra những lời chỉ trích kiểu này thì các lập trình viên khác thường nhìn mình bằng nửa con mắt
Đến giờ vẫn có rất nhiều công cụ và kỹ thuật mà với tư cách lập trình viên tôi buộc phải dùng dù chúng là phản mẫu, và thực tế đáng buồn của ngành là không ít công cụ được dùng rộng rãi lại dở và còn khuyến khích phản mẫu
Trong ngành công nghệ có một số ít lập trình viên và cựu lập trình viên có quan hệ rộng nắm quyền quyết định, và tôi cảm thấy họ cũng không ra gì
Cũng có những ORM có tỷ lệ ưu và nhược điểm khá ổn, đặc biệt là phía Python
Django ORM thì thô kệch và hiệu năng không tốt, nhưng được tích hợp tốt, thực dụng, năng suất và cảm giác dùng cũng ổn
Peewee cung cấp ORM trong một gói nhỏ, nên khi không cần gì ghê gớm và chỉ muốn đỡ phiền thì nó giúp viết các chương trình nhỏ một cách vui vẻ
SQLAlchemy đòi hỏi đầu tư nhiều hơn nhưng rất linh hoạt, sinh ra SQL sạch sẽ và hoạt động chính xác
Nó cũng lộ ra các query builder cấp thấp hơn dành cho khi bạn không muốn mô hình hướng đối tượng mà muốn biểu đạt hành vi SQL mang tính thành ngữ dưới dạng trừu tượng bằng Python
Cuối cùng thì đây vẫn là một quyết định kỹ thuật thông thường dựa trên lợi tức trên đầu tư
Tôi đã làm việc này hơn 10 năm, nhưng chưa có truy vấn nào mà chỉ cần đọc tài liệu Hibernate 5 phút và làm đúng theo hướng dẫn cho tình huống đó lại không xử lý được tốt hơn
Có vẻ như những fanboy SQL tin rằng mọi lập trình viên phải thuộc lòng bảng logic ba giá trị và các tên hàm kiểu COBOL, nhưng lại không muốn bỏ công đọc tài liệu Hibernate
ORM dành cho OLTP workload, không phải cho OLAP, và một trong những người tạo ra Hibernate cũng từng nói như vậy
Lợi ích chính chỉ là giúp khỏi phải tự viết những câu lệnh INSERT/UPDATE dài dòng dễ lỗi, đồng thời tự động ánh xạ các hàng SQL thành object
Nếu đi theo kiểu raw thì bạn sẽ phải tự triển khai lại khá nhiều phần trong số đó, nên đây cũng không phải trò chơi có tổng bằng không
Trong những ứng dụng đủ phức tạp, sớm muộn gì cũng sẽ xuất hiện thứ gì đó như query builder để nhiều phần của ứng dụng có thể cùng nhau kết hợp truy vấn theo kiểu trì hoãn
Đây là cấu trúc hướng tới việc kết hợp bằng truy vấn thay vì ghép, lọc và sắp xếp dữ liệu trong bộ nhớ
ORM là công cụ giúp làm điều này dễ dàng, nhưng cũng có thể vô tình khiến bạn tự bắn vào chân vì rất dễ tạo ra truy vấn N+1 mà không nhận ra
Giống như mọi công cụ khác, cần cân nhắc trade-off cùng với trường hợp sử dụng thực tế, và tôi không khuyến nghị cách tự thao tác trực tiếp với chuỗi câu lệnh SQL trong bất kỳ trường hợp nào
Dù vậy, lúc nào cũng có người bỏ qua những khác biệt đó rồi khẳng định một cách tuyệt đối rằng ORM là tốt hay xấu
Tốt hơn là cứ xem đó như một thái độ gây tranh cãi để thu hút chú ý rồi bỏ qua, và tập trung vào những thảo luận bắt đầu từ quan điểm “ORM có lợi ích, nhưng cần biết nó hiệu quả ở đâu và đừng để vấn đề khi sử dụng lấn át lợi ích đó”
Khi cần dữ liệu thì hãy đi qua tầng truy cập dữ liệu, và nếu nó chưa cung cấp thứ cần thiết thì hãy tạo repository, provider mới hoặc thứ gì đó phù hợp với pattern đang dùng
Dù là ORM hay bộ kết hợp truy vấn tự viết, nếu ứng dụng đã đến mức tự lừa mình rằng “nó đủ phức tạp nên cần cái này”, thì thực ra nó đã quá phức tạp để vận hành ổn định rồi
Cuối cùng bạn либо đang đánh giá builder ở sai tầng, hoặc sẽ bỏ lỡ việc mình đang tạo ra truy vấn N+1 trong lúc lặp qua kết quả
ORM là không cần thiết
LINQ không hẳn chính xác là ORM; khi bạn tạo các câu LINQ được định kiểu mạnh, chúng sẽ được chuyển thành cây biểu thức, rồi nhà cung cấp truy vấn sẽ biến chúng thành truy vấn
Trong lúc phát triển, tôi thích tính dễ đọc của ORM trong model, nhưng khi cần thì sẽ theo dõi sát N+1 và các dạng kém hiệu quả khác để tối ưu
Ranh giới của “khi cần” không rõ ràng, nhưng tôi cố tránh tối ưu quá sớm
Với dự án mới, tôi thường bắt đầu từ cơ sở dữ liệu và nắm cảm giác về mô hình dữ liệu bằng factory, seeder và truy vấn raw SQL trước khi viết code
ORM như Eloquent của Laravel có những phương thức tốt để xử lý N+1 và thực hiện lazy loading, nhưng lúc nào cũng có trade-off
Thay vì thư viện cho phép kết hợp truy vấn trì hoãn, bạn tự viết truy vấn và thư viện sẽ sinh mã cho truy vấn đó ở thời điểm biên dịch
Ví dụ, nếu bạn viết truy vấn như
getUser: SELECT * FROM users WHERE id = ?thì nó sẽ tạo ra lớpGetUserQueryvà phương thức nhưgetUser(id: String): GetUserQueryResult, và tôi thấy mô hình này tốt hơn nhiềuLý do chính tôi không thích ORM là vì chúng có xu hướng đối xử với các SQL engine hiện đại như một kho lưu bit ngu ngốc bị phóng đại
CTE, LATERAL join, mệnh đề RETURNING có thể đơn giản hóa xử lý rất nhiều hoặc loại bỏ khả năng dữ liệu không nhất quán, nhưng ORM phần lớn chỉ dừng lại ở mức ánh xạ đơn giản các bảng và view cơ bản sang những object được định nghĩa sẵn
Nếu ORM còn tự tạo cả bảng thì còn tệ hơn
SQL về bản chất vừa là công cụ trích xuất dữ liệu vừa là ngôn ngữ biến đổi, nhưng ORM gần như phớt lờ mặt này, khiến nhiều lập trình viên không biết rằng SQL còn có nhiều thứ hơn INSERT/SELECT/UPDATE/DELETE
Còn có bảng pivot, truy vấn theo thời gian, CUBE/ROLLUP, window function, set-returning function, materialized view, external table, xử lý JSON, xử lý ngày tháng, exclusion constraint, các kiểu như range/interval/domain, bảo mật mức hàng, MERGE, v.v.
Giống như có sẵn cả một nhà kho đầy công cụ mà ai đó chỉ đưa cho bạn mỗi cái búa, tua vít và cưa sắt rồi thuyết phục rằng thế là đủ, trong khi bạn dành cả sự nghiệp mà không hề biết chỉ cách đó vài mét còn có cưa bàn, router, máy chà nhám và cả bộ nêm
ORM đúng là khiến người ta chủ yếu nghĩ theo các câu lệnh CRUD đơn giản, nhưng có lẽ như vậy lại tốt hơn và các tính năng nâng cao nên được dùng tiết kiệm
Dù vậy, khi buộc phải dùng DB thì tôi cũng cố tình chỉ dùng một tập con rất nhỏ của các tính năng DB
Vì tôi xem “code” là phần có thể kiểm soát được, còn “cơ sở dữ liệu” là một vùng nguy hiểm, khó chạm tới, nơi lỗi chỉ lộ ra về sau ở những chỗ như integration test chậm chạp
Logic xảy ra bên trong DB nằm ngoài phạm vi của các kiểm thử mức thấp nên khiến tôi thấy đáng ngại, và có lẽ tôi sẽ không dùng cả truy vấn
select-from-selectTôi sẵn sàng bỏ lại phần lớn nhà kho dụng cụ đó
Phần lớn thời gian bị tiêu tốn để tạo ra các giải pháp vòng vo tinh vi chỉ nhằm phát minh lại những cơ chế bảo vệ toàn vẹn dữ liệu cơ bản
Tự làm cơ sở dữ liệu của riêng mình có thể vui cho mục đích học tập, nhưng không phải cho ứng dụng production
ActiveRecord lúc nào cũng cho cảm giác rất ổn
Có vài trường hợp ngoại lệ, nhưng nó đánh trúng điểm 80/20, cho phép thoát xuống SQL khi cần, và các lifecycle hook để tổ chức domain logic cũng rất tuyệt và dễ hiểu
Tôi thích những ORM thực dụng, không giấu mọi thứ sau một “bundle” hay đưa vào một ngôn ngữ truy vấn riêng
Những ORM cố gắng “giải quyết” hoàn toàn vấn đề ORM mới là thứ khó làm việc cùng
ORM nên được làm theo cách này
Tuy nhiên, để dùng đúng thì cần có nền tảng SQL tốt từ trước
Vấn đề xảy ra khi mọi người không học SQL và không hiểu các truy vấn mà AR sinh ra cũng như các giới hạn của nó
Tiền đề đã sai. ORM chưa từng là một “ý tưởng có hại”
Có những ORM rất kinh khủng để làm việc cùng, nhưng điều đó không có nghĩa cả thể loại này là một ý tưởng tồi
Tôi đã dùng SQLAlchemy rất thoải mái suốt nhiều năm vì nó không cố tái phát minh chính khái niệm SQL
Thay vào đó, nó cung cấp một tầng tiện lợi để xây dựng và truyền truy vấn, đồng thời xử lý đúng các chi tiết lặt vặt để tôi không phải tự mình vọc vào
Gần đây khi học Rust, việc tự viết mã khuôn mẫu để xử lý CRUD đơn giản khiến tôi thấy đau đớn và như một sự lãng phí thời gian
ORM của SQLAlchemy có thể hơi cản trở với các truy vấn phức tạp hơn hoặc cần tối ưu, nhưng trong những trường hợp đó bạn luôn có thể hạ xuống viết SQL trực tiếp
Cũng như mọi thứ khác, có những tình huống phù hợp và không phù hợp, và công nghệ rất dễ bị lạm dụng hoặc dùng sai
Ví dụ, các ORM như Entity Framework của .NET có thể là một tài sản lớn, đặc biệt khi làm việc theo hướng database-first
Nếu bạn có một DB với hàng trăm bảng và các quan hệ khóa ngoại đúng đắn, ORM giúp khám phá schema phức tạp và cung cấp kiểm tra ở thời điểm biên dịch khi thay đổi
SQL nhúng là con dao hai lưỡi, trông như có lợi thế hiệu năng nhưng lại cực kỳ khó bảo trì khi SQL dài dòng bị hardcode, đặc biệt là ở các phép join
Tôi không nói về lúc có 5~10 bảng mà là khi có hàng trăm bảng
Tôi không định thuyết phục ai, nhưng bạn không nên tin nguyên xi những gì đọc được trên mạng về các best practice
Mọi người có thể đang nói về những thứ hoàn toàn khác nhau, và dù dùng công nghệ nào thì vẫn luôn có lập trình viên tệ
Nếu không dùng ORM hay giao diện DB nào khác, cuối cùng bạn sẽ tự viết và bảo trì một cái cho những thứ như CRUD
Và rất có thể trong đó sẽ có những bug kỳ quặc, edge case và lỗ hổng bảo mật
Cũng có vấn đề khi các nguyên tắc như SOLID được dạy trong đại học như thể đó là các nguyên tắc thiết kế phần mềm phổ quát
Trong học thuật thì điều đó có lý vì các ràng buộc như thời gian, khả năng bảo trì, tiền bạc và công sức ít quan trọng hơn, nhưng khi sinh viên mới ra trường bước vào môi trường thực tế thì sẽ có một cú va chạm rất tệ
Vì họ đã quen dành cả ngày để yak shaving và tái phát minh bánh xe nhằm tìm ra lời giải “hoàn hảo”
Nếu không có đủ senior/lead đủ năng lực để chặn việc đó, bạn sẽ có một sản phẩm rất “thú vị”, vượt ngân sách, cháy lớn, hoặc là tổ hợp của tất cả những thứ đó
Tệ hơn nữa là khi thứ gì đó được tạo ra trong học thuật và thiết kế cho học thuật lại được tung ra công chúng
Ví dụ điển hình vừa tốt vừa xấu là OpenStack, với vô số tay nắm và nút chỉnh để hỗ trợ môi trường đặc thù của CERN và hàng trăm trường đại học, cùng các thành phần được mô-đun hóa đến mức điên rồ, nhưng nó quá kiểu Byzantine nên gần như không thể bắt đầu được
ORM không giúp bạn đổi cơ sở dữ liệu mà không tốn công, không loại bỏ nhu cầu phải học và hiểu SQL mà nó sinh ra, cũng không làm schema trở nên mượt mà hơn
Dù vậy người ta vẫn dùng nó vì đó là một lớp trừu tượng tiêu chuẩn mà kiểu gì bạn cũng sẽ phải sao chép lại
Nó cho phép cache truy cập DB, thứ mà với SQL thủ công thì càng ở quy mô lớn càng khó một cách đáng ngạc nhiên
Nó cũng đi kèm công cụ chuẩn hóa và best practice, giúp những vấn đề như N+1 trở nên không còn đáng ngại
Vấn đề chính của ORM là kỳ vọng sai và những ORM tệ
Nếu muốn biết giá trị của ORM, hãy mở một dự án được viết mà không có ORM rồi thử sửa bất kỳ thứ gì
Xem https://news.ycombinator.com/item?id=36498583
Công việc hữu ích không tiến triển, hoặc mất lâu hơn 20~100 lần so với cách tiếp cận nhanh và bẩn
Tệ nhất là trường hợp một đội designer HTML lành nghề bị ép phải học lập trình hàm
Phù thủy cấu hình backend đó là một kỳ quan của kỹ thuật hiện đại và thiết kế thanh nhã, nhưng mất 10 người làm trong 1 năm
Tiền VC khiến con người trở nên kỳ quặc
Ngôn ngữ SQL rất phức tạp, và việc làm ra một query builder đúng nghĩa, đầy đủ tính năng không hề là chuyện nhỏ nhặt
Điều này vẫn đúng ngay cả khi bỏ qua phần ánh xạ quan hệ thực tế
Tôi cho rằng SQL là một trường hợp đúng với kiểu “cứ tự mình lập trình cái chết tiệt đó đi”
Học SQL hay thư viện ORM thì thực ra không có nhiều ý nghĩa bằng việc tự học và tự viết SQL
Truy cập cơ sở dữ liệu có lẽ là công việc nền tảng bạn sẽ làm suốt cả sự nghiệp, nên tốt nhất là học trực tiếp kỹ năng thực tế đó
CSS cũng tương tự: thay vì học thư viện CSS thì nên học và dùng CSS
Thực ra gần như mọi mặt của phát triển frontend cũng vậy, thay vì “thư viện form” thì cứ làm việc trực tiếp với form API của trình duyệt
Cá nhân tôi thấy SQL dễ học hơn nhiều so với bất kỳ ORM nào
Đừng lãng phí chi phí để học những thứ sai hướng
CSS cũng vậy, nếu biết CSS thì khi chọn thư viện cho tiện lợi bạn sẽ linh hoạt hơn nhiều và hiểu rõ hơn
Qua nhiều nền tảng phát triển như mainframe, desktop, client/server, web và các ngôn ngữ khác nhau trên đó, SQL luôn là sợi chỉ chung xuyên suốt
Tôi hoàn toàn đồng ý rằng lập trình viên hiểu rõ tầng dữ liệu và những gì diễn ra bên dưới sẽ là lập trình viên mạnh hơn
Nếu đã định dành thời gian để học những điểm kỳ quặc của ORM, thì câu hỏi kinh điển là: tại sao không đầu tư thời gian đó vào việc học SQL?
Lợi ích cộng dồn của kinh nghiệm SQL sau 10–15 năm rất có thể sẽ giá trị hơn ORM của một nền tảng hay ngôn ngữ cụ thể
Có lý do để học và dùng ORM, nhưng không nên nghiêng về ORM chỉ vì không muốn học SQL
Có như vậy bạn mới biết mình phải trả giá gì cho lớp trừu tượng đó. Tất nhiên, nếu là “trừu tượng hóa không chi phí” thì khác
Nhưng giờ tôi đang dùng
crudcủaazer, thứ có thể xếp vào ORM, vì việc marshal/unmarshal với kiểu Gosqltrong thư viện chuẩn Go quá cơ bản, nên gần như phải tự viết phần marshal/unmarshal đối tượng, rất tẻ nhạtNếu ngày nay dùng ORM thì có lẽ tôi chỉ dùng đúng cho mục đích đó
Tôi thích các micro ORM ở “điểm giữa” như Dapper hay Diesel
Bạn viết truy vấn bằng SQL nhưng vẫn có kiểu mạnh và tự động ánh xạ tập kết quả sang đối tượng
Tức là vừa có năng suất vừa có một ngôn ngữ truy vấn “thực thụ” đầy đủ tính năng
Tôi cũng dần thích cách chỉ dùng object mapper cho các truy vấn chỉ đọc
Cập nhật thì thực hiện bằng command pattern, tức stored procedure, và có thể ánh xạ để chúng trông như các phương thức native
Lập trình viên nên chấp nhận sự tồn tại của SQL thay vì giả vờ như nó không có
Eloquent trừu tượng hóa đủ tốt mấy việc lặt vặt đó để tôi tập trung vào logic
Tôi đang viết lại một ứng dụng PHP “kiểu cũ” chỉ có mảng và truy vấn sang cấu trúc dùng model và Eloquent, và cảm giác như thay đổi hoàn toàn cuộc chơi
Trước đây khi dùng SQLite trên .NET tôi cũng từng làm một thư viện wrapper theo hướng đó: https://github.com/zmj/sqlite-fast
Chủ đề này cho thấy rất rõ sự thống trị về mindshare của ORM
Trong gần như mọi bình luận, phương án thay thế ORM được ngầm hiểu là raw SQL dưới dạng chuỗi literal trong mã ứng dụng
Từ 6 năm trước đã có các công cụ dùng SQL như một ngôn ngữ riêng và sinh wrapper để phơi bày truy vấn thành phương thức trong ứng dụng
Ví dụ như queryfirst, pgtyped, pugsql, sqlc
Đây là một sự chuyển đổi mô hình, hoặc ít nhất đã có thể là như vậy, và rõ ràng cho thấy đó là cách làm vượt trội hơn, nhưng ORM và cuộc tranh luận bất biến quanh nó đã hút hết không khí, khiến hướng này vẫn ở bên lề
SQL là một ngôn ngữ, mà còn là ngôn ngữ ở mức rất cao nữa
Cố gắng chắp vá SQL từ một ngôn ngữ cấp thấp hơn là ví dụ điển hình của kiểu “cầm búa thì mọi thứ đều trông như cái đinh”
Ví dụ, nếu bạn đang code bằng assembly cấp thấp và phải tương tác với một hệ thống lớn, mà tài liệu của hệ thống đó nói đầu vào chỉ có thể biểu diễn bằng JavaScript, thì bạn có lựa chọn
Bạn có thể mang về một thư viện khó hiểu để chắp vá mọi thứ bằng assembly thuần và khỏi phải commit file
xxx.jsvào kho mã, hoặc đơn giản là dùng sức mạnh của ngôn ngữ cấp cao bằng cách biểu diễn nó bằng file.jsBạn có được một nguồn chân lý duy nhất cho các truy vấn SQL đang dùng, và vì thứ thực sự được viết và bảo trì là chính các truy vấn đó, nên việc tối ưu như tạo chỉ mục mới cũng trở nên dễ dàng
Đặt một lớp trừu tượng lên trên chuỗi raw SQL là rất hữu ích, nhưng giả vờ quan hệ là đối tượng thì là một cách làm phức tạp và rối rắm
Có lẽ TopLink cũng vậy
Đó là cách nó xử lý việc ánh xạ giữa stored procedure và local entity