Posts Tagged ‘programming’
Review: Agile Development With Rails, 3rd Edition
Agile Web Development with Rails: A Pragmatic Guide by Dave Thomas
My rating: 4 of 5 stars
In general, this book does a fairly good job of helping you create a rails-based application. Part 3 includes some great in-depth information on the topics that are briefly discussed in Part 2.
I only have one real gripe about this book. It packs in lots of topics (e.g. db theory, AJAX, unit testing, security, deployment), but it doesn’t really tell you much about them. Therefore, if you have a problem, then good luck figuring it out using the content in the book.
A good example is the final chapter which covers deployment. The chapter devotes only a few small paragraphs to configuring Apache for passenger. To me, this section was completely useless unless you were already an expert with Apache configuration. I ended that chapter with a broken Apache server and no resources (from the book) to begin fixing it.
Another problem that I had with that chapter is that it really didn’t follow the pattern that the chapters in Part 2 used. In those chapters, the authors would should you how to do something relatively small, show you how to test it, and then provide some troubleshooting information if the task was particularly complex. The deployment chapter gave you a *very brief and generalized* tutorial in each section, and then just assumed that everything went perfectly. It didn’t show you how to test anything, and it didn’t help you troubleshoot any possible problems.
Don’t get me wrong. I know that no book will provide all of the information that I would ever need about a subject, and thank goodness for the internet in these situations. I was just hoping that all of the chapters in a book that I actually bought would provide better information than some person’s blog.
So in general, I guess I would have to say that this was a very good book with some bad chapters that were tacked-on at the end.
Testing The Waters Of Jruby & JDBC
I was recently tasked with writing a command-line script in Jruby that performed simple CRUD operations against a simple database table. I’ve written tons of scripts in the past that manipulated tables, but I had never done so using Jruby. I therefore decided to first write a “bare-minimum” test script that would help me dip my toes in this unfamiliar water.
I wanted to write my test script against a database manager that ran on my laptop, but I didn’t want to go through the hassle of installing and configuring Oracle or MySql. Also, I soon learned that a lot of Ruby database drivers don’t work with Jruby, so I needed a small, simple database that had a good JDBC driver. I ended up installing and configuring Apache Derby, and it worked out very well for me.
So anyways, here’s the script (jdbctest.rb):
require 'java'
require './derbyclient.jar'
require './derbytools.jar'
# This example assumes that you have the free DerbyDB software installed on
# your machine. It also assumes that you are running it in "server" mode by
# executing the startNetworkServer.bat script.
# This is what I'm using instead of Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance()
import 'org.apache.derby.jdbc.ClientDriver'
connString = "jdbc:derby://localhost:1527/MyDbTest"
conn = Java::JavaSql::DriverManager.getConnection(connString)
stmt = conn.createStatement
rs = stmt.executeQuery("select * from derbyDb")
while (rs.next) do
puts "#{rs.getString("NUM")} -- #{rs.getString("ADDR")}"
end
rs.close
stmt.close
conn.close()
I then placed the jdbctest.rb script in a folder with the derbyclient.jar and derbytools.jar file, and then executed the script like this:
c:\Dev\jruby\somefolder>jruby .\jdbctest.rb 180 -- Grand Ave. 1910 -- Union St.
To make this script work, you need to do the following:
- Install Derby using this tutorial: Step 1 – Install Software
- This is a very simple task that took me all of 6 minutes after downloading the software.
- Create the MyDbTest database and the derbyDB table using this tutorial: Step 2 – ij Basics
- You should also populate this table using the SQL located under the Execute SQL Statements section.
- Once you’ve created and queried your table using
ij, start your Derby server using this tutorial: Step 4 – Derby Network Server- You should validate the server using
ij. Please see the Test network server connection with ij section in the Step 4 tutorial for help.
- You should validate the server using
Please note that this might seem like a lot of work, but it’s really very simple, especially when you compare it installing and configuring most relational database managers. It took me about 20 minutes from A to Z, and I had no prior experience with Derby.
That’s it! I hope that this tutorial helps a few other people who want to get started with Jruby and JDBC.
Web Development Toolbox
A friend of mine recently volunteered to update and maintain a web site for a local non-profit. He basically wants to clean up the formatting on the site (using CSS whenever possible), add more rich media such as flash-based slide shows, and make it more collaborative by adding features like a forum.
Of course, since he has a day job and is doing this in his spare time, he would like to accomplish all of this in a way that is inexpensive, relatively simple, and intuitive for a technical professional who isn’t a web designer.
Since I’ve been in his shoes before, he asked if I knew of any tools that could help him build a professional-looking site easily and inexpensively. Here’s what I came up with, and hopefully it will help other technical professionals/hobbyists get started with web development.
Software
Firefox + Firebug
A vanilla instance of Firefox itself isn’t an inherently superior browser for web development over IE or Opera. Once you add Firebug, however, it turns into the best free web application development environment that I’ve ever seen. Here are some of the things you can do with Firebug:
- Find which HTML snippet maps to which element on a web site by hovering over the snippet
- For me, this is the best feature
- View the document’s HTML or CSS as a tree
- Debug Javascript
- Edit HTML and CSS in memory so you can test-drive the addition or removal of features.
- et cetera
Honestly, this tool easily saved me half of my web development time. It’s worth checking out, even if you’re a dedicated IE or Opera user.
Note: Apparently, there is also a scaled-down version of Firebug that works with Internet Explorer. More information can be found at the Firebug home page.
XAMPP
XAMPP is a “distribution” of web server software that is configured to work very well together, out-of-the-box. It includes Apache2, PHP, MySql, Perl, phpMyAdmin, and a bunch of other things that I’ve never even had any time to use. It’s simply an excellent way to set up a server-side, LAMP development environment on Windows in a hurry.
A Decent Text Editor
There are a lot of integrated development environments (IDE’s) that do a pretty decent job of helping you create robust web sites. Eclipse, for example, has a highly-regarded PHP plugin, and Netbeans has a robust set of “Ruby On Rails” plugins. If you’re working on a very complex web site, or you don’t use a decent text editor on a regular basis, then you’ll probably save time with a decent, free IDE.
However, if you are already using a decent text editor (e.g. Jedit, Vim, Emacs, Textpad, Textmate, etc.) for other tasks, then you should look into using them for HTML editing too. Your favorite editor probably has some excellent plugins to help you write code using HTML, JavaScript, PHP, etc.
The main benefit of using a familiar text editor over an unfamiliar, web-centric IDE is the size of your learning curve. Most IDE’s, while powerful, can be difficult to master. Also, IDE’s usually force you to manage your project in “the Eclipse” way or “the ASP.Net” way, which may be very different from your normal process. A good text editor, however, should already be very familiar to you and flexible enough to allow you to manage your project in a way that works well for you.
This isn’t to say that IDE’s are a bad idea. Just keep the text editor option in mind if you find your IDE to be too bloated, expensive, or difficult to use.
HTML Tidy
HTML Tidy is a great command-line utility for validating web pages. You can use it to automatically format your HTML, but I mostly use it to validate my web pages and point out any mistakes I may have made (such as forgetting to close a tag).
Online Resources
Open Source Web Design
Here are the two hardest tasks for most technologists (sysadmins, programmers, etc.) who aren’t dedicated web developers:
1. Designing the look of the web site
2. Implementing the design
This should be evident by what they wear, but it’s worth stating: most technologists are not good at tasks that require visual creativity. If you need someone to write an efficient sorting algorithm or trace some packets, then they’re the people to call. Designing a clean, good-looking UI, however, is something that most technologists simply can’t do.
And that’s just half the story. Even if the technologist can create a good design on paper, it’s even harder to actually implement the design. CSS is great, don’t get me wrong, but it has a huge learning curve, and just enough browser-based idiosyncrasies to drive you nuts.
In comes the Open Source Web Design project to the rescue. This site has a repository of page designs and the CSS files that implement them, all for free. Just browse the designs, download the ones that work best for you, and your 95% along the path of creating a solid, attractive web site.
Alertbox
Ok, now you site looks pretty good, but it’s just a shell of its future self. It needs content and customization, which brings up a lot of questions. Does my web site need an RSS feed, or should I just use a mailing list? Will a bunch of dancing, AJAX-y crap bring in more traffic or will it just frustrate my users?
Jakob Nielsen’s Alertbox answers questions like this using two guiding principles: usability and quality content. Your site should be usable by your target audience, and it should contain the content that they need. Anything that is contrary to these principles should be avoided at all costs.
Of course, that sort of thing is much more easily said than implemented, so Jakob does tons of research on the subject and then publishes a lot of his results on his web site. Check these out if you want to do a better job of connecting with your “customers”, whomever they may be.
Dead-Tree Resources
Now that I think about it, I’ve only cracked open one actual book on fundamental web design. Not surprisingly, there’s a wealth of information available on HTML, CSS, Javascript, and other web technologies online. If you do need some help with CSS, however, I highly recommend Eric Meyer On CSS. It’s easy-to-read, succinct, and packed with loads of useful examples.
Itty-Bitty Classes
How I learned that using objects, even in a small script, can make you more efficient and you software more flexible and effective.
The Problem
Between work, home, and about a half-dozen operating systems, I use a lot of different backup programs. Most of these programs use some sort of snapshot-based process where you have multiple full backups, each representing a different snapshot in time. The backups have to be rotated on an arbitrary basis, using a process that looks like this:
- Compare the current number of snapshot folders with the intended number. Delete folders, from oldest to newest, until the total number of folders equals the intended number minus 1.
- In practice, this usually means deleting the oldest folder, whose age is indicated by an index number in its name.
- In reverse index order, rename each snapshot folder so that it’s index number is incremented by 1.
Here’s how it looks in the shell if you only want two snapshots:
$ ls -i # dirs with inode numbers 17706835 snapshot.0/ 19108205 snapshot.1/ 21109296 snapshot.2/ $ rm -rf ./snapshot.2 $ mv snapshot.1 snapshot.2 $ mv snapshot.0 snapshot.1 $ ls -i 17706835 snapshot.1/ 19108205 snapshot.2/
As simple as this process sounds, I wasn’t able to find any cross-platform scripts that would execute this process on an arbitrary set of snapshot directories. I therefore decided to throw something together myself, and figured it would take me all of 20 minutes. It actually ended up taking me a bit longer, but the entire experience was worth it.
Which Language?
As much as I wanted to hammer something like this out in a 15-line bash script, I saw three big disadvantages:
- Bash scripts aren’t cross-platform
- Cygwin doesn’t count
- Cygwin doesn’t count
- Integration Methods
- The most popular method of integrating a shell script with something else is using things like pipes, streams, and channels (STDIN, STDOUT, STDERR). This method of integration is very robust and mature, but I’d rather not have it be my only option. Being able to load this functionality into another program as a library with a robust interface would also be nice.
- Ease Of Maintenance
- Most of the non-trivial shell scripts that I’ve ever written or used are comprised of numerous “clever” awk, sed, and grep statements that, while powerful, are difficult to write and even more difficult to maintain. I would therefore prefer using a language that relies less upon “shell magic”.
I’ve been a big fan of Python for a while now, and I’ve written numerous sysadmin scripts using that language, so I decided to use it to solve my problem. I guess I could’ve used a lot of other languages, but this time, Python seemed like a good idea.
Iteration 1 – The Procedural Approach
Ok, so that language decision took way too long (at least 3 minutes), and I really wanted to hammer out this script, so I started hacking. Python is an OO language, but I didn’t have time to design classes and build constructors and such, so I started writing a very procedural program.
Note: One of the cool things about Python is that it gives you a choice between writing your program in an OO way or a procedural way. This is especially handy (like in this case study) when your “simple” procedural script turns into something more complex that would benefit from some of advantages of object-orientation.
I got to my rotate_snapshots method, which started out like this:
import re, os, sys
from distutils import dir_util
def rotate_snapshots(root_dir, snapshot_prefix, num_snapshots):
# Retrieve your folder list
files = os.listdir(root_dir)
dirs = []
for f in files:
if os.path.isdir("%s/%s" % (root_dir, f)):
# I probably need to do some sort of validation here, but
# that can wait for rev 2
dirs.append(f)
Ok, I have my folder list. So far, so good. Now I need to delete the unwanted directories (which is usually just the oldest one). Here’s my first stab at satisfying that requirement:
### Delete dirs requirement
dirs.sort()
# Grab the index number from the folder's name
pattern = re.compile('.*\.([0-9]{1,10})$')
# Walk through the list of dir names backwards
for dir in reversed(dirs):
try:
index = int(pattern.search(dir).groups()[0])
except:
# *not* a snapshot dir
continue
if index > (int(int(num_snapshots)) - 2):
# Delete unwanted snashot dir
dir_util.remove_tree(root_dir + '/' + dir) # Delete the dir
dirs.pop() # Remove it from the list of dirs
else:
# Done looping through unwanted snapshot dirs, drop out
break
Here’s where I ran into my first snag. This code chunk sorts my directories by name, walks through the list backwards, and if it finds a directory with an index that is too high, it deletes it. Once it finds an index that it wants to keep, it falls out of this loop.
The problem is that this code chunk relies upon a list that sorted by the integer value of the indexes. What we get, however, is a list that is sorted by the string value of the snapshot directory’s name. This is how it looks in the python shell:
In [1]: l = ['dir.1', 'dir.2', 'dir.3', 'dir.10']
In [2]: l
Out[2]: ['dir.1', 'dir.2', 'dir.3', 'dir.10']
In [3]: l.sort()
In [4]: l
Out[4]: ['dir.1', 'dir.10', 'dir.2', 'dir.3']
^^^^^^
Since Python assumes that I’m sorting a list of strings, it places 10-19 before 2. This is ok if you never need to work with more than 10 snapshot directories, but that’s not an assumption that I want to make.
I could just loop through every directory name and delete the unwanted snapshot directories. That’s a little inefficient, but it’s easy and it fixes the problem right? Well, yes, until I then try to rename the snapshot directories. For that operation, it’s absolutely necessary that my list of folder names be sorted based on the index value. I can’t rename dir.9 as dir.10 before I rename dir.10 as dir.11, for example.
Ok, remember that my mind is still in “hammering it out” mode. “Ok”, I thought. “I’ll just sort the list myself with my own algorithm”. And that’s when I moved to my next phase of development.
Iteration 2 – Epiphany
“Why on earth am I manually sorting a list in Python?”, I thought. Python is a very robust language that is easy-to-use. It has all types of cool functionality built-in so that I don’t have to do things like sort arrays. “There’s got to be a better way”, I thought.
Then I remembered that each Python class has a cmp method. This method is invoked when one Python object is compared to another using something like the == operator, for example. I could create a snapshot directory class and override the cmp method so that my objects could be compared by their numeric index, not their full name. Then sorting my list would simply be a matter of invoking the sort method on a list of “snapshot directory” objects.
This, of course, is when the “hammering it out” part of my brain kicked in. “What do you mean you want to create a class?”, I thought. “We already established that that would be way too much work”. After thinking about it for a minute (and pondering why my inner-monologue just said “we”), I realized that it’s also a lot of work to write and test my own algorithm for sorting lists of snapshot directory names. I therefore decided to give the OO approach a stab.
Iteration 3 – OO Is Easy (In Python)
To get started refactoring my script, I first tried to come up with a list of nouns and verbs so I could design my classes and methods. This is usually the part where most procedural programmers run screaming, but it doesn’t have to be that bad, especially on small-to-medium-sized projects. I promise that you won’t have to read a Martin Fowler book or open a graphical modeling tool in a lot of cases
Ok first I looked at the 2-step process listed above, and found that I basically have the following entities:
- Noun(s)
- snapshot directory
- Verb(s)
- delete directory
- rotate/move directory
That’s it. Based on that “analysis”, I threw together the following stub in my module:
class SnapshotDirectory:
"""Docs go here
"""
def __init__(self, full_dir_path, snapshot_dir_prefix):
self.dir_path = full_dir_path
self.prefix = snapshot_dir_prefix # Use for validation
# TODO Validate directory
self.__is_valid = True
# TODO Get index value
def __cmp__(self, snapshot_dir):
"""Override __cmp__ so we can compare directories based on index value,
not string name.
"""
pass
def isValid(self):
"""This returns true if the directory still exists on the filesystem."""
pass
def deleteSnapshot(self):
"""Delete the snapshot from the directory."""
pass
def changeIndex(self, new_index):
"""This renames the directory with a new index number."""
pass
Ok, here’s a quick summary. The __init__ method is like a constructor, and it’s where I parse and validate values and set initial property values. The __cmp__ method is where I will set up my comparison criteria. Everything else mentioned earlier except for the isValid method. I thought that this might end up being a handy helper method. Overall, the entire process of designing and stubbing-out my class took less than 10 minutes, which ain’t bad, especially when you compare it to Java.
Next, I wanted to implement my __init__ and __cmp__ methods. Here’s what I came up with:
def __init__(self, full_dir_path, snapshot_dir_prefix):
if os.path.exists(full_dir_path) == False:
raise Exception("Could not find the full_dir_path: %s" % full_dir_path)
self.dir_path = full_dir_path
self.prefix = snapshot_dir_prefix
pattern = re.compile('.*\.([0-9]{1,10})$')
try:
self.index = int(pattern.search(self.dir_path).groups()[0])
except:
raise Exception("Could not retrieve index number from directory.")
self.__is_valid = True
Ok, that’s simple enough. Validate the directory and retrieve the index number. Now let’s look at the cmp method:
def __cmp__(self, snapshot_dir):
"""Override __cmp__ so we can compare directories based on index value,
not string name.
"""
if isinstance(snapshot_dir, SnapshotDirectory):
return cmp(self.index, snapshot_dir.index)
else:
return cmp(self.index, snapshot_dir)
Methods like this are one of the reasons that I really like Python. In 5 lines of code (not counting comments), I’m able to enable index-based sorting. No muss, no fuss, and definitely no implementation of my own sorting algorithm.
Note: Another great thing about Python is interactive interpreter. It’s great to be able to instantly test your code after you’ve written it.
I then implemented the rest of the methods (plus a few others) and an Exception class called SnapshotParsingError. A dedicated exception class might seem like overkill to non-Python developers, but it only requires two lines of code, and I didn’t even have to create a new file.
Here’s the code for the two classes:
class SnapshotParsingError(Exception):
pass
class SnapshotDirectory:
"""This class represents a "snapshot"-style (dirprefix.index) directory on a filesystem.
Example:
sdir = new SnapshotDirectory('/home/tom/backups/snapshot.1', 'snapshot')
This class throws a SnapshotParsingError exception if the snapshot
directory doesn't follow the 'dirprefix.index' naming convention.
"""
def __init__(self, full_dir_path, snapshot_dir_prefix):
if os.path.exists(full_dir_path) == False:
raise SnapshotParsingError("Could not find the full_dir_path: %s" % full_dir_path)
self.dir_path = full_dir_path
self.prefix = snapshot_dir_prefix
pattern = re.compile('.*\.([0-9]{1,10})$')
try:
self.index = int(pattern.search(self.dir_path).groups()[0])
except:
raise SnapshotParsingError("Could not retrieve index number from directory.")
self.__is_valid = True
def __cmp__(self, snapshot_dir):
"""Override __cmp__ so we can compare directories based on index value,
not string name.
"""
if isinstance(snapshot_dir, SnapshotDirectory):
return cmp(self.index, snapshot_dir.index)
else:
return cmp(self.index, snapshot_dir)
def __repr__(self):
return self.__str__()
def __str__(self):
retval = """
self.dir_path = %s
self.prefix = %s
self.index = %s
self.__is_valid = %s""" % (self.dir_path, self.prefix, self.index, self.__is_valid)
return retval
def isValid(self):
"""This returns true if the directory still exists on the filesystem."""
return self.__is_valid
def deleteSnapshot(self):
"""Delete the snapshot from the directory."""
dir_util.remove_tree(self.dir_path)
self.__is_valid = False
def changeIndex(self, new_index):
"""This renames the directory with a new index number."""
pattern = re.compile('(.*\.)[0-9]{1,10}$')
path_prefix = pattern.match(self.dir_path).groups()[0]
new_dir_path = path_prefix + str(new_index)
os.rename(self.dir_path, new_dir_path)
self.index = int(new_index)
self.dir_path = new_dir_path
Ok, now that my classes are written and functionally tested, I can rewrite my rotate_snapshots method:
def rotate_snapshots(root_dir, snapshot_prefix, num_snapshots):
"""Please see module-level help for details about how this function works"""
files = os.listdir(root_dir)
dirs = []
for f in files:
if os.path.isdir("%s/%s" % (root_dir, f)):
print "Found the following dir: %s" % f
dirs.append(SnapshotDirectory(root_dir + "/" + f, 'snapshot'))
dirs.sort() # It works!!!
if len(dirs) > 0:
while dirs[-1].index > (int(int(num_snapshots) - 2)):
print "Deleting dir: %s" % dirs[-1].dir_path
dirs[-1].deleteSnapshot()
dirs.pop()
dirs.reverse()
for dir in dirs:
print "Incrementing the index of %s by 1" % dir.dir_path
dir.changeIndex(dir.index + 1)
else:
print "No directories are available for rotation"
Ok, here’s some of the differences between the previously-attempted version of this function and the current version:
- The new one is a lot clearer. The class constructor takes care of validation, the sort method works, and, in general, it’s just really easy to read. I barely even added any comments because I didn’t think they were necessary. If I come back to maintain this thing in a year, I’ll definitely know what’s it doing.
- It’s shorter than the previous version would have been, which is also nice.
- I realize that the creation of a class probably adds more total lines of code to this script, but that’s ok if it means less code duplication and easier maintenance.
Conclusion
So that’s how I learned to stop worrying and love OO Python. Even in small scripts, it can really make the task of programming easier, faster, and more flexible.
Also, please note that the code chunks in this script are alpha-quality and incomplete. When I’m done writing this script and have tested it for a little while, I’ll post it to this site.
Groovy For Sysadmins
I’ve been using the Groovy programming language a lot lately at work to programmatically interact with systems that have Java interfaces. Simply put, it’s great, and it really makes my job as a sysadmin of Java middleware easier. Also, if you’ve tried other Java-based scripting languages like Jython in the past but have been disappointed (like me), then I definitely recommend that you check Groovy out.
I think that the admin angle of the language is lost on most potential users, however. Groovy is a great language for writing small-to-medium-sized administrative scripts, and it’s even a great language for non-”real” programmers who want to start dipping their toes into the pool of Java. For those who are considering whether they want to put in the time to learn a little about Groovy, here are some of the advantages that I see as a sysadmin:
No More Compiling & Building
First of all, if you’re still compiling your Java apps using javac, then stop reading this article and start using Apache Ant. You’re wasting your time with javac, even if most of your scripts are pretty small. Ant is a great tool that has saved me a ton of time, but it’s definitely not without it’s own learning curve and occasional problems, however.
With Groovy, there is no explicit compilation step, just like with Perl and the Korn Shell. You just write your script, run it, fix and problems, run your script again, and then rinse and repeat if necessary. This is a much more intuitive programming workflow for most sysadmins.
Easier Deployments
If your script is going to eventually run on a server, all you have to do to deploy it is to upload it to the server. From there, you can run it like any other Perl or shell script. You don’t have to worry about writing or deploying wrapper scripts for your class or jar files that actually invoke your program.
Simpler Syntax
Here are some of the syntactic niceties offered by Groovy:
- Like Python and the Korn Shell, Groovy doesn’t force you to end every line with a semi-colon if it only contains a single statement.
- Loose typing, so you don’t have to declare a variable’s type when you create it.
- Fewer brackets
- No forced classes
- In Java, every file is explicitly defined as being a class. You don’t have to do this with Groovy.
- Multiple Classes In One File
- Tired of following OO design standards that force you to create 8 separate class files for a relatively simple program? Put them all in a single file in Groovy and simplify your life.
- More features that I’m just now discovering like closures and Javabean-like accessors.
Text Editor Friendly
I was reading a blog article by a Sun developer the other day where he said that he didn’t like Groovy because it didn’t integrate very well in Netbeans (an IDE). He mentioned that there was no decent code completion module for Groovy yet like there is for Java. It therefore took him longer to write the following print statement in Groovy:
println "hello"
…than it did to write the equivalent (and much longer) statement in Java with the help of code completion:
System.out.println("Hello");
Although this statement is a little short-sighted in my opinion (“I don’t like cars because there’s no place to hook up my horse”), it points out one of Groovy’s strengths: it can be used very well with only a text editor and a command prompt. Groovy, like Perl and shell languages, was never designed with whiz-bang IDE’s in mind. It’s brief, powerful syntax and development tools were designed to make programming with it so easy that you could do it using Notepad and the command prompt if you wanted and still be very efficient and effective.
Groovy’s ease-of-use outside of an IDE is good news for most sysadmins for a couple of reasons. First, they spend a good portion of their days using text editors to do things like view log files, change config files, et cetera. Being able to use the same text editor to also write scripts lowers the learning curve and is very synergistic. Also, most sysadmins usually don’t have IDE’s like Eclipse or Netbeans installed on their system. For the type of Java programming that they typically do, they view IDE’s as being bloated and having an unnecessarily high learning curve.
Groovy Shell
One of Python’s greatest strengths is the fact that it comes with an interactive interpreter. Groovy also includes an interactive interpreter, and its major benefit is that it allows you to evaluate small snippets of code quickly and easily. This comes in handy when you’re having problems getting a chunk of code to work, and also when you’re “kicking the tires” on a new third-party library or language feature.
Conclusion
There are a lot of new scripting languages out there that are Java-based, and their potential benefits are numerous. However, it can be difficult to pick one that is worth the time and attention necessary to achieve proficiency. In my opinion, Groovy fits the bill and then some, and is especially good for people who need to write small-to-medium-sized programs that interact with Java systems.

