I am still experimenting with Maglev, but it looks really promising
for now.
However, one very nice thing about rails is, that it takes care of
database evolution with migrations. As long as we just redefine method
semantics an add new methods there is no real problem, a simple
ruby -Mcommit model.rb
will do the trick and all persisted objects learn the new tricks.
However, once we start adding new instance variables things become a
little more tricky, as we might want to initialize them. Migrations
take care of this too, but I do not like the thought of scattering my
class definitions across a sequence of "class migrations". How does
Smalltalk deal with schema/class evolution in Gemstone/S?
Persistent code also introduces additional problems if you start
removing methods. As far as I can see you will have to call
remove_method :method_to_remove
exactly once in a persistent context. Of course I could guard this
inside the class definition using
remove_method :method_to_remove if method_defined? :method_to_remove
but this looks terrible in a piece of code that should stick around to
define the behavior of a class.
On the one hand I still think there would have to be something like a
migration to be able to go back and forth with the schema/class
definition, but on the other hand I would like to keep the definition
of the class in one file that I can track with a revision control
system. This does not seem to mix well with the persistence semantics
of Maglev and the dynamic behavior of classes in Ruby.
If someone has already come up with a solution I would like a pointer.
--
You received this message because you are subscribed to the Google Groups "MagLev Discussion" group.
To post to this group, send email to maglev-d...@googlegroups.com.
To unsubscribe from this group, send email to maglev-discuss...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/maglev-discussion?hl=en.
> I am still experimenting with Maglev, but it looks really promising
> for now.
Nice to hear that!
> How does Smalltalk deal with schema/class evolution in Gemstone/S?
For the official scoop, see chapter 9 of the GS64 Programming Guide
http://community.gemstone.com/download/attachments/6816350/GS64-ProgGuide-3.0.pdf?version=1
I also briefly discuss and compare with ruby in examples/persistence/migrations/migrations.org (see Appendix A).
NOTE: migrations.org are just my notes and half-baked writing as I was trying to thing through the issues; it is an unfinished document, i.e., there is a lot more room for discussion here, I may have things wrong, etc.
> Persistent code also introduces additional problems if you start
> removing methods. As far as I can see you will have to call
>
> remove_method :method_to_remove
>
> exactly once in a persistent context. Of course I could guard this
> inside the class definition using
>
> remove_method :method_to_remove if method_defined? :method_to_remove
>
> but this looks terrible in a piece of code that should stick around to
> define the behavior of a class.
I think that there is a good opportunity to create a migration DSL. We were reluctant to create to much of an official migration DSL, since, as implementors of the language rather than hard-core users of ruby, we lacked the real-world application level experience and we didn't want to start the whole DSL off on the wrong foot. Most of the experience the MagLev team has with migrations, are from the Smalltalk side, but the tools, issues and mostly the usage patterns (metaprogramming) between Smalltalk and Ruby are quite different (some of this is mentioned in migrations.org).
My personal view is that a migration DSL that is similar to the Rails migrations is probably the way to go (and by "similar", I mean that you deal with persistent classes and objects mostly or exclusively through the dsl (rails generate model ...; edit ; rake db:migrate). This forces you to think about and consider schema evolution. The flip side is that you may not want to persist rails itself (although you could).
> On the one hand I still think there would have to be something like a
> migration to be able to go back and forth with the schema/class
> definition, but on the other hand I would like to keep the definition
> of the class in one file that I can track with a revision control
> system. This does not seem to mix well with the persistence semantics
> of Maglev and the dynamic behavior of classes in Ruby.
I don't think there is a silver bullet here. Take a look at examples/persistence/migration (keeping in mind it is just a sketch) and I'd love to hear some good discussion about this.
--
Peter McLain
pmc...@vmware.com
Sent from my iPad
On Nov 11, 2011, at 7:21 AM, Patru <pat...@gmail.com> wrote:
> sorry, my ASCII-art broke, will try to improve on it if there is
> interest.
>
Patru, I am very interested in the discussion.
-Conrad
I put it in the tag-wiki on stackoverflow, appears to be a more
appropriate place at it will be easier to update and to keep it as a
working document (and google will index it real quickly :-). You can
find it on
http://stackoverflow.com/tags/maglev/info
At some point it should probably migrate to a page on github.
Unfortunately there seems to have been little discussion on the point,
maybe we can spice it up a little.
I am pretty sure we will need some type-Metadata to work with Rails
and the web. Of course Maglev will be able to store anything we care
to throw into an instance variable, but it will *not* know how to
demarshall a string coming in from a web-form. In order to enable a
correct conversion we will have to provide rails with some type
information (as we will use plain objects, not ActiveRecords). I never
dug far enough into rails to tell what exactly this might have to be,
but I guess we should be able to do this in a simple hash:
META = {
:name => :String,
:first_name => :String,
:date_of_birth => :Date,
:zip_ccde => :Fixnum,
:city => :String
}
you get the idea. Rails usually relies on the information in schema.rb
which is generated by reading the metadata from the database. As long
as we are not even providing Maglev with this information we can
hardly expect to guess it correctly. And as classes are the only
schema information I need to provide to Maglev Address::META looks
like a natural place to put it.
For the structural migrations I am still not quite sure where I really
want to keep them. There is of course the possibility to keep it in
migration files as rails usually does it, but that will scatter the
definition of our class which is a thought I do not really like (at
least until there is a development system that would be able to stitch
it together again).
On the other hand we might introduce a class constant with the version
of the class. It ought to be possible to determine the current version
number of the persistent class while loading the file and write plain
old ruby code (there might not even be a need of a special DSL to do
it) which migrates the class (or at least its disruptive changes) to
the current version. Might look something like
...
if VERSION < "0.9.0"
remove_method :postal_code
VERSION = "0.9.0"
end
if VERSION < "0.9.5"
attr_accessor :street
VERSION = "0.9.0"
end
...
again you get the idea. I will have to try if this really works, but I
think it should do so for now.
This would have the advantage to keep the whole class definition in
one file which could be written in the development environment and
then just loaded into your Maglev image in test, staging or production
environments. It would be possible to load a class multiple times and
it could break in a controlled way if it needs to do so. It would
however rely on migrations which are isolated inside one class. This
might be too much of a restriction, but I think we will all have to
experiment with some projects which use Maglev objects inside rails to
be able to know better.
I could also imagine that it does not really play nice for "large"
migrations, whatever that might turn out to be, but you probably do
not want to initialize new attributes in millions of existing objects
during class load time.
:: Patru ""
Of course there is one more caveat (which should have been obvious to
me in the first place). As all classes descend from Object
Company::VERSION will always be "visible" even if it is not defined in
Company. This also explains why all classes in Maglev do seem to be of
version "1.0.0".
As VERSION is called an obsolete constant in Ruby 1.8.7, because of
this it is probably a bad idea to use the (obvious) name as a
versioning construct. While it would not interfere with Ruby 1.9 and
above its use in 1.8 (although I have not been able to determine the
exact semantics) makes it a suspicious candidate for a versioning
construct. I guess I will resort to using CLASS_VERSION for now.
On 21 Dez., 23:56, Patru <pat...@gmail.com> wrote:> all classes (even your own ones) get a VERSION String 1.0.0 by default
> Object::VERSION
>
> in MRI you get the ruby version (at least up to 1.8.7, 1.9 does not
> seem to define this Constant anymore). Maglev will return a version
> number for the class, for Object that currently is 1.0.0, other
> classes have their own VERSION constant <class>::VERSION, currently
> which might be an indication of the version of Maglev I am using. As
> shown above you can redefine this CONSTANT in your own classes,
> although it is probably not a good idea to set it lower than it
> initially is.
You can use the VERSION constant to migrate your persistent classes,
but it is still just a one-way trip, there does not seem to be an easy
way to "migrate back". However, you may abort the transaction if your
code does not compile, but if the code compiles ok but introduces
other problems (which you will agree should never happen :-) then
there is no obvious way to get "back". This is still not quite what we
are used to in Rails.
:: Patru ""