Sharp knives and glue

On 5/3/06, James Edward G. II [email protected] wrote:

hold in their heads.

Do you use unit tests?

Yes. And they work just fine for small project, but the cross-product
of
methods that can pass parameters to other methods in other classes that
get
passed down the line, etc. cannot be confidently tested with unit
tests…
especially when delegates are introduced into the mix.

Unit tests are not a substitute for programmers defining the rules in
their
code and having a tool check/enforce those rules.

Ruby would be better if I could

say, “only the following classes/modules can change the behavior of my
classes” so that some MixIn that I know nothing about changes
something in
my code.

If some code you know nothing about is changing your code, they are
breaking the rules and should know to expect the consequences, in my
opinion.

Well… what are the consequences? For example, Instiki 0.11 works just
fine under WEBrick, but breaks running under FastCGI because of a load
sequence issue with the 0.8.x rails libraries that are shipped with
Instiki
and whatever version of stuff is in my Gems directory.

The consequences of this is I can’t use a Rails app in my normal
production
environment. Sure, I could figure out what’s going on… but that’s a
waste
of my time (I’ve already lost 3 hours of consulting revenue trying to
install Instiki as a FastCGI rather than a port-forwarded WEBrick app.)

The consequences of this is I’m screwed.

The consquences of this is I can’t recommend Ruby to my enterprise
clients
because they can’t predictably deploy applications unless they have a
freeze-dried perfectly versioned system that will never change because
of
the unpredictability and instability of changing library versions.

Oh… BTW – Instiki passes its unit tests because the load sequence is
correct for the unit tests… but it’s not correct when Instiki is
launched
as a CGI or FastCGI. So… the consquences of this is that you can’t
trust
unit tests in Ruby because they can be impacted by Module/Class load
sequences.

James Edward G. II

On 5/3/06, David P. [email protected] wrote:

I am a very, very good programmer. I’ve written more than a dozen
commercial applications including Mesa which was used by Wall Street traders
as part of a automated trading systems.

Commercial software is not necessarily the benchmark of good. This
is not meant to reflect upon your capabilities, but I think it’s sort
of pointless to mention this.

But I used C++ and later Java to help keep order. I used the machine and
the tools to help me do the right thing. After all, if you have tools, why
not use them. I can refactor the Java code using Eclipse because of Java’s
strong typing (e.g., migrating some of the code in Integer to use generics
and enumerations.)

Yes, this helps. It’s too bad we don’t have better refactoring tools
in ruby. But I think a lot of refactoring that is necessary in
Java/C++ etc is not necessary in Ruby.

How do you make a method ‘abstract’ in Ruby? One way would be to just
delete it from the class which things will inherit from. Since the
refactoring patterns seem to be simpler, since the codebase is
substantially smaller, and the time to write this code is far less,
auomated refactoring is less of a life saver. Don’t get me wrong, i’m
not saying it wouldn’t be a great thing… what i am saying is the
time saved by automated tools in Java would be hard to compare with
the time saved by not using Java.

I would never have been able to write Mesa (95%+ of the code base came from
my hands) or Integer (50%+ of the code base came from my hands) if not for
the compiler tools. They helped me write better code.

Is there anything a compiler did that a well written unit test
couldn’t? If so, what features of the compiler tools were most
essential to you?

In the begining, Mesa was all Objective-C. I found it increasingly
difficult to refactor code, etc. without the tools that C++ brought to the
table (if I changed a method name, I’d do a compile and all the places in
the code that called that method would be flagged, etc.)

Sounds like exactly what happens when I change a method name in
Ruport, except it’s my function by function unit tests which do this
for me.

Ruby forces the developer to do more work and think more. This is okay if
you’ve got a small team that has a mind-meld. This is more and more
difficult when you have larger and larger teams. It’s not a question of
dicipline or quality of developers, it’s a question of how much people can
hold in their heads. People can only remember so many naming conventions,
code conventions, etc. Using the machine rather than the developer to deal
with these issues is why we have machines in the first place.

