|
|
||
Evan Summers's BlogCommunity: Java Tools ArchivesPlumber's Hack 2: Blog o' warezPosted by evanx on September 06, 2006 at 02:42 AM | Permalink | Comments (6)
So i wrote this warez to parse my articles in "poor text format" and generate my desired output, eg. HTML for my weblog, with syntax highlighting. Another feature is switching between online image URLs, and local offline image files. There's a GUI interface, for previewing the HTML. This could be used as a tool for syntax highlighting and escaping Java and XML snippets, to cut and paste into your blog entries. Read the full article on java.net CVS. Ssh ssh, Show me the warez Here is the Web Starter...
Which looks like this...
The code for the above demo in the quitewriter package on vellum.dev.java.net, but moving to quitewriter.dev.java.net. The main class to run the GUI is quitewriter.gui.QuitewriterGui. Other Reading Material
Last week, in Swing and Roundabouts 1M: Emission DTs,
we implemented a publish/subscribe message bus, for dialogs and such.
Plumber's Hack 1: Highlighting SourcyPosted by evanx on August 09, 2006 at 01:07 AM | Permalink | Comments (5)Grid Bag Grease introduced a Gbc.java convenience class, and a Sourcy sample app that used it. Here is the formal introduction to that Quite Sourcy thing.
It just trivially post-processes the output from Netbeans "Print to HTML" into a non-CSS format, using some "search and replace" commands. In particular, it changes span tags from referring to a CSS style eg. class="java-keywords", to using an embedded style attribute, as follows.
private String process(String line) { line = replace(line, "java-keywords", "color: #000099; font-weight: bold"); line = replace(line, "java-string-literal", "color: #99006b"); line = replace(line, "java-layer-method", "font-weight: bold"); line = replace(line, "java-numeric-literals", "color: #780000"); return line; } private String replace(String line, String className, String style) { String replacePattern = "class=\"" + className + "\""; String replaceWith = "style='" + style + "'"; line = stringHelper.replaceAll(line, replacePattern, replaceWith); return line; } Here is the Quite Sourcy launcher.
You'll get the following screen.
You can try to cut and paste the contents of the HTML output file produced using Netbeans 5
"Print to HTML" into the Source tab,
then press Process. The output will be written to the Output tab,
and from there you can cut and paste it into your blog.
The source code for Quite Sourcy is in
vellum.dev.java.net.
Soon, its dependent aptfoundation classes will move across to
aptfoundation.dev.java.net,
and Sourcy will move to
quitewriter.dev.java.net.
Swing and Roundabouts 5: Quite Gooey will present the pack of simple foundation and
helper classes used for building the above Web Start demo, and more. I've been having
far too much fun lately implementing some Quite Gooey helpers with beans binding by convention,
and validation and configuration by annotation, and so this is shaping up to be
a helluva long article, packed full of Web Start demos :)
Hey, in case you missed it, you can check in with
Trip and Tick 3
on using cvs.exe to kick off a java.net/Netbeans project. If you don't already have
your own sandpit on java.net, then c'mon, it's playtime! And if you haven't played
around with Netbeans' Matisse GUI builder, then you are in for quite a treat :)
Credits: Icons by everaldo.com.
Trip and Tick 3: Setting up a new java.net/Netbeans project using CVS.exePosted by evanx on August 03, 2006 at 09:55 AM | Permalink | Comments (0)
I dunno if it's just me, but the few times i've tried to setup a new java.net project, that is to get my Netbeans project/source and the java.net CVS married and checked in, i seem to struggle for hours. But no more! Today we gonna make it happen in 5 minutes or die trying, goddammit! The trick is, we gonna add a command-line CVS client to our arsenal to beat Netbeans to the punch, if it comes to that, which it does. I downloaded a cvs.exe from ftp.gnu.org via cvs.nongnu.org. So if you got any code of your own lying around, c'mon, let's do this! First request a Java project (it's quick and easy), which will get created right away, but only be visible by yourself until it's been approved. Incidently, this might take anything from a few days to a few weeks. Ample time to tell All Staff the good news that the crown jewels are going opensource ;) Incidently, i wrote an article on opensource licenses, called CDDLing up with Sun, to explain to myself the diffferences between GPL, MPL, ASL, and CDDL, so...
We use our command-line cvs client to checkout the new java.net project into our CVS projects directory. In this example, the java.net project is vellum (as in vellum.dev.java.net) so substitute vellum with your own project name. And USER with your java.net username.
cd /projects cvs -d :pserver:USER@cvs.dev.java.net:/cvs co vellum dir vellum Since it's a new project (on java.net), all it will contain is a www directory. We need to make a src directory, which we do, and we need to add that to the CVS, which we do, using our cvs client.
cd /projects/vellum mkdir src cvs add src Our cvs client will look at the CVS/Repository file to get the repository, so we don't need to specify it as before ie. -d :pserver:USER@cvs.dev.java.net:/cvs. Now if we look at the CVS/Entries file, it will reflect both the www and src directories.
And we can browse the CVS source on our java.net project page to see that it's there too. Supoib! Now that we have a source directory, we can create a Netbeans project, and specify this source directory.
My project properties are as follows, where as you can see, the CVS/source for the project is off a projects subdirectory, and netbeans project files are in a separate nbprojects directory, because i like to keep these separate.
When things go wrong, we might use cvs remove to remove stuff from the CVS (after you have deleted it locally). Also, we can use cvs update to recover stuff from the java.net CVS that we've deleted locally (and haven't yet done a cvs remove on). When things go really wrong, just start from scratch by removing your project directory eg. /projects/vellum, and checking it out again... Remember, that whenever you create a new file or directory (in the command-line) you have to do cvs add on that file to get it into the CVS. And whenever you delete something, you gotta do a cvs remove on it to get it out of the CVS. That's what's great about IDEs, that they keep track of new and deleted (and renamed) files, and handle all this CVS drudgery for you :)
Now we need to copy our source into this src directory, assuming we have some source for the new project already. If the source is "tainted" by CVS directories from before, then we first make it "pristine" by searching for any old "CVS" directories and deleting them all. For example in Windows Explorer, we search for all files containing "CVS" in the file name, Ctrl-A to select them all, and Delete. Then we can drop our "CVS-free" source tree into our src folder, make sure the project compiles, and then get our IDE to do a "cvs commit" for us, to add all these "new" files it finds to our CVS java.net repository. But as a rule do a "cvs update" before committing. Then Netbeans knows for sure that all these new files aren't in the CVS repository yet.
Our Netbeans and java.net projects are now forged into "one ring to rule them all"
:) And we can forget about cvs.exe... till next time.
Trip and Tick 1: Checking out a java.net project using NetbeansPosted by evanx on July 07, 2006 at 08:59 AM | Permalink | Comments (5)I got an email on Friday from a chap in Italy asking where he could find a document on how to run aptframework in Netbeans, which is like pressing not one but two or three, of my JButtons simultaneously, and which has led to me to writing this blog article. I'm sure he'll be watching Italy in the World Cup Final this weekend, rather than doing anything else, but anyway here goes. Let's say you hear about a project that is hosted on java.net, and you go to its home page eg. http://aptframework.dev.java.net. You'll see something like the following.
With any luck there'll be a link to some screenshots, which the project owner might have uploaded into "Documents & files" under the "Project Tools" tab. That's very nice, but you'll quickly discover that projects on java.net are all about the code. Happily, you can browse the source in the CVS using "Version control - CVS". Some projects put a Webstart "Launch" button on the home page. Supoib! (Catch the episode when Bart Simpson works for the mafia, to see how to pronounce "superb" as "supoib" heh heh.) I really must read up on JNLP and do the same... see Trip and Tick 2! If you aren't a member of java.net, well that's very easily rectified. Just click on Register at the top right of the above page to get the following.
Now in Netbeans, you go to the CVS menu, and choose "Checkout..." and specify the following CVS root, with your own java.net username and password of course.
Then you specify the project name as the module, and the directory where you want to check out projects to, eg. to your home/projects directory.
The default suggestion is $HOME/nbprojects or something like that. In Windows, that would be C:\Documents and Settings\USER\nbprojects. Personally i like to keep my CVS code, and Netbeans project file directory separate. So i use a projects subdirectory for the code checked out from CVS, using Netbeans or some other CVS client. And later we can specify a separate nbprojects subdirectory for the Netbeans project files, when we create the project after the code has been checked out. Alternative directory names might be cvsprojects for the code, and netbeans for the Netbeans project files. In UNIX these would be off your home directory, and in Windows in your Documents and Settings. Incidently, if you also use Eclipse, then your code will be in your Eclipse workspace directory, and your Netbeans project files in nbprojects. And you can happily switch between Eclipse and Netbeans in this case, eg. to use Netbeans' Mattise or Profiler. Back to the game. It might take Netbeans a minute or two to check out all the sources into the chosen directory. Then Netbeans prompts us to create a project from the checked out sources. This is just like prompting us to select "New Project..." in the File menu.
We give the project name, and our netbeans project folder for this project, eg. off nbprojects.
We specify our "existing sources" as the src directory we have just checked out, as follows. We can ignore any other directories, eg. www is the project home page, and nbprojects is a Netbeans project directory, maybe checked in by mistake long ago, in a land far far away...
Finally, we select the class to run in the project properties. We right-click on the project name in the Projects window, and choose Properties, the last item in the project menu, and the following dialog pops up.
Our source folder has already been selected, so nothing to do here. We click on the Run category, and select the main class to run, as follows. In the case of the aptframework demo, it's ZViewContext.
Finally we press F6 to compile and run! Actually this will compile and run the currently flagged "Main Project" of those projects you have open in the Projects window. You right-click on the project and select the "Set Main Project" to flag that project as such. The Main Project name then goes bold. Otherwise you can right-click and select "Run Project" to run a project which is not flagged as the Main Project.
In the case of aptframework, the demo will popup as follows.
The next article in this series will be "Trip and Tick 2: JooJ up your project page with Netbeans' JNLP tool." Update: You can check out the demo without checking out the code using the following Web Starter :) Refactoring TranslationsPosted by evanx on May 26, 2006 at 05:20 AM | Permalink | Comments (3)
That means moving strings, like exception messages, into a resource bundle. I had some fun with a phased approach, which I present here.
The first phase was moving the string literals in the code into a "message class" as below.
public class IMessage {
public static String systemErrorLogin = "~ logging in";
public static String systemBusyCommunicatingWithServer = "Communicating with the server...";
public static String systemErrorOccurred = "An error has occurred";
public static String systemErrorOccuredFormatTilde = "An error has occurred while %s";
public static String systemSendOpLogoffReq = "~ sending logoff message";
public static String systemUpdateError = "~ updating application";
public static char systemLoginMnemonic = 'L';
public static String[] periodOptions = {"Today", "Yesterday", ...};
...
}
Note that we allow different types in the message class, ie. char for mnemonics, and string arrays for combo boxes. (Incidently, in the above example, we use a notation where a tilde at the beginning of exception messages is substituted with "An error has occurred while..." It's lazy, and that's what I really dig about it, man! The application code becomes "stringless" as follows.
public void run() {
try {
login();
} catch (Exception e) {
e.printStackTrace();
gui.showExceptionDialog(e, IMessage.systemErrorLogin);
}
}
By the way, this is in keeping with my "Bean Curd" blog, where I argue that "string references" (eg. resource bundle keys in this case) hinder refactoring, and so we should aim for applications with "no string references attached."
The second phase is to generate the resource bundle from this message class. We use the field name as the key, and use reflection to generate the resource bundle as follows.
public void generateResourceBundleContent() throws Exception {
IMessage messages = new IMessage();
for (Field field : IMessage.class.getFields()) {
// iterate through all the fields in the message class
String key = field.getName();
Object value = field.get(messages);
if (field.getType() == String.class) {
// output a regular string message
logger.println(key + " = " + value);
} else if (field.getType() == String[].class) {
// output a string array, eg. combo box items
String[] array = (String[]) value;
int index = 0;
for (String string : array) {
logger.println(key + index + " = " + array[index]);
index++;
}
} else if (field.getType() == char.class) {
// output a char, eg. a mnemonic
logger.println(key + " = " + value);
}
}
}
In the above method, we generate the content to be cut and pasted into our resource bundle file eg. myapp_en.properties. Note that we handle string arrays by appending an index digit to the key.
public static final Map<String, String> resourceMap = new HashMap();
public void loadMessages() throws Exception {
for (Enumeration<String> it = resourceBundle.getKeys(); it.hasMoreElements();) {
String key = it.nextElement();
String value = resourceBundle.getString(key);
resourceMap.put(key, value);
}
logger.exiting(resourceMap.size());
}
So now we gonna load the resource bundle messages into our messages class (which is otherwise still initialised to the original English strings). We use reflection, as follows.
public void configureMessages() throws Exception {
IMessage messages = new IMessage();
for (Field field : IMessage.class.getFields()) {
// iterate through all the fields in the message class
String key = field.getName();
Object defaultValue = field.get(messages);
Object resourceValue = null;
if (field.getType() == String.class) {
// we are looking for a regular string message
resourceValue = resourceMap.get(key);
if (resourceValue == null) {
throw new IRuntimeException(field);
}
field.set(messages, resourceValue);
} else if (field.getType() == String[].class) {
// we are looking for an array of strings in this case
String[] defaultArray = (String[]) defaultValue;
List<String> stringList = new ArrayList();
for (int index = 0;; index++) {
String string = resourceMap.get(key + index);
if (string == null) break;
stringList.add(string);
}
if (stringList.size() != defaultArray.length) {
throw new IRuntimeException(field);
}
resourceValue = stringList.toArray(new String[stringList.size()]);
field.set(messages, resourceValue);
} else if (field.getType() == char.class) {
// we are looking for a char resource
String resourceString = resourceMap.get(key);
if (resourceString == null || resourceString.length() != 1) {
throw new IRuntimeException(field);
}
resourceValue = resourceString.charAt(0);
field.set(messages, resourceValue);
}
}
Note that in the above code, if an entry is found in the resource bundle that is inconsistent with the messages class, eg. an unrecognised key, or different length string array, then an exception is thrown. This should be performed as a unit test. Anyway we will know as soon as we run the application if our resource bundle is not as it should be (via an exception).
An advantage of the message class approach, is that it enables unit testing of our resource bundles. For example, we can easily test that every one of our messages (as declared in the message class) is translated in our resource bundles, as follows.
public void test() throws Exception {
IMessage messages = new IMessage();
for (Field field : IMessage.class.getFields()) {
String key = field.getName();
if (resourceMap.get(key) == null) {
throw new IRuntimeException(key);
}
}
}
The above code sample is over-simplified, but hopefully illustrates the point.
public void emitMessagesCode() throws Exception {
for (String key : resourceMap.keySet()) {
String value = resourceMap.get(key);
logger.println("public static String " + key + " = \"" + value + "\";");
}
}
public void installGerman() {
IMessage.systemError = "Eine Störung trat auf";
...
}
This first phase enables us to ensure neat and consistent naming of the keys we use to reference messages. For example, we can readily rename the message keys using IDE refactorings, to correct spelling mistakes and inconsistent naming conventions. The next phase is to generate the master resource bundle from the message class. We use reflection on the message class to generate the key/value pairs, which we cut and paste into the master resource bundle file. After this stage, the resource bundle can be translated into multiple languages. At startup, the application loads the resource bundle for the current locale, and uses reflection to configure the message class from the resource bundle. This offers a mechanism to ensure that the resource bundle is consistent, ie. there are no strings that remain untranslated. In general, I argue that source code should contain no string literals whatsoever! The reason for this is that string literals are typically fragile references, which are not refactorable. This applies to strings that refer to field or method names as discussed in my earlier blog "Explicit Reflection", and string references to properties, as discussed in "Bean Curd (Chapter 1)". (Strings used in OR queries will be discussed in an up-coming blog, "Bean Curd 2: Native Query Beans.") Clearly strings that are text messages are also undesirable, because they should be externalised for translation (in resource bundles). And finally string references to externalised messages in resource bundles, are fragile and unable to be unit tested, and consequently dangerous, eg. getString("loginError"). So I think that covers all the evil strings that we might find lurking in our code? Let's root them out and banish them forever!
My Postscript Punt for today is... "Bin Bash Java (Chapter 1)." And not "Swing trounces Ajax" as usual ;)
Bin Bash Java (Chapter 1)Posted by evanx on May 24, 2006 at 01:37 AM | Permalink | Comments (4)
In the preceding blogs "Java is all you'll ever need" and "A Fool's Errand" I alluded to using Java for "small tasks" eg. file/system tasks, rather than shell scripts. I promised to present some examples along these lines. This is Chapter 1 of many, and presents a basic design. We'll thrash it out in subsequent chapters.
My motivation for trying to move away from shell scripting (or using some other scripting language like python or groovy), in favour of writing "tasklets" in Java, are as follows.
A typical task is backing up our computer, so let's consider this one of our first goals. OK, this could take a while. Hopefully we'll achieve this goal in subsequent chapters. Doing a good design here would be a great start.
Of course our "framework" should be reusable for other tasks, besides the backup one. And very convenient to use. So that some day soon, we can write all our file and system tasks in Java, and never look back, woohoo!
Let's create some helper classes, eg. TFileHelper for handling files, and TProcessHelper for handling processes. And we will create a TTaskContext which exposes our "library" to our tasklets, and/or can be used as a superclass by our tasklet classes. Note that I've choosen the letter T to prefix our "tasking" project classes. This avoids any potential namespace conflicts, and makes it clear which classes are our new ones. To give us some flexibility, let's create our own classes to represent files and processes, namely TFile and TProcess. We will extend those eg. TDir and TZipFile from TFile. First let's design our file helper class. (Note that I'm using abstract declarations to highlight the interface at this stage, rather than the implementation.)
public class TFileHelper {
public boolean exists(TFile file);
public boolean isDirectory(TFile file);
public void remove(TFile file);
public void removeIfExists(TFile file);
public void removeDirectory(TDir directory);
public void moveToTrash(TFile file);
public void moveToTrashDirectory(TDir directory);
public TDir createDirectory(TDir directory);
public void copy(TFile file, TFile destination);
public void copyOverwrite(TFile file, TFile destination);
public List<TFile> listDirectory(TDir directory);
public List<TFile> listDirectoryRecursively(TDir directory);
public List<TFile> findRecursively(TDir directory, String pattern);
public TZipFile zipRecursively(TFile ... paths);
public TZipFile openZipFile(TZipFile zipFile);
public String getDigestString(TFile file);
public boolean equalsDigest(TFile file, TFile otherFile);
}
That's just for starters. We can expect this class to grow a lot!
Next let's design our process helper class.
public class TProcessHelper {
public void kill(TProcess ... processes);
public boolean killAll(TProcess process);
public TFile pipe(TProcess ... processes);
public TFile exec(TProcess process, Object ... args);
public List<TProcess> getProcessList(TProcess ... processes);
public TProcess fileWriter(TFile outputFile);
public TProcess fileReader(TFile inputFile);
public TProcess gzipProcess(TFile gzipFile);
public TProcess tarProcess(TFile tarFile);
public TProcess xargProcess(TProcess execProcess);
public TProcess findProcess(TProcess execProcess);
}
The file reader and writer processes above would be used for redirection, eg. the file reader as the first argument in the pipe(), and/or the file writer as the last, as follows.
processHelper.pipe(findProcess, grepProcess,
xargProcess, gzipProcess, fileWriter);
As you can see, we are loving Java5 varargs :)
For convenience, let's introduce a superclass for our tasklets.
public class TTaskContext {
public TFileHelper fileHelper = new TFileHelper();
public TProcessHelper processHelper = new TProcessHelper();
public TCalendarHelper calendarHelper = new TCalendarHelper();
public TDir toDir(String dirName);
public TFile toFile(String fileName);
public TProcess toProcess(String processName);
}
Let's slide this baby into gear and start putting rubber to road.
So let's imagine what our first backup tasklet implementation might look like, eg. for zipping up our home directory on Linux.
public class BackupTask extends TTaskContext {
@TArgument TDir targetDir = toDir("/home/evan");
@TArgument TDir archiveDir = toDir("/backups/evan");
@TArgument String zipBaseFileName = "evan";
public void run() {
String timestamp = calendarHelper.getNumericTimestamp();
TZipFile zipFile = fileHelper.zipRecursively(targetDir);
zipFile.setOutputDirectory(archiveDir);
zipFile.saveAs(zipBaseFileName + timestamp);
}
}
Ok, so if we wanna write tasklets like the above, we still gotta bit of work to do. It's gonna rock tho, innit. So you spotted those annotations. The idea is that our framework could prompt for those eg. if not specified on the command-line...
So we gonna use annotations to tell the framework what it needs to know to provide a "tasklet container" with a management console in future maybe. Now we're talking! I'm getting way ahead of myself here, but let's dream on... This "management console" could have a Swing interface, and/or a web interface.
On the other hand, a web interface would be quick and easy for administering remote boxen, eg. backing up our media center in the lounge using our laptop. Even on a local machine, having a web-based console for tasks would be handy. You know what, I just decided we gonna embed a web server into our tasklet framework. So that our tasklets are always remoteable, and deployable via a single self-contained jar... OK, I better stop, I'm getting too excited here!
Like when you are reversing your car towards a wall, you find out very quickly when you've gone too far. Rather that than driving in the wrong direction for hours on end, and not knowing it. Let's hope for accidents of the former "loud and clear" type, rather than misdirections of the latter, later type. In the next chapter, we might refine this design before we kick off, so please post comments to that effect. Then we can start rolling up our sleeves to implement some of the file IO functionality. Uh oh, sounds like work. So we'll google and cut and paste. We are developers after all, with a limited amount of time, so the less code we actually write the better, innit ;) Update. Check out NailGun which aims to obviate the start time of the JVM, eg. for Java command-line tasks. They say, "Java has an extensive and robust core API and huge number of available open source libraries. It's a great big hammer, making almost any programming project look like a nail." :)
Postscript. Here's punting my blog "Swing thumps Ajax" again. Check it out, dog.
A Fool's ErrandPosted by evanx on May 19, 2006 at 02:44 AM | Permalink | Comments (5)A reader commented to my blog "Java is all you'll ever need" that "anyone thinking he needs only a single tool to do any job is a fool." That would be me. So lemme introduce you to this fool's errand...
I have my favourite Java Leatherman with me, and so I gonna leave my Python Army Knife at home. Bash is written in C. Clearly it could be rewritten in Java. But let's not do that, let's write a better bash. And rather than a scripting language, let's just write a framework and library. Even if not as concise as a purpose-built scripting language, our approach will have the advantage of being able to leverage tools like Netbeans and Eclipse right off the bat to write our "scripts." And that is no small thing in my book. My main argument against bash, python, perl, C et al, is very simple and personal. Just that they are not my favourite language, programmable using my favourite IDE. That is, they are not my personal favourite programming tool. When I was at school in the 1980s, my first big pet project was writing a 4GL in Basic. A scripting language of sorts. I spent years on that thing. I was emulating my father because he wrote 4GL language tools. When i discovered C, everything changed. Now rather than write a new scripting language, you would just write a new framework and library, because C let you do that. And Java has made that truer than it ever was with C.
But Java (like any language) let's us write a library to support writing tasks, so that we can approach the brevity of shell scripts, without the downsides of shell programming. And with a big upside if Java/Netbeans is your favourite hammer and so you want everything to start looking like a nail. So watch out for my blog in the next few days titled "Bin Bash Java (Chapter 1)." As you can surmise, it's the first in a series. It's the beginning of a journey, to create a library so that I can say goodbye to my bash scripts and do some serious "scripting" on Windows too. I hope to meet you along the way!
Update. This blog continues over at "Bin Bash Java (Chapter 1)". Also Check out NailGun which aims to obviate the start time of the JVM, eg. for Java command-line tasks. They say, "Java has an extensive and robust core API and huge number of available open source libraries. It's a great big hammer, making almost any programming project look like a nail."
Java is all you'll ever needPosted by evanx on May 15, 2006 at 02:16 AM | Permalink | Comments (9)In his blog, Damien Katz wrote on "Signs you are a crappy programmer, and don't know it." At the top of the list is "Java is all you'll ever need." Since i'm guilty of that, here is my response - why i choose not to add other languages to my toolbox. So you have some system task to do. This is where you jump into vi and hack together a bash, python or perl script to accomplish this task in quick (and dirty) way, right? This first problem for me is that this means leaving my Netbeans environment. These days I'd rather go to the dentist for root canal than do that. Like most people, I guess I don't like going to the dentist. It does have one advantage though, which is if you aren't enjoying your job, you can schedule the dentist in the late afternoon and leave work early. Which i did regularly one year, when i wasn't enjoying my job, and had to go to the dentist a few times for a nagging pain. For my perly whites. Yes, I was using Perl at the time, and vi. So I'd be in that dentist's chair, with the drill screeching in my ears, and thinking, "Ah, what a pleasure not to be at work right now!"
So I choose Netbeans, to build up a library of support classes for various archetypes of tasks, eg. system tasks. This sharpens my skills in Java in different elements of the standard libraries, eg. System and Runtime. And it keeps me "thinking in Java." I'm obsessive compulsive about code. Happily Netbeans lets me rename things, to keep my code "clean." Writing in python and C, I get an immediate dentist reaction to lazy and legacy programming conventions, like abbreviations and underscores. I've had that sore tooth removed so that pain would never come back. Incidently, C# is shaping up well for system tasks, with the C# .Net command-line in Vista. Hopefully the Java community will get a similar thing via Groovy at some point. In a large company, every engineer and programmer might choose their own favourite language, to automate various tasks. Very soon you end up with an unmanaged and unmanageable environment which is held together with prestuck and sticky-taped scripts, written by ex-employees, in every language you've heard of, and some you haven't.
And a great way to encourage employees to write overview documentation (in addition to javadocs) is to have a technical company newsletter or blog - and incentivise and reward submissions, with gift vouchers, public praise, and "get out of the dentist's chair free" cards - you know, the important things in life! But LAMP hackers are real men and use vi innit. They don't want or need an IDE, or strict conventions. The problem is that in large teams, some programmers are veteran gurus of the system, while others are one-month newbies (which might be future veteran gurus, or otherwise working for your competition). Now those newbies want IDEs, to navigate the (javadoc'ed) code with ease, to be prompted with method names, etcetera. And you, the CIO, want to help them help you - show them the Netbeans! Having those fantastic hackers that Paul Graham waxes lyrically about, is great, until they leave the company to go and work for Google. And leave fantastically terse, undocumented code, behind. To make their newbie replacement's life a spaghetti hell for a few months. Time for the dentist! Another thing Damien mentions, is cutting and pasting. I think that API's, and superclasses and such, should be blindingly simple. Because it's difficult to predict how you might want to (re)use them in future. So if you build in functionality you need for your current problem, that might render that superclass unsuitable later, for a different unforeseen case. And in trying to change that superclass, or API, you tend to break older code that has been working fine. So cutting and pasting can serve to isolate code, to make it safe from the rug being pulled out from under it later. An (over-engineered) superclass or API, that is great today, might be a sore tooth tomorrow...
Update. Check my blog "A Fool's Errand" which follows on from this, and introduces an upcoming series "Bin Bash Java" inspired by this blog entry.
Netbeans Day (South Africa) Part 1Posted by evanx on May 05, 2006 at 10:26 AM | Permalink | Comments (0)Health warning: the italic text is just me rambling and so should probably be skipped.
As agreed with my mother (the one with the car), i was up at 7am so as to be ready to leave at 730. (My mother was up at 5am for gym - mentil!) So I dropped mom at her office and kept on trucking through to the "Sandton Convention Centre" in her car. Traffic wasn't as bad as i had feared (being a provincial boy from quieter south african coastal towns like Durban and Cape Town), and the venue and its parking were perfect. After registration i enjoyed the coffee and muffins on offer, especially seeing as I didn't recognise anyone, like former colleagues - i felt like i knew no one, probably because i didn't. I was really looking forward to the "opening keynote" by James Gosling. I hadn't noticed it was just a 15 minute "intro" (I had missed the preceding two "Sun Tech Days" where he gave his main keynote and talks i guess) but still it was great to see and hear the father of Java, even if only for a short while. The speakers were Geertjan Wielenga (from the Netbean's Prague office i presume), Chuk Munn Lee, and Sang Shin, a Java evangelist from Sun. Geertjan Wielenga's first talk was entitled "What makes Netbeans Best?" The salient points (for me) were:
Geertjan Wielenga's second talk was entitled "Plug-in Development and Rich Client Platform" - read Part 2 for that.
In Part 3, I'll cover Sang Shin's talk "What makes Netbeans the best IDE for Java EE Development?" - the last installment in this series on Netbeans Day (South Africa).
| ||
|
|