Trước khi tôi trả lời câu hỏi, tôi nghĩ rằng một số nền tảng là theo thứ tự.
Cốt lõi của vấn đề
Sau nhiều năm phỏng vấn và tuyển dụng các nhà phát triển, tôi đã học được hai điều:
Phần lớn các nhà phát triển có rất ít kinh nghiệm trong thiết kế cơ sở dữ liệu.
Tôi đã nhận thấy mối tương quan lỏng lẻo giữa những người không hiểu cơ sở dữ liệu và những người ghét ORM.
(Lưu ý: và vâng, tôi biết có những người hiểu rất rõ về cơ sở dữ liệu, những người ghét ORM)
Khi người ta không hiểu tại sao các phím nước ngoài là quan trọng, tại sao bạn không nhúng các tên nhà sản xuất trong item
bảng, hoặc lý do tại sao customer.address1
, customer.address2
và customer.address3
các lĩnh vực không phải là một ý tưởng tốt, thêm một ORM để làm cho nó dễ dàng hơn cho họ để lỗi cơ sở dữ liệu ghi sẽ không giúp được gì cả.
Thay vào đó, với cơ sở dữ liệu được thiết kế đúng và trường hợp sử dụng OLTP, ORM là vàng. Hầu hết các công việc khó khăn đều biến mất và với các công cụ như DBIx :: Class :: Schema :: Loader , tôi có thể chuyển từ một lược đồ cơ sở dữ liệu tốt sang làm việc với mã Perl trong vài phút. Tôi xin trích dẫn Quy tắc Pareto và nói rằng 80% các vấn đề của tôi đã được giải quyết với 20% công việc, nhưng thực tế, tôi thấy lợi ích còn lớn hơn thế.
Lạm dụng giải pháp
Một lý do khác khiến một số người ghét ORM là vì họ sẽ để sự trừu tượng bị rò rỉ. Hãy xem xét trường hợp phổ biến của các ứng dụng web MVC. Đây là một cái gì đó chúng ta thường thấy (mã giả):
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $company = $app->model('Company')->find({ slug => $company_slug })
or $app->redirect('/');
my $countries = $app->model('Countries')->search(
{
'company.company_id' => $company->company_id,
},
{
join => [ offices => 'company' ],
order_by => 'me.name',
},
);
$app->stash({
company => $company,
countries => $country,
});
}
Mọi người viết các tuyến điều khiển như thế và vỗ nhẹ vào lưng, nghĩ rằng đó là mã sạch, tốt. Họ sẽ kinh ngạc với SQL mã hóa cứng trong bộ điều khiển của mình, nhưng họ đã làm ít hơn là phơi bày một cú pháp SQL khác. Mã ORM của họ cần được đẩy xuống thành một mô hình và sau đó họ có thể làm điều này:
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $result = $app->model('Company')->countries($company_slug)
or $app->redirect('/');
$app->stash({ result => $result });
}
Bạn biết những gì đã xảy ra bây giờ? Bạn đã đóng gói đúng mô hình của mình, bạn đã không hiển thị ORM và sau đó, khi bạn thấy rằng bạn có thể tìm nạp dữ liệu đó từ bộ đệm thay vì cơ sở dữ liệu, bạn không cần thay đổi mã điều khiển của mình (và nó dễ dàng hơn để viết các bài kiểm tra cho nó và sử dụng lại logic).
Trong thực tế, điều xảy ra là mọi người rò rỉ mã ORM của họ trên tất cả các bộ điều khiển (và chế độ xem) của họ và khi họ gặp phải các vấn đề về khả năng mở rộng, họ bắt đầu đổ lỗi cho ORM thay vì kiến trúc của họ. ORM có một bản rap tệ (tôi thấy điều này lặp đi lặp lại cho nhiều khách hàng). Thay vào đó, hãy ẩn sự trừu tượng đó để khi bạn thực sự đạt giới hạn ORM, bạn có thể chọn giải pháp phù hợp cho vấn đề của mình thay vì để mã được liên kết chặt chẽ với ORM mà bạn bị ràng buộc.
Báo cáo và các hạn chế khác
Như Rob Kinyon đã nói rõ ở trên, báo cáo có xu hướng là một điểm yếu trong ORM. Đây là một tập hợp con của một vấn đề lớn hơn khi SQL hoặc SQL phức tạp kéo dài nhiều bảng đôi khi không hoạt động tốt với ORM. Ví dụ: đôi khi ORM buộc loại tham gia mà tôi không muốn và tôi không thể biết cách khắc phục điều đó. Hoặc có thể tôi muốn sử dụng một gợi ý chỉ mục trong MySQL, nhưng nó không dễ dàng . Hoặc đôi khi SQL quá phức tạp đến nỗi việc viết SQL sẽ tốt hơn thay vì sự trừu tượng được cung cấp.
Đây là một phần lý do tôi bắt đầu viết DBIx :: Class :: Báo cáo . Cho đến nay nó hoạt động tốt và giải quyết được phần lớn các vấn đề mà mọi người gặp phải ở đây (miễn là chúng ổn với giao diện chỉ đọc). Và trong khi nó có vẻ giống như một cái nạng, trong thực tế, miễn là bạn không bị rò rỉ sự trừu tượng của mình (như đã giải thích trong phần trước), nó làm cho việc làm việc DBIx::Class
trở nên dễ dàng hơn.
Vậy khi nào tôi sẽ chọn DBIx :: Class?
Đối với tôi, tôi sẽ chọn nó hầu hết các lần tôi cần một giao diện cho cơ sở dữ liệu. Tôi đã sử dụng nó trong nhiều năm. Tuy nhiên, tôi có thể không chọn nó cho hệ thống OLAP và các lập trình viên mới hơn chắc chắn sẽ phải vật lộn với nó. Ngoài ra, tôi thường thấy tôi cần lập trình meta và trong khi DBIx::Class
cung cấp các công cụ, chúng rất kém.
Chìa khóa để sử dụng DBIx::Class
chính xác giống như đối với hầu hết các ORM:
Đừng rò rỉ sự trừu tượng.
Viết bài kiểm tra chết tiệt của bạn.
Biết cách thả xuống SQL, khi cần.
Tìm hiểu làm thế nào để bình thường hóa một cơ sở dữ liệu.
DBIx::Class
, một khi bạn học nó, sẽ chăm sóc hầu hết các công việc nặng nhọc của bạn cho bạn và làm cho nó dễ dàng để nhanh chóng viết các ứng dụng.