Have you ever worked to implement code based on tests someone else has
written, or to extend code which is covered by another set of tests?
I may have totally missed the boat in Java / C++ as to how a compiler
will save my life here, but I’ll tell you one thing, well written
tests tell me exactly what’s amiss, and they even give me a little
insight into where and why.

It’s great fun to work through the Test First Challenge for ruby (or
the original Java version even ). This might be a good example of how
someone else (or even yourself) can mold an interface and a set of
behaviors before implementation and ensure that the code will conform
to this.

Sorry to go off on you, but your argument is the same argument that people
used to claim that C++ was better because developers managed memory rather
than having the machine manage memory. Machines are better than developers
at managing memory. Machines are better than humans at enforcing rules.

You were right when you said that computers are better than developers
at memory management. Luckily, Ruby is an excellent language as far
as handling dynamic typing, memory allocation, and all these things
that would be scary for us to do by hand… Still, there is a human
component to all of this, and I’ll trust myself to design a better API
than the computer, so a language that doesn’t get in my way when I’m
doing this, is A Good Thing. I also trust that I will understand the
behaviors of my software better than the computer will… this is
where test driven development really shines.

Machines are better at enforcing rules, without a doubt. But machines
cannot understand rules, nor can they change them, nor can they know
when it’s okay to break them. That is uniquely human, and is
important to any creative process.

In the begining of a coding project, it’s better to worry about the thing
one is building rather than worrying about the rules and structures of what
one is coding. But as a project evolves and grows beyond a few people, it’s
better to have the rules by which the code was written included in the
code… not mearly as comments, but as constructs that tools can enforce.
This helps keep everybody in the same dicipline without some stupid
construct like “The Hungarian System” with managers at Microsoft losing
bonus if their developers weren’t writing “Hungarian” code.

Um… unit tests? Functional tests? Acceptance tests?

Guard rails are good. Lines on the road are good. If I was the only driver
on the road and I knew the roads that I was driving or was blazing new
trails… sure… I’d prefer to have fewer obsticles. But once you have
lots of drivers, even excellent drivers, driving over a well defined set of
roads, keeping them driving in harmony is a lot better than letting them go
willy-nilly all over the place.

I don’t know. Nice analogy, but to me, Ruby is not a road, but a wide
open space. When you’re working with wide open spaces, you don’t need
to worry so much about crashing into each other.

Ruby would be better if I could put up guard rails around certain system
features so that one would have to be explicit about using those features (
e.g., the #unsafe block modifier in C#.) Ruby would be better if I could
say, “only the following classes/modules can change the behavior of my
classes” so that some MixIn that I know nothing about changes something in
my code.

Sure, it’d be nice to see stuff like this. But it’s something that’s
secondary to the design goals of the language, and in my experience,
doesn’t come into practical necessity in ruby development. There are
bound to be plenty of edge cases, and for those, things like this
would be nice. But the power of this language is that it doesn’t
get in your way. If you’re not using that power, you might be much
happier in a language with a lot more rules. Some applications really
do need strictness like this, but many others do not.

This is not a binary argument (either Java or Ruby). This is not a “Java is
absolutely better than Ruby” argument. This is a discussion about how to
borrow from other systems to make an excellent system (Ruby) even better for
an important class of developers.

Yes, I think it’s important to find ways for certain applications to
be written ‘safely’ in Ruby, but part of that is changing the way you
think about things when you are working in different languages. What
works for Java is not necessarily good for Ruby. It doesn’t mean that
Java must be used for big applications and Ruby can’t scale… it just
means that you have to design differently when you are using languages
which are very different philosophically.

That’s not a bad thing, and with it in mind, if there are ways to
tighten things up optionally (and I do think that RAA has at least a
few libs that help), I say that’s a great thing.

But it doesn’t mean that the language should be changed to meet these
goals. Ruby’s not broken :slight_smile:

On Thu, May 04, 2006 at 12:22:20AM +0900, kate rhodes wrote:
} Just want to point out that a secondary issue has been introduced to
this
} conversation that makes it much harder to answer the initial question.
} People started talking about large scale development projects and
} enterprise this and that which are valid issues to address when
comparing
} ruby to other languages BUT, the question at hand is should
undiciplined,
} or just poor quality, programmers be handed a language as dynamic and
} flexible as Ruby or something that limits their ability/options to do
} stupid things, like Java or Ada? Ada, as Ed pointed out, probably is a
} better choice than Java by this criteria and it is alive and well in
the
} defence industry.

