The recent rise in popularity and enthusiasm around languages fully equipped of dynamic amazements such as Python and Ruby have made me wish
to get started with them trying, where possible, to use them instead of the old static Java. Hallelujah. At last, most of us cried. Since already
familiar with Python, I decided to get started with Ruby full of enthusiasm. As a conseguence, as most beginners, I have some doubts especially
concerning the adoption of Ruby in large scale projects. I'm aware that, as old Java developer, these doubts might be related to my background, but
anyway I'd like to share them.
Reading further on Ruby's object-oriented features, I found out in Programming Ruby that:
Classes are never closed: you can always add methods to an existing class. This applies to the classes you write as well as the standard,
built-in classes. All you have to do is open up a class definition for an existing class, and the new contents you specify will be added to
whatever's there.
As a conseguence, you can always revise a method (changing its semantics) to an existing class no matter where you are.
For instance, let consider the following example.
class Folder
def initialize(name)
@name = name
@files = Array.new
end
def addFile(newFile)
@files.push(newFile)
end
def list
puts @name+":"
for i in 0...@files.length
puts "--"+@files[i]
end
end
end
#base semantics
aFolder = Folder.new("reports")
aFolder.list
puts "here we're ..."
#...............
#...............
#...............
#...............
#...............
#...............
#override
class Folder
def list
puts @name+":"
if @files.length == 0
raise "empty folder!"
end
for i in 0...@files.length
puts "--"+@files[i]
end
end
end
#modified semantics
aFolder = Folder.new("reports")
aFolder.list
puts "never reached!!"
In the previous example the semantics of the method list has been changed on-the-fly. While the first invocation of the method doesn't raise
an exception if the array is empty, the second does. That might be an useful feature in some circumstances. On the other hand, I wonder if that could
make Ruby classes semantics a bit "context-sensitive" instead of "context-free" as in Java. For example, while in Java when I have to deal with a
java.util.ArrayList I'm sure about its semantics (at least, from the moment I took a look at the source code on) no matter if used in a project
instead of another (the context), in Ruby if I have to deal with an Array I must be careful if its semantics has been changed somewhere. The more the
places I must check, the more the time.
Do you believe that could be a problem in large scale projects, where each developer can change the semantics of any class inside any scope?
What about the overhead in terms of learning time for each new developer?
In AOP considered harmful, the authors present the obliviousness-property of AOP meaning that "at the source code location describing
an affected join point (i.e. a method call, field access, ...) the advice which will be executed is not visible, in contrast to a method call.
As a result just looking at the source code line, loop counters or the call stack is not enough to deduce a variable value—a piece of advice
might have changed it in-between, invisible for the programmer".
Do you believe that the obliviousness-property holds also for Ruby's class definition, meaning that just looking at the source code lines
of the first definition of a class isn't enough to fully understand its semantics?
Obviously, a suitable tool could outdo my hard work of manually checking. Such a tool should be able, for instance, to get the actual working
definition of each class inside a given scope. Such a kind of tool makes me remind an Eclipse plugin for AOP for getting displayed where advices
are/may be applied using a "gutter marker". The markers contain rich information to inform you why there is a (or several) joinpoints on a specific
line of source code. In the same way, that reminds me of the objection to AOP of being considered harmful. In the paper by Koppen and Stoerzer, PCDiff: Attacking the Fragile Pointcut Problem, we find the formulation of the so called fragile pointcut problem about AOP,
i.e. "a programmer refactoring e.g. a class of the base system is not aware of all the aspects possibly matching joinpoints in this class.
Tool support lightens this problem, but in our opinion this does not resolve the problems for evolution of aspects, classes and their dependencies.
This also raises another interesting question for companies developing AO software: If failures due to changed pointcut semantics occur,
who is responsible? The aspect developer or the base developer? Both answers are not satisfactory ...
So in general both programmers have to talk to each other but therefore they have to be aware of potential evolution problems."
In the previous example, things might be a bit worse, as the programmer refactoring the base definition of the class Folder
(let's imagine deployed in a different module) turning the name of the method list into listFiles, for example, isn't aware that
client source code will run using a further re-definition of the method list (previously, now the only definition of such a method)
getting no compile-time error. So, client side invoking the method list you'll get the same results before refactoring
as the base class owner performed no refactoring at all. I wonder if refactoring still makes sense in such a context.
Still, if failures due to redefined class semantics occur, who is responsible? The base developer or the other developer (if there's only
one in the chain)?
You're thinking one object, and the question is about long term projects and the whether or not stability can be achieved with non-static objects.
Ultimately I'm sure this will be answered with the usual Ruby posts of "just write unit tests" and "the developers don't have to use this if they decide it's a bad idea".
> You're thinking one object, and the question is about long > term projects and the whether or not stability can be > achieved with non-static objects. > > Ultimately I'm sure this will be answered with the usual > Ruby posts of "just write unit tests" and "the developers > don't have to use this if they decide it's a bad idea".
Yeah, I am sure it will be. Again the problem I have with most of the dynamic languages in real terms is they are bad for larger-teams and longer lived applications. It has been said before, and I will say it again, "Ruby is great if you have a stable development team of great coders." This, however, is not always the case in the real world.
> > You're thinking one object, and the question is about > long > > term projects and the whether or not stability can be > > achieved with non-static objects.
This is a question you have? Seriously? There are a LOT of long term large scale systems written in dynamic languages. This feature is also available in Objective C - so all the Cocoa based apps on the Mac (and formerly, Next)would be just one data point. There are a lot of enterprise Smalltalk systems that have achieved long term stability.
These are not small systems. This entire thread is fear mongering from the C++/Java bigots.
> ...the problem I have with > most of the dynamic languages in real terms is they are > bad for larger-teams and longer lived applications.
Says you based on what? My experience is exactly the opposite. C++ has huge scalability problems, java somewhat less so, but system brittleness is still very high.
> "Ruby is great > if you have a stable development team of great coders." > This, however, is not always the case in the real world.
Without a stable development team of decent coders, you have no chance at all in any language.
> These are not small systems. This entire thread is fear > mongering from the C++/Java bigots. > I don't think most C++ or Java programmers have much vested interest in protecting C++ or Java from Ruby and other dynamic languages by fear mongering. I think it is not so much fear mongering as just plain old fear. I know I have this fear, or at least concern, about the scalability of dynamic languages. I don't have any experience creating a large system in a dynamic language, precisely because I'm too afraid to bet a large project on a language I'm not sure scales to the task. It seems logical to me that all these things in static languages that slow individuals down may help groups work together more effectively. But I just don't know because I'm not willing to take a chance building a large project on a dynamic language unless I'm sure ahead of time.
What's a large project? Seriously. How large does a project need to be?
I know that if I was able to use Ruby for a lot of the stuff I do at work, the amount of code that I'd have to write would drop by at least two thirds, if not more. (I can't, for a variety of reasons, and that's okay. Ruby *isn't* appropriate for everything as much as I wish it were.)
I think that one would need more regular code reviews, but I suspect that it would be highly unusual to have a project so large that it couldn't be understood relatively quickly.
I know I pull this example out often, and it's becoming a *little* stale because I haven't had time to update the code, but PDF::Writer is less than a tenth the size of similar C# and Java projects.
What size of project are you really talking about, and what size of project do you really need?
class Folder
attr_accessor :files
def initialize(name)
@name = name
@files = []
end
def list
puts @name + ':'
puts @files.map{|f| '--' + f}
end
end
a = Folder.new('reports')
a.list
# ...
class Folder
def list
puts @name + ':'
raise 'empty folder!' if @files.empty?
puts @files.map{|f| '--' + f}
end
end
a = Folder.new('reports')
a.list
Large projects are often a lot smaller in Ruby.
Why are many Java programmers afraid of powerful things? Open classes aren't intended for this kind of thing.
I'll give an example with open-objects (not exactly open classes but similar).
You want to create a button in a GUI. The on_click method will be called when the user clicks the button. Here are two ways to do this:
class AButton < Button
def on_click
...
end
end
# ...
abutton = AButton.new
- or -
abutton = Button.new
def abutton.on_click
...
end
The second way is cleaner.
Now, for example, imagine that you want the button to change behavior once it's clicked:
abutton = Button.new
def abutton.on_click
alert('First click!')
def self.on_click
alert('You already clicked me!')
end
end
"Whoa this is scary. Everyone can redefine your objects at runtime!!!"
Many seem to think that programmers are stupid/evil. If you want to be evil in Ruby, you can redefine Array.new, so that it will return an integer 1% of the time. Now that's a hard to find bug. Would anyone ever do this? No.
> Ultimately I'm sure this will be answered with the > usual Ruby posts of "just write unit tests" and "the > developers don't have to use this if they decide it's > a bad idea".
Yes, and the fact that you can predict the answers doesn't make them less valid.
> What's a large project? Seriously. How large does a > project need to be? > > I know that if I was able to use Ruby for a lot of the > stuff I do at work, the amount of code that I'd have to > write would drop by at least two thirds, if not more. (I > can't, for a variety of reasons, and that's okay. Ruby > *isn't* appropriate for everything as much as I wish it > were.) > > I think that one would need more regular code reviews, but > I suspect that it would be highly unusual to have a > project so large that it couldn't be understood relatively > quickly. > > I know I pull this example out often, and it's becoming a > *little* stale because I haven't had time to update the > code, but PDF::Writer is less than a tenth the size of > similar C# and Java projects. > > What size of project are you really talking about, and > what size of project do you really need?
I had the same question but from a slightly different angle. These sorts of questions have come up before and where I think some of these more powerful constructs cause real problems is when 'large' is used to describe the team or organization that is working on the project.
I think if the project is large only in the sense that it has a lot of files and/or LOC but the team that is working on the project is small, say 10 people or less (I wanted to say 6 initially, but that seems overly constraining for some reason) then I don't think you run into problems. If you have a few people and they are all on the same page as far as the tools being used, conventions for coding, when to use certain constructs and when not to, then I don't think you have a problem. After all, just because you can do something doesn't mean you should do something and a small group of sharp people should be able to figure out where that line is.
Once the number of people on a project gets large (30 or 50 or 100 or more) then you run into issues because the average talent level will be lower. That's due to nothing more than the number of people on the team. You'll have some people that won't understand what's going on and that person may be so far removed from the person with the answer that they will either never understand what is going on or finding out what is going on will take an inordinate amount of time bacause he's got to go find the person and that might involve asking his boss who has to ask her boss who has to ask the other team manager who has to go talk to somebody, etc.
If you look there are stories of large pieces of software using non-mainstream technology that get bought by big companies and then the super cool technology that got bought has to be re-worked so a much larger group of people can take advantage of it. The two that come to mind are Yahoo! buying Viaweb and Sony buying Naughty Dog. In both cases rumor has it that these systems had to have major portions, if not the whole thing, re-worked so that larger groups of developers could work on them. The systems had made use of lisp and all that lisp stuff just couldn't be utilized or they could find enough people to work on, maintain or enhance the systems.
More or less I agree with Bill on this one. However, as Jules mentions, large projects do tend to get smaller with dynamic languages. At least that's been my experience.
And I can only agree with the first half of Ivan's "Ultimately I'm sure this will be answered with the usual Ruby posts of "just write unit tests" and "the developers don't have to use this if they decide it's a bad idea"." There are plenty of idioms in any language I've worked with that can be considered bad or dangerous. I can't imagine strong typing and static classes saving a project from becoming a complete clusterfuck if the developers involved can't discern between good and bad implementation decisions.
> Large projects are often a lot smaller in Ruby. > See? Dynamic languages don't scale to large projects! The code is too crisp and concise to allow the project to get very big.
It is good to ask what people mean by big. Do they mean large swaths of code, large teams, both? I think the large team question is a question about social organization. We have speed limits and stop signs that slow down individuals in the name of increasing public safety. It isn't just that that as a population grows you'll get some bad drivers (bad programmers), but that good drivers, being human, sometimes make mistakes that can end up hurting others. The question to answer in chosing a language for a project is, what's the best tradeoff between freedom and constraints given the task at hand?
> What's a large project? Seriously. How large does a > project need to be?
A good question. And how long, may I add? Not ever easy to answer, especially before to jump in 1.0 adventure without any engagement about 2.0. Anyway, I see three aspects.
1. How many technologies should a company invest in to deliver the same kind of projects? Is it a good long-term strategy to adopt a solution for small/medium projects and another for big/mega projects? If you're hiring a junior programmer you must take into account a period of time for training, that indeed would become two. Still, the time a programmer spends to get started in two programming languages could be spent to become expert in one only.
2. I didn't talk about dynamic languages generally. I made specific mention of Ruby. Do any/most dynamic languages support open classes?
3. Let's assume that with a set of self-imposted practices a good development team addresses these issues. What about using third-party modules?
That said, I must confess that, as a programmer, I love synthetic and elegant programs and dislike unuseful heavy notation. At any rate, I don't think that elegance and synthesis are always with problems. Indeed, my faith says the opposite.
> Many seem to think that programmers are stupid/evil. If > you want to be evil in Ruby, you can redefine Array.new, > so that it will return an integer 1% of the time. Now > that's a hard to find bug. Would anyone ever do this? No.
Let's think about the Oracle's design choice not to allow triggers to modify/query a table that is currently being modified by the statementthat fired the trigger. Are these ALWAYS infinite loop? At Oracle they knew that in case of problems managers would have heard "Oracle isn't stable enough".
Flat View: This topic has 51 replies
on 4 pages
[
1234
|
»
]