모든 액티브 레코드가 싫어하는 이유는 무엇입니까? [닫은]
OOP에 대해 점점 더 많이 배우고 다양한 디자인 패턴을 구현하기 시작하면서 사람들이 Active Record에서 싫어하는 사례를 계속해서 떠 올립니다 .
종종 사람들은 그것이 잘 확장되지 않는다고 말하지만 (트위터를 그들의 주된 예로서 인용)-아무도 실제로 왜 잘 확장되지 않는지 설명 하지 않습니다. 및 / 또는 단점없이 AR의 장점을 달성하는 방법 (비슷하지만 다른 패턴을 통해?)
바라건대 이것은 디자인 패턴에 대한 성스러운 전쟁으로 바뀌지 않을 것입니다. 제가 알고 싶은 것은 **** 구체적으로 **** Active Record의 문제점입니다.
확장이 잘되지 않는다면 왜 안됩니까?
다른 어떤 문제가 있습니까?
거기에 액티브는 디자인 패턴 및 액티브 레일 ORM 라이브러리 및 .NET 용 노크 오프, 다른 언어의 톤도있다.
이것들은 모두 다른 것입니다. 그들은 대부분 그 디자인 패턴을 따르지만 다양한 방법으로 확장하고 수정합니다. 그래서 누군가 "ActiveRecord Sucks"라고 말하기 전에 "어떤 ActiveRecord, 힙이 있습니까?"라고 말하여 자격을 부여해야합니다.
저는 Rails의 ActiveRecord에만 익숙합니다. 사용과 관련하여 제기 된 모든 불만 사항을 해결하려고합니다.
@BlaM
내가 Active Records에서 보는 문제는 항상 하나의 테이블에 불과하다는 것입니다.
암호:
class Person
belongs_to :company
end
people = Person.find(:all, :include => :company )
이렇게하면를 사용하여 SQL이 생성 LEFT JOIN companies on companies.id = person.company_id
되고 연결된 Company 개체가 자동으로 생성되므로 people.first.company
데이터가 이미 존재하므로 데이터베이스에 접속할 필요가 없습니다.
멍멍
Active Record의 내재 된 문제는 데이터베이스 쿼리가 자동으로 생성되고 실행되어 개체를 채우고 데이터베이스 레코드를 수정한다는 것입니다.
암호:
person = Person.find_by_sql("giant complicated sql query")
추악하기 때문에 권장하지 않지만 단순하고 단순하게 원시 SQL을 작성해야하는 경우에는 쉽게 수행 할 수 있습니다.
@Tim Sullivan
... 모델의 여러 인스턴스를 선택하면 기본적으로 "select * from ..."을 수행합니다.
암호:
people = Person.find(:all, :select=>'name, id')
이렇게하면 데이터베이스에서 이름과 ID 열만 선택되고 매핑 된 개체의 다른 모든 '속성'은 해당 개체를 수동으로 다시로드하지 않는 한 nil이됩니다.
저는 항상 ActiveRecord가 모델이 상대적으로 평탄한 (클래스 계층 구조가 많지 않은) 빠른 CRUD 기반 애플리케이션에 적합하다는 것을 발견했습니다. 그러나 복잡한 OO 계층이있는 응용 프로그램의 경우 DataMapper 가 더 나은 솔루션 일 수 있습니다. ActiveRecord는 테이블과 데이터 개체간에 1 : 1 비율을 가정하지만 이러한 종류의 관계는 더 복잡한 도메인에서는 다루기 어렵습니다. 패턴에 관한 그의 책에서 Martin Fowler는 ActiveRecord가 모델이 상당히 복잡한 조건에서 분해되는 경향이 있다고 지적 하고 대안 으로 DataMapper 를 제안합니다 .
나는 이것이 실제로 사실임을 발견했습니다. 도메인에 상속이 많은 경우 연결 또는 구성을 매핑하는 것보다 상속을 RDBMS에 매핑하는 것이 더 어렵습니다.
내가하는 방법은 컨트롤러가 이러한 DataMapper (또는 "서비스 계층") 클래스를 통해 액세스하는 "도메인"개체를 갖는 것입니다. 이들은 데이터베이스를 직접 미러링하지 않지만 일부 실제 개체에 대한 OO 표현으로 작동합니다. 도메인에 User 클래스가 있고 해당 User 개체를 검색 할 때 이미로드 된 다른 개체에 대한 참조 또는 컬렉션이 있어야한다고 가정합니다. 데이터는 여러 다른 테이블에서 가져올 수 있으며 ActiveRecord 패턴으로 인해 매우 어려울 수 있습니다.
User 객체를 직접로드하고 ActiveRecord 스타일 API를 사용하여 데이터에 액세스하는 대신 컨트롤러 코드는 예를 들어 UserMapper.getUser () 메서드의 API를 호출하여 User 객체를 검색합니다. 각각의 테이블에서 연결된 개체를로드하고 완료된 사용자 "도메인"개체를 호출자에게 반환하는 것은 매퍼입니다.
기본적으로 코드를보다 쉽게 관리 할 수 있도록 다른 추상화 계층을 추가하는 것입니다. DataMapper 클래스에 원시 사용자 지정 SQL이 포함되어 있든, 데이터 추상화 계층 API에 대한 호출이 있든, 심지어 ActiveRecord 패턴 자체에 액세스하든 상관없이 멋지고 채워진 User 개체를 수신하는 컨트롤러 코드에는 중요하지 않습니다.
어쨌든, 그렇게 해요.
I think there is a likely a very different set of reasons between why people are "hating" on ActiveRecord and what is "wrong" with it.
On the hating issue, there is a lot of venom towards anything Rails related. As far as what is wrong with it, it is likely that it is like all technology and there are situations where it is a good choice and situations where there are better choices. The situation where you don't get to take advantage of most of the features of Rails ActiveRecord, in my experience, is where the database is badly structured. If you are accessing data without primary keys, with things that violate first normal form, where there are lots of stored procedures required to access the data, you are better off using something that is more of just a SQL wrapper. If your database is relatively well structured, ActiveRecord lets you take advantage of that.
To add to the theme of replying to commenters who say things are hard in ActiveRecord with a code snippet rejoinder
@Sam McAfee Say you have a User class in your domain, and need to have references to, or collections of other objects, already loaded when you retrieve that User object. The data may be coming from many different tables, and an ActiveRecord pattern can make it really hard.
user = User.find(id, :include => ["posts", "comments"])
first_post = user.posts.first
first_comment = user.comments.first
By using the include option, ActiveRecord lets you override the default lazy-loading behavior.
My long and late answer, not even complete, but a good explanation WHY I hate this pattern, opinions and even some emotions:
1) short version: Active Record creates a "thin layer" of "strong binding" between the database and the application code. Which solves no logical, no whatever-problems, no problems at all. IMHO it does not provide ANY VALUE, except some syntactic sugar for the programmer (which may then use an "object syntax" to access some data, that exists in a relational database). The effort to create some comfort for the programmers should (IMHO...) better be invested in low level database access tools, e.g. some variations of simple, easy, plain hash_map get_record( string id_value, string table_name, string id_column_name="id" )
and similar methods (of course, the concepts and elegance greatly varies with the language used).
2) long version: In any database-driven projects where I had the "conceptual control" of things, I avoided AR, and it was good. I usually build a layered architecture (you sooner or later do divide your software in layers, at least in medium- to large-sized projects):
A1) the database itself, tables, relations, even some logic if the DBMS allows it (MySQL is also grown-up now)
A2) very often, there is more than a data store: file system (blobs in database are not always a good decision...), legacy systems (imagine yourself "how" they will be accessed, many varieties possible.. but thats not the point...)
B) database access layer (at this level, tool methods, helpers to easily access the data in the database are very welcome, but AR does not provide any value here, except some syntactic sugar)
C) application objects layer: "application objects" sometimes are simple rows of a table in the database, but most times they are compound objects anyway, and have some higher logic attached, so investing time in AR objects at this level is just plainly useless, a waste of precious coders time, because the "real value", the "higher logic" of those objects needs to be implemented on top of the AR objects, anyway - with and without AR! And, for example, why would you want to have an abstraction of "Log entry objects"? App logic code writes them, but should that have the ability to update or delete them? sounds silly, and App::Log("I am a log message")
is some magnitudes easier to use than le=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();
. And for example: using a "Log entry object" in the log view in your application will work for 100, 1000 or even 10000 log lines, but sooner or later you will have to optimize - and I bet in most cases, you will just use that small beautiful SQL SELECT statement in your app logic (which totally breaks the AR idea..), instead of wrapping that small statement in rigid fixed AR idea frames with lots of code wrapping and hiding it. The time you wasted with writing and/or building AR code could have been invested in a much more clever interface for reading lists of log-entries (many, many ways, the sky is the limit). Coders should dare to invent new abstractions to realize their application logic that fit the intended application, and not stupidly re-implement silly patterns, that sound good on first sight!
D) the application logic - implements the logic of interacting objects and creating, deleting and listing(!) of application logic objects (NO, those tasks should rarely be anchored in the application logic objects itself: does the sheet of paper on your desk tell you the names and locations of all other sheets in your office? forget "static" methods for listing objects, thats silly, a bad compromise created to make the human way of thinking fit into [some-not-all-AR-framework-like-]AR thinking)
E) the user interface - well, what I will write in the following lines is very, very, very subjective, but in my experience, projects that built on AR often neglected the UI part of an application - time was wasted on creation obscure abstractions. In the end such applications wasted a lot of coders time and feel like applications from coders for coders, tech-inclined inside and outside. The coders feel good (hard work finally done, everything finished and correct, according to the concept on paper...), and the customers "just have to learn that it needs to be like that", because thats "professional".. ok, sorry, I digress ;-)
Well, admittedly, this all is subjective, but its my experience (Ruby on Rails excluded, it may be different, and I have zero practical experience with that approach).
In paid projects, I often heard the demand to start with creating some "active record" objects as a building block for the higher level application logic. In my experience, this conspicuously often was some kind of excuse for that the customer (a software dev company in most cases) did not have a good concept, a big view, an overview of what the product should finally be. Those customers think in rigid frames ("in the project ten years ago it worked well.."), they may flesh out entities, they may define entities relations, they may break down data relations and define basic application logic, but then they stop and hand it over to you, and think thats all you need... they often lack a complete concept of application logic, user interface, usability and so on and so on... they lack the big view and they lack love for the details, and they want you to follow that AR way of things, because.. well, why, it worked in that project years ago, it keeps people busy and silent? I don't know. But the "details" separate the men from the boys, or .. how was the original advertisement slogan ? ;-)
After many years (ten years of active development experience), whenever a customer mentions an "active record pattern", my alarm bell rings. I learned to try to get them back to that essential conceptional phase, let them think twice, try them to show their conceptional weaknesses or just avoid them at all if they are undiscerning (in the end, you know, a customer that does not yet know what it wants, maybe even thinks it knows but doesn't, or tries to externalize concept work to ME for free, costs me many precious hours, days, weeks and months of my time, live is too short ... ).
So, finally: THIS ALL is why I hate that silly "active record pattern", and I do and will avoid it whenever possible.
EDIT: I would even call this a No-Pattern. It does not solve any problem (patterns are not meant to create syntactic sugar). It creates many problems: the root of all its problems (mentioned in many answers here..) is, that it just hides the good old well-developed and powerful SQL behind an interface that is by the patterns definition extremely limited.
This pattern replaces flexibility with syntactic sugar!
Think about it, which problem does AR solve for you?
Some messages are getting me confused. Some answers are going to "ORM" vs "SQL" or something like that.
The fact is that AR is just a simplification programming pattern where you take advantage of your domain objects to write there database access code.
These objects usually have business attributes (properties of the bean) and some behaviour (methods that usually work on these properties).
The AR just says "add some methods to these domain objects" to database related tasks.
And I have to say, from my opinion and experience, that I do not like the pattern.
At first sight it can sound pretty good. Some modern Java tools like Spring Roo uses this pattern.
For me, the real problem is just with OOP concern. AR pattern forces you in some way to add a dependency from your object to infraestructure objects. These infraestructure objects let the domain object to query the database through the methods suggested by AR.
I have always said that two layers are key to the success of a project. The service layer (where the bussiness logic resides or can be exported through some kind of remoting technology, as Web Services, for example) and the domain layer. In my opinion, if we add some dependencies (not really needed) to the domain layer objects for resolving the AR pattern, our domain objects will be harder to share with other layers or (rare) external applications.
Spring Roo implementation of AR is interesting, because it does not rely on the object itself, but in some AspectJ files. But if later you do not want to work with Roo and have to refactor the project, the AR methods will be implemented directly in your domain objects.
Another point of view. Imagine we do not use a Relational Database to store our objects. Imagine the application stores our domain objects in a NoSQL Database or just in XML files, for example. Would we implement the methods that do these tasks in our domain objects? I do not think so (for example, in the case of XM, we would add XML related dependencies to our domain objects...Truly sad I think). Why then do we have to implement the relational DB methods in the domain objects, as the Ar pattern says?
To sum up, the AR pattern can sound simpler and good for small and simple applications. But, when we have complex and large apps, I think the classical layered architecture is a better approach.
The question is about the Active Record design pattern. Not an orm Tool.
The original question is tagged with rails and refers to Twitter which is built in Ruby on Rails. The ActiveRecord framework within Rails is an implementation of Fowler's Active Record design pattern.
The main thing that I've seen with regards to complaints about Active Record is that when you create a model around a table, and you select several instances of the model, you're basically doing a "select * from ...". This is fine for editing a record or displaying a record, but if you want to, say, display a list of the cities for all the contacts in your database, you could do "select City from ..." and only get the cities. Doing this with Active Record would require that you're selecting all the columns, but only using City.
Of course, varying implementations will handle this differently. Nevertheless, it's one issue.
Now, you can get around this by creating a new model for the specific thing you're trying to do, but some people would argue that it's more effort than the benefit.
Me, I dig Active Record. :-)
HTH
I love the way SubSonic does the one column only thing.
Either
DataBaseTable.GetList(DataBaseTable.Columns.ColumnYouWant)
, or:
Query q = DataBaseTable.CreateQuery()
.WHERE(DataBaseTable.Columns.ColumnToFilterOn,value);
q.SelectList = DataBaseTable.Columns.ColumnYouWant;
q.Load();
But Linq is still king when it comes to lazy loading.
@BlaM: Sometimes I justed implemented an active record for a result of a join. Doesn't always have to be the relation Table <--> Active Record. Why not "Result of a Join statement" <--> Active Record ?
I'm going to talk about Active Record as a design pattern, I haven't seen ROR.
Some developers hate Active Record, because they read smart books about writing clean and neat code, and these books states that active record violates single resposobility principle, violates DDD rule that domain object should be persistant ignorant, and many other rules from these kind of books.
The second thing domain objects in Active Record tend to be 1-to-1 with database, that may be considered a limitation in some kind of systems (n-tier mostly).
Thats just abstract things, i haven't seen ruby on rails actual implementation of this pattern.
The problem that I see with Active Records is, that it's always just about one table. That's okay, as long as you really work with just that one table, but when you work with data in most cases you'll have some kind of join somewhere.
Yes, join usually is worse than no join at all when it comes to performance, but join usually is better than "fake" join by first reading the whole table A and then using the gained information to read and filter table B.
The problem with ActiveRecord is that the queries it automatically generates for you can cause performance problems.
You end up doing some unintuitive tricks to optimize the queries that leave you wondering if it would have been more time effective to write the query by hand in the first place.
Although all the other comments regarding SQL optimization are certainly valid, my main complaint with the active record pattern is that it usually leads to impedance mismatch. I like keeping my domain clean and properly encapsulated, which the active record pattern usually destroys all hope of doing.
Try doing a many to many polymorphic relationship. Not so easy. Especially when you aren't using STI.
참고URL : https://stackoverflow.com/questions/7864/why-all-the-active-record-hate
'IT박스' 카테고리의 다른 글
Oracle SQL의 테이블에 대한 모든 제약 조건의 표시 이름 (0) | 2020.08.15 |
---|---|
SSL 대체를 비활성화하고 .NET에서 아웃 바운드 연결에 TLS 만 사용하려면 어떻게해야합니까? (0) | 2020.08.15 |
Windows 배치 파일의 한 줄에 여러 명령 (0) | 2020.08.15 |
"순수한 가상 함수 호출"충돌은 어디에서 발생합니까? (0) | 2020.08.15 |
img 요소를 만드는 데 가장 좋은 JavaScript 코드는 무엇입니까 (0) | 2020.08.15 |