Poor quality programmers should not be paid to develop software any more
than poor quality construction workers should be paid to build
buildings.
Anyone who isn’t good at their work should either make an effort to
improve
or choose different work.

If the goal is to learn how to program from the beginning, I think Ruby
is
an excellent first language. It is very readable, strongly
self-consistent,
and has aspects of several language paradigms. I’m using it to teach my
wife, for example.

If the goal is to learn discipline, the language depends on what variety
of
discipline one is seeking. One learns different flavors of discipline
from
different languages depending on the safety nets inherent in the
languages.
Some (certainly incomplete) examples:

  • C++ (and C) programming requires rigorous memory management discipline
  • Ruby requires discipline in consistent naming/terminology

If the goal is to learn design, any language will do. Some languages
have
better constructs than others (e.g. Ruby modules vs. C++ namespaces vs.
Java packages), but high-level design is largely language-independent.

If the goal is to collaborate with other developers, especially many
teams
of other developers, languages like C#, Java, and C++ have good
constructs
to keep people from stepping on each others toes. It requires more
rigorous
discipline to develop Ruby code collaboratively, particularly in that
there
is less facility for automated tools to warn of lack of discipline.

If the goal is long-term maintainability, no undisciplined developer
should
come near the project. Maintainability is direclty proportional to the
discipline involved in the development. I don’t mean development
process, I
mean everything from coding conventions (e.g. two-space indentation,
underscore-separated variable and method names) to loose coupling (e.g.
minimize entry points into objects) to fine-grained namespaces (e.g.
heavy
use of nested modules). Even Perl code can be maintainable if there is
discipline in development.

There are other goals which (should) affect one’s decision to use one
language or another (e.g. portability), and there are usually many goals
involved in any given project. It’s all about using the right tool for
the
job. You can’t even know the right tool if you don’t know several
languages. Start small, gain experience, and learn every step of the way
is
my advice.

} -kate
–Greg

On May 3, 2006, at 11:38 AM, David P. wrote:

For example, Instiki 0.11 works just
fine under WEBrick, but breaks running under FastCGI because of a load
sequence issue with the 0.8.x rails libraries that are shipped with
Instiki
and whatever version of stuff is in my Gems directory.

On the flip side, the version of Instiki I have has trouble with the
–daemon option and can’t be run the way I needed it too. I’m so
glad I was able to add a few lines to its startup script to inject
the fix right into the code where I needed it.

James Edward G. II

On 5/3/06, David P. [email protected] wrote:

unit tests in Ruby because they can be impacted by Module/Class load
sequences.

But of course in the Java world there are never any incompatibilities
in different versions of libraries. I can take a Java 1.1 compiled
application and run it fine in the latest Java 1.5.whatever. Sun and
IBM and Microsoft Java VMs all run in exactly the same way. No one
could ever have a older JAR file on their CLASSPATH which causes a
normally fine application not to run because of library differences.
Since it isn’t always obvious over the email medium, I’m being
sarcastic.

Then of course in the C++ world there are plenty of problems with DLL
incompatibilies as well.

So, in other words I think your above example, while certainly an
annoying situation, is not a valid argument against Ruby being used
for big applications. Any application that relies on external
libraries can have problems like this.

Ryan

On 5/3/06, David P. [email protected] wrote:

… Compound this with the the lack of namespaces …

What support for namespaces would you like to see beyond the current
ability to put class definitions inside modules? I always looked at
that as pretty much equivalent to package statements in Java.

Ryan,

If you turn on the verifier for class loading, any incompatible
libraries
get flushed out very, very early in the application run cycle.

This compares very favorably to some 3rd party module magically changing
the
behavior of String, Object, Module, or Class in such a way that makes my
application behave unpredictably. Because Ruby Modules can and do
change
system classes or my classes (and may change the order in which they do
so
depending on load-order), there is a lot more problems than a method
call
signature changing or method functionality changing. Compound this with
the
the lack of namespaces and no errors being generated if my class Foo
comflicts with another class Foo (hey… we’ve got 1 class with a lot of
methods… let’s hope the method names don’t collide) you’ve got an
unpredictable mess.

Thanks,

David

On 5/3/06, Mark V. [email protected] wrote:

On 5/3/06, David P. [email protected] wrote:

… Compound this with the the lack of namespaces …

What support for namespaces would you like to see beyond the current
ability to put class definitions inside modules? I always looked at
that as pretty much equivalent to package statements in Java.

selector namespace will help in the future…

On 5/3/06, David P. [email protected] wrote:

[snip]

The consequences of this is I’m screwed.

[snip]

Hi David,

I’m fairly new to Ruby. Do you think a ruby option, maybe something like

ruby -w --very-strict

would be worthwhile?

—John

All the things you mention unit tests not handling James? That’s where
Functional and Accptance tests come in.

The fact that Instiki doesn’t work under lighttpd is a poor test of if
you
should recommend ruby. I would not be hard to find 10 apps in every
language that don’t work in certain environments their creators didn’t
plan
for. Time consuming yes…but not hard.

Sorry to go off on you, but your argument is the same argument that people
used to claim that C++ was better because developers managed memory rather
than having the machine manage memory. Machines are better than developers
at managing memory. Machines are better than humans at enforcing rules.

I don’t see your post as going off on me at all. I think you’re making
pretty much exactly the same point i did in both of my posts…only more
verbosely.

As- i said

the question at hand is should undiciplined, or just poor
quality, programmers be handed a language as dynamic and flexible as Ruby
or something that limits their ability/options to do stupid things, like
Java
or Ada?

Java and Ada just have more “guard rails” as you put it. I never claimed
any
language was “better” or the right choice. But i did claim that using a
language with more restrictions was probably a better choice for less
disciplined/experienced/good developers, which it seems you did too.

-Kate

Kate,

On 5/3/06, kate rhodes [email protected] wrote:

Java and Ada just have more “guard rails” as you put it. I never claimed
any
language was “better” or the right choice. But i did claim that using a
language with more restrictions was probably a better choice for less
disciplined/experienced/good developers, which it seems you did too.

No, that is not my point. My point is that the dangerous parts of a
language should be more difficult to access or at least be wrapped in a
way
that makes explicit that the dangerous features are being used (see the
example of C#'s ‘unsafe’ keyword which allows developers to access C/C++
style pointers from a managed language.)

This is not a discussion about the discipline of developers. It’s a
discussion about the complexity of software and the difficulty for
anybody,
no matter how skilled they are, to manage that complexity. My premise
and
argument is simple… in order for Ruby to grow from a tool used by
small
teams to build small to medium sized projects into an enterprise class
environment, it must make available a series of tools/functions/etc.
that
allow better management of the complexities of huge systems.

On Wednesday 03 May 2006 2:53 pm, David P. wrote:

The reason that Instiki doesn’t work under FastCGI because the class load
sequence running under FastCGI is a different sequence than the class
loading sequence under WEBrick. Because the classes are loaded in a
different order, some of the metaprogramming stuff that’s happening done
“wrong” and thus Instiki doesn’t work. If a pretty uncomplex system
(Instiki is not very complex) is so very fragile and subject to problems
because of the order classes are loaded into the environment, this problem
will just get worse in complex systems.

You keep using this an an example of a Ruby problem. It’s not a Ruby
problem.
It’s not a language problem. It’s an application problem, an Instiki
problem.

In this case, Instiki needs to be fixed, not Ruby.

Kirk H.

I have to disagree David. In my opinion this is just a case where a
programmer did something a little funky (metaprogramming) and didn’t
write
sufficient code to check that his funkyness was always inserted
correctly.

A great example is servlet code in java… some things are completely
different in Jetty than they are in Tomcat. Put a webapp written with
one in
mind and there’s a decent chance it’s going to break in the other
because
the programmer made assumptions about the environment. This is just like
instiki’s developer making the assumption that it would be run under
Webrick. Does this mean that you can’t recommend Java either? If so
you’ve
got some problems because we can bring up very similar examples from
pretty
much any language. If not, i think you should rethink your decision
against
Ruby. It may still not be appropriate for you clients but…

-Kate

Kate,

I don’t think you understand the underlying issue in the post. It’s not
that Instiki doesn’t work… you’re right… that’s not uncommon.
It’s WHYit does not work.

The reason that Instiki doesn’t work under FastCGI because the class
load
sequence running under FastCGI is a different sequence than the class
loading sequence under WEBrick. Because the classes are loaded in a
different order, some of the metaprogramming stuff that’s happening done
“wrong” and thus Instiki doesn’t work. If a pretty uncomplex system
(Instiki is not very complex) is so very fragile and subject to problems
because of the order classes are loaded into the environment, this
problem
will just get worse in complex systems.

Put another way, Ruby programs can break each other because they can
change
behaviors of the system and/or my classes. This makes Ruby programs
unpredictable, especially in moderately complex systems. Unpredictable
are
not testable. Programs that are not testable cannot be put into
production
in environments such as insurance, financial services, etc.

Thanks,

David

Kate,

I’m sorry, but please, go back and read my posts. I love Ruby. I think
Ruby is awesome. There are parts of Ruby that need improvement. Some
of
these things need to be improved/fixed before Ruby is ready to compete
with
J2EE or .Net for enterprise systems. The reason I am spending a lot of
time
hammering on this issue is that I believe Ruby should be the next
language/system that captures developer mindshare like Java did 10 years
ago.

One of the things that needs improvement is protection against meta-code
breaking applications. This is not an issue of a programmer calling one
set
of APIs vs. another set. This is an issue of the order in which the
classes
were loaded impacting the execution of the code.

In Java (unless the developers have used AOP), I know that no matter the
order that my classes are loaded, the code will execute the same way.

In Ruby this is not the case. Because classes patch other classes, the
order in which the patches happen impact the code path. In the case of
running Instiki under WEBrick vs. FastCGI, the EXACT SAME LIBRARIES are
used. However, they are loaded in a different order and that load order
is
causing some methods to behave differently. The analogie to running an
app
under Tomcat vs. Jetty doesn’t hold. This is not about making calls to
different implementations of the same interface. This is an issue that
the
order in which the classes are loaded impacts the way the classes work.
That level of unpredictability is very, very bad.

Once again, please read all my posts rather than branding me a Ruby
hater or
mischaracterising the Instiki instance of the problem as a “you’re using
2
different libraries” issue.

I am a Ruby lover and as a Ruby lover, I am working to make Ruby a
better
environment for more people.

There are problems with Ruby that make is not ready for enterprise
systems.
These problems have fixes. Admitting there are problems and admitting
that
Ruby needs to make it into the enterprise will help to address things
rather
than having Ruby wind up in the heap of “coulda-been” systems like Lisp,
SmallTalk, Objective-C/NextStep/Interface Builder, OS/2 (okay, I hated
OS/2,
but many thought it was great), etc.

VB, Java, C++, and maybe PHP made the grade. Let’s figure out how to
get
Ruby into that club rather than the SmallTalk club.

Hopefully without interrupting quite an interesting discussion -
I think my question has been answered.

Sadly, my friend can’t do anything about the particularly poor
programmer
in his team because that programmer is the “lead developer”. He is lead
developer because he has been there writing terrible code for so long.

Even more sadly, I will stop recommending Ruby for that environment
because
I imagine that enforcing some discipline should at least control what
comes
out of the bad code even if the internals are incomprehensible and the
results likely to be wrong in many circumstances.

I just have a hard time accepting that we can’t just all program in Ruby
all the time! I have tried using IRB as a shell! I am eagerly awaiting
QtRuby
for Windows! I wish I could somehow load Ruby into my little ARM
processor
based embedded devices and kiss C and Assembler goodbye! (ie. in 32k of
RAM!)

So then my only remaining hope is that at some point we’ll have
“Razelle”
and
then I will be happy:

:wink:

David, aren’t you a bit new here to be making friends this badly
already? :wink:

On May 3, 2006, at 4:58 PM, David P. wrote:

One of the things that needs improvement is protection against meta-
code
breaking applications. This is not an issue of a programmer
calling one set
of APIs vs. another set. This is an issue of the order in which
the classes
were loaded impacting the execution of the code.

Obviously, this is your opinion. I think it’s pretty clear from this
thread that it’s not a popular opinion, but really the only opinion
that matters in this instance is that of Matz. I’m pretty sure I’ve
seen him say that Ruby is meant to trust the programmer to do the
right thing multiple times in the past, so I wouldn’t hold your
breath waiting for the patch.

In Java (unless the developers have used AOP), I know that no
matter the
order that my classes are loaded, the code will execute the same way.

In Ruby this is not the case. Because classes patch other classes,
the
order in which the patches happen impact the code path.

I have no idea what you are saying here. It honestly sounds like you
are making things up now. I’m pretty confident the order Ruby loads
code is a well defined process. Please show us some sample code.

I am a Ruby lover and as a Ruby lover, I am working to make Ruby a
better
environment for more people.

I would believe that a lot more if you had patched the Instiki
issue you supposedly found. Why don’t you school us on the issue so
we can go fix it for you.

James Edward G. II

On 5/3/06, James Edward G. II [email protected] wrote:

I’m pretty confident the order Ruby loads code is a well defined process.
Please show us some sample code.

I think the core of what David is talking about comes down to this
point:

$ cat foo.rb
class Foo
def quux
“This is one definition”
end
end

$ cat bar.rb
class Foo
def quux
“This is another definition”
end
end

$ cat baz1.rb
require ‘foo’
require ‘bar’
puts Foo.new.quux

$ cat baz2.rb
require ‘bar’
require ‘foo’
puts Foo.new.quux

$ ruby baz1.rb
This is another definition

$ ruby baz2.rb
This is one definition

So the execution of the code (“the code” being to everything excepting
the require statements) is dependent on the ordering of the require
statements.

In a simple case like this, it’s easy to say “just make sure you
require them in the right order”. But, guessing from David’s
description, webrick and fastcgi are doing their own requiring –
Instiki is not doing the requiring, and David’s code is not doing the
requiring – in different orders which is causing this problem.

This just reiterates the need for two libraries be very careful
about extending any code from foreign libraries. Otherwise, you get
people stomping on each others feet.

So I agree with David about his analysis of the situation – this
shouldn’t be happening. It’s not his fault, and it might not even be
instiki’s fault (don’t know).

I disagree however with the solution. I don’t think that this is a
fault of Ruby for allowing this toe stomping, but of the authors of
the libraries that aren’t playing nicely together. If you are going to
release a module as a library and that module plays with the internals
of other modules, be very careful and document! And even if you
think you’re only “extending” a module by adding a method not in the
module’s original implementation, assume you’re actually replacing an
existing method and act accordingly – you don’t know when someone
else, including the author him/herself in a future version, might also
want to use that method name.

Jacob F.

On May 3, 2006, at 5:56 PM, Jacob F. wrote:

def quux

$ cat baz1.rb
require ‘foo’
require ‘bar’
puts Foo.new.quux

Luckily, Ruby does warn me there is a problem, as long as I use
warnings:

$ ruby -w baz1.rb
./bar.rb:2: warning: method redefined; discarding old quux
This is another definition

James Edward G. II