Saturday, January 31, 2009

Gravitor

When I go to conferences, I find myself with little I can do work-wise, but surrounded by tech stuff. With nothing billable to do, I can't help but direct my free energy towards obsessively working on some pet project.

This time it was Gemini, a game engine in JRuby and powered by Slick and Phys2D that David Koontz and myself were working on. We wanted to make a lot of the done-to-death things we see aspiring game developers rewriting all of the time. Too often, everyone spends time recreating the technology, but not doing anything interesting with it. This even includes 3D/Game engines such as Ogre3D, jMonkeyEngine, CrystalSpace, etc.

While at RubyConf08, my goal was to create a complete game, front to back, with Gemini. Obviously, it wasn't going to be a AAA title. I defined complete game as a game having graphics, sound effects, music, victory conditions, defeat conditions, and app navigation (menu, playing game, game over screen, victory screen, and the ability to move between all of these).
I was able to get it done, and with only 337 lines of code. I did pretty much all of the graphics by hand. The background is a brush template in SeaShore. I got my sound effects from a couple sites that offer free sound effect files. The music was stuff I threw together from GarageBand, but it's mostly looping tracks that were glued together.



The menu button is cleverly disguised as a black hole

The game has a total of 5 classes. A load state, main state, menu state, game over state, and victory state. Everything else is built with Gemini's GameObject/Behavior system.



Pilot your ship with the Gravitor cannon - a device that emits gravity wells


In Gemini, you have states, which is best thought of as a mode for the application. In the MenuState, menu stuff goes on (starting a game, loading, saving, options). In the PlayState, play stuff goes on (the level is shown, the player is able to play, etc). States are pretty simple. Once you're in the state, you think in terms of GameObjects. You can inherit from a GameObject, and slap a bunch of Behaviors on it. You can also just create a GameObject, and slap a bunch of behaviors on it. I didn't repeat myself just now. You can create a subclass for every kind of thing that shows up in your game, or you can create them more dynamically at the object level.

I'm getting ahead of myself. What's this Behavior business I'm talking about? Behaviors are the most powerful thing in the engine. Behaviors can create methods on the GameObject they will be bound to. Behaviors can even depend on other behaviors. For example, a Collidable behavior will depend on the Spatial behavior. In order for collision calculations to work, the Collidable needs to know where it is in relation to other things. The Spatial behavior takes care of that for us already, so Collidable can just declare that it depends on a Spatial, and the engine will ensure that all Collidable game objects are also Spatial.

Behaviors can also create callbacks for the GameObject. Our Collidable Behavior would add an on_collide method, which takes a block. These callbacks are much better way than the old inheritance scheme for handling game objects, as you can register multiple listeners to a particular event. Performance wise, this is slower, but the focus of Gemini is to be a tool that lets you create games (quickly - although I argue this enables you to create them at all, otherwise you suffer Failure of Greater Ambition). Performance is of secondary concern (although it's still a concern). Hey, this is Ruby. If you want fast, go write it in C or Java.

There's a lot more features about Behaviors, but the last major one I want to go into is the runtime component of them. You can add and remove Behaviors from a game object during the runtime. The monsters in Pac-Man might have an AI behavior that causes them to seek out Pac-Man. Once Pac-Man picks up the power pill, simply remove that AI behavior and add on a Flee behavior. Easy stuff!

I might sell the game one day if I can fluff up some of the graphics and audio, and add a bunch of levels. For now, anyone can grab the game and try it out:

If you're using Linux, just download the Windows zip and use this to execute the app:
java -Djava.library.path=lib/java/native_files -XX:+UseConcMarkSweepGC -Djruby.compile.mode=FORCE -Xms256m -Xmx512m -jar Gravitor.jar

Friday, January 30, 2009

Where is PHP?

$work or die();
PHP was my first memorable experience with a dynamically typed language. In some ways it's hard to compare PHP to my current pet langauge - Ruby. PHP was designed for throwing together simple dynamic web pages, and mostly runs within a web-serving environment. I don't really see people writing desktop or back-end apps with PHP, although I have heard of such things done. Ruby is more general purpose, and before any comparisons are drawn, this needs to be considered against PHP's specific purpose. I'm not going to compare the languages today. I'm more interested in the state of PHP right now, as it compares to Ruby and Ruby's web environments.

PHP is everywhere. Want bulliten board? PHPBB2. CMS? Check out Drupal. Wordpress is PHP. There's some wiki servers that are PHP. PHP has tons of out-of-box solutions. Those in the Ruby/Rails environment should heed this, as I think it's lead to PHP's widespread usage. I know Ruby has a few things such as Substruct, Redmine, and Mephisto, but none are as mature or widely adopted.

The PHP help just isn't there, or so I've heard. I've spoken with an office-mate who is the company's programmer, and has specialized in Cake-PHP. He's writing some software for his company to market (we'll keep this anonymous, I don't know how confidential that talk was), but he's found that it's hard to move forward because he just can't find help. He just recently decided that PHP just isn't the tool for this job, and is going through the pain of learning Ruby and Rails. Picking up a second language can be a little rough, especially when it's on the clock. Also, a lot of the PHP folks I've met are self-learned mostly from looking at snippets and tweaking existing scripts. I think this makes the prospect of learning a language that has a lot of differences and a lot of new libraries a daunting task. My point is that the help must have been sorely needed and absent for him to want to make the switch.

Where did that help go? It was there at one point, but now I'm told it's moved on to Ruby/Rails. Now, I'm not here to say "Ruby is great. Rails is great". I think there's a large community out there that can say that for me. I can't help but think that people are still going to need Wordpress, Durpal, and the myriad of other apps. If the Great Rails Exodus has drained PHP of its ranks, then who is to maintain these legacy applications?

Being a capitalist pig, enemy of wealth-spreaders everywhere, I think it's time to fit PHP onto my resumé. PHP may not be my language of choice, but saying I only can write code in one language at a time seems like a waste of my technical abilities, and thus my ability to make money. On top of that, our company is shifting to focus on providing programming services to Web Designers, who seem to have an easier time finding work than ourselves. Being able to say 'We do PHP, and we do it well' will really help there.

Thursday, January 29, 2009

Dawn of War 2 Beta

An open mind is like a fortress with it's gates unbarred and unguarded.

Last night, I played the Dawn of War 2 Beta. Granted, it's a beta, and there's going to be some problems. Overall, the night was fun, and even my skeptical friends who don't enjoy Warhammer 40,000 as much as myself enjoyed their time. Lots of stuff has changed since Dawn of War 1, so there's lots to talk about.

Steam is used to download the game. Steam doesn't run on Vista without some work. In fact, one of our XP users had some problems getting Steam up and going. I was there when Steam was new, and it was extremely buggy. It's gotten a lot better, but I still see some people who have the same problems cropping up. I think the Steam developers need to look into unit testing. I can expect Vista problems. Vista is a support nightmare for anyone doing desktop development, so Steam is off the hook there. But XP? Sorry, you guys gotta nail down stability issues. That said, when Steam works, it works well. I like installing apps on Steam because it's stupid easy, and Steam remembers all my previous games. If I want to install Half-Life 1, I can do so without digging up the CDs and running all of the updaters.

It was also confusing to one of my friends who was trying to get the game, but just heard about it yesterday. He couldn't find where to get the game anywhere, especially on the Dawn of War 2 site. Some pointers to getting Steam or something else to download the beta would have really helped. Maybe he missed something, I didn't go that route, as I had seen the information in some blog post a while back.

Windows Live! was pretty painless to configure. I already have an XBox Live! account, and the accounts are tied together. That's a win. Little hassle there.

Later on, my fiancé Stacey fired up the XBox just as I was joining today, and she signed into my account so she could watch NetFlix through the XBox/Netflix streaming feature, and I was booted. I was really on a roll that day, so it took me a total of about 3 seconds to figure out what happened. Someone who doesn't write software for a living and hobby might have encountered more frustration. By default the XBox automatically signs in, if I recall, and it would really suck if this had happened if I was in the middle of a game. Windows Live! is still pretty new, and I don't expect it to be super magical. However, my XBox is mostly a really expensive DVD player without being signed in, as games you purchase on the Live! store can only be accessed through your account, and any real XBox 360 games require you to be signed in to save your progress, let alone play the game. This is a problem that Microsoft has to figure out, or Live! seamless integration is a waste. Unfortunately, this affects the Dawn of War 2 experience, since they decided to go the route of Windows Live!

Wow, I haven't even gotten to the game yet.

My laptop (and some other people's rigs that were playing) were really screaming machines when they were purchased about 3 years ago. PC game developers - Either cut the graphics and focus on making the games super fun, or become console developers, where the hardware is dedicated to running a game, rather than running on varied hardware that runs and OS that in turn runs a game. You lose tons of customers because you demand that keep up in an arms race with gaming hardware. Now, we have to give Relic (the guys who made the game) a little break. The game might be missing a lot of its optimizations at this point. I'm going forward with this as the baseline. The game might run better when it's released, or it might remain where it is in terms of performance. Fancy graphics mean little if I can't see them because my hardware wasn't purchased this month.

Dawn of War 2 departed significantly from its predecessor. This is generally a good thing. However, it left me and my cohorts in the dust in terms of understanding what to do. It's not like any RTS I've played before, so we were all trying to do what we could to just figure out what was going on. It would be nice if there was some kind of "What's changed" article out there that I didn't have to Google for. The multiplayer video they released on their blogs was pretty helpful, but there were a lot of very important things that they just didn't/couldn't cover.

Cover is real now! Squads take cover behind rocks and other things, although you need to know how to use it. When moving or attact-moving, you can mouse-over interesting terrain. The terrain will glow, and dots will appear where the squad will take position. I haven't figured out how to tell them to choose a particular angle. It also isn't obvious to me on how well the cover is working, or if line of sight is obscured (units just don't seem to do anything when this happens). This is a big improvement over the area cover that was in the first Dawn of War, where the squad would just sit in a crater and get a bonus. With this cover system, it's possible to get flanked and the cover does nothing. Very tactical, which is what Dawn of War strives to be. Squads can even jump into buildings.

I really like the Heavy Gunners. Every race has a gunner squad of some kind. The gunner has some support characters, so it's not some artillery that's totally useless if the gunner isn't deployed. The gunner needs to warm up to deploy, which is shown by a spinner clock. Once the gunner is deployed, he covers an arc. Woe betied any that enter this arc. The unit becomes surpressed, which is basically a really nasty snare. In the mean time, the gunner just chews up the squad under fire. It's possible to direct which way this arc faces, although this is a cumbersome task that I perhaps do not fully understand yet. It takes time for the gunner to tear down and set up again to face a new direction, so you want to make sure he's facing the right way when he gets somewhere. Also, this gives quick and manueverable units high tactical value, as they can come up a flank and hopefully close the gap before the gunner has time to adjust.

Sim City has been removed as a game mechanism from this RTS! You get one building, which produces all of your units. Very simple! No more hidden upgrade trees. No massive real estate for buildings. No peons to kill! This is one of the best features. It's very hard to destroy the main building too. It has some 30k hit points. Avatars (the strongest unit in the game) have 6000 in comparison. There's a button you can click at any time (or hit f1) that selects your base so you can build stuff. The base is guarded by two strong turrets. I think this is a big win for the more casual players, and takes the focus off of siege and makes it more about units fighting units.

Commanders can't join squads. Joining squads was a nice feature in the first Dawn of War that kept people from assassinating your leaders easily (this is also done in the table-top game). I don't see that you can join up anymore, which is a little disappointing. Maybe there's a good reason for this, but I'm unaware as to why.

Vehicles have rear armor that's very weak. My dreadnought came up behind a looted tank and whacked it once on the rear, and the tank, which was at near full HP, exploded! Fun! The game says "Rear Armor Hit!", which brings me to my next point.

The game tells you what's going on: "Billy's computer is too slow, and is causing lag". "Joseph dropped from the server, and a comptuer player has replaced him". "Rear armor hit!", "Suppressed!". I like knowing what's going on. Obscure icons don't always do the trick for me, and I don't mind the text.

Turtling just got a lot harder. You must control victory points to win. These victory points define the point of conflict for the game. It's nice that the RTS gives a shove, because many new players like to build up their forces before sending them out, or upgrade everything all the way before venturing out of their base.

Equipment upgrades are cool. Heroes can upgrade their equipment, but only have 3 slots. Some of the upgrades can be pretty far out there.

There's three different heroes for each race, which must be chosen before the game starts. I like it. A lot of them don't make sense fluff-wise though. Why is the Apothecary a leader? He's just a medic. Why not a Chaplain? I suppose this is to make the RTS more fun.

Terrain features are mutable. Tanks and walkers plow through cover as if it were nothing. Map-inserted buildings can be leveled. I've even seen a video where a bridge was destroyed, and some squads fell to their deaths. Very cool.

Bolters and Shuriken Catapults sound like they actually hurt now. This was especially bad for the catapults of DoW1, which made me think they had glitter cannons, and were fueled by sprinkles.

Falling back button. Sweet. Just hit the button and the squad will run back to the nearest 'base' (whereever they can reinforce and heal, which happens very fast).

Squads and commanders gain levels. I don't know what this does yet in multiplayer.

Overall, the RTS keeps to the spirit of the table top. They took some freedoms in that it's no longer a RTS translation of the table-top anymore. Perhaps this is for the best, as I don't think it can be all things to all people. RTS developers will be wise to watch where Dawn of War goes in the future. I think they are either making a new genre, or refining the current one to be fun for a lot more people. The beta doesn't go over the co-op campaign, which is of high interest to me. I hope it allows for more than two players. I'll definitely be getting this game before it comes out, and I might get a pre-order (especially if there's an incentive in doing so).

UPDATE:
Earlier I said - When playing Dawn of War 2, I had to set all settings to the lowest possible settings, which makes the game look worse than the first Dawn of War on full settings - And my framerate is higher for the first Dawn of War.
After playing the game a little more, I checked out the graphics settings, and noticed that the game wasn't running on my screen's native resolution. This makes anything look terrible on an LCD screen. Things got much better once I switched resolutions. Thus, I retract my statement above. I still have to run everything at the lowest setting, which makes graphics look less than impressive, but I don't feel like I would have better off with the first series' engine anymore.

Wednesday, January 28, 2009

R.I.P. Cross Platform for Java

It's time Java's proud feature of cross-platform compatibility had a funeral, was carried by six people, and lowered into the earth. For developers, there is no lowest common denominator that they can use that just works everywhere. I found out with JotBot's issues with running on Vista. Even though Vista is easy to blame with all of the stupid problems that is has, I don't blame Microsoft. Instead, I place the blame squarely on Sun and Apple. First, let's start with Vista's problem.

Vista just doesn't run right with Java 1.5. I don't blame them, Vista is new and shiny. It's obvious that things have changed in terms of getting a window on the screen under the hood. Also, Java 1.5 support has been over for some time now, and things work just peachy in 1.6. This gets Microsoft off the hook in terms of fingers to point.

Apple for the longest time has implemented their own JVM, which has to conform to certain specifications laid out by Sun. As a Swing developer, you find out why fairly quickly. There's a lot of bells and whistles that Apple has added, and all of their Swing apps run in the native look and feel unless one is set. There's also some other graphical enchancements. I don't have a problem with any of this. In time, Apple's Java fell far behind Sun's Java. This might not be a big deal. However, Apple's Java is the only Java you can reasonably expect to see on a Mac. Alternatives are other JVMs such as Soylatte and OpenJDK, which I'd only expect to see on a developer's machine.

Right now, Apple has a 1.5 JVM, and a 1.6 JVM. The 1.6 JVM only exists for 64 bit machines. The 1.5 JVM is what is installed on every machine as the default Java, even if you walk into the store right now and play with one of their new fancy machines. You could direct these machines to use 1.6, but people will just got find a different JotBot somewhere else that doesn't require them to admin their machine just to get my $25 app running. This also means I couldn't support 32-bit Macs like mine, which are about three years old. In all practicality, Apple only has the 1.5 JVM out in the wild. The 1.5 JVM isn't supported anymore. The crux is Apple has a dead Java running on it.

As I said above, Sun is to blame as well. Why? Sun implements Java on how many platforms? And they can't do one more? Why not take the reigns, Sun? Apple is dragging your name through the mud, and your users and developers suffer for it while you sit back and do nothing. I can't even run your samples on your tutorial pages for Swing. Is this your vision of Java?

On a somewhat positive note, we found a way to run JotBot on all platforms, and it's essentially by forcing different OSs to run on different VMs, and having special code for different VMs. We have code that runs one way on Java 1.5, and runs totally differently for 1.6. We also only support 1.5 on OS X, while everyone else is on 1.6. This feels like cross platform in the same way that C++ or C is cross platform. I have to code for different nuances in certain sections, and hope that my platform layer is pretty thin.

I don't know if I'm willing to say that small businesses such as mine should steer away from future public product development for Java on Swing, but I would like this to serve as a warning to anyone going off to do said development. I've been a Mac user for some time now, and I'm pretty happy with it. The Java problem is my biggest complaint about using a Mac, and it's seriously effecting my choice on my next laptop that I get, because right now, Java is paying the bills.

Tuesday, January 27, 2009

How to use images and other content in Monkeybars

Images can be used on JButtons and JLabels pretty easily in Netbeans. Just click on the ellipsis (...) next to imageIcon, and find your image. However, this solution isn't very robust. Reading off te filesystem is great and simple, but that may not be an option for an all-jar deployment, such as when using Web Start, or even an updater like GetDown, which I believe only updates jars. Another problem with picking images straight off the filesystem is that I think Netbeans does some odd stuff with relative in absolute jars. In more recent versions, this seems to be getting better, but I still see some odd quirks from time to time.

First off, you have to make some kind of media jar. Rawr handles this, and even includes a sample that's commented in your build_configuration.rb.
c.jars[:data] = { :directory => 'data/images', :location_in_jar => 'images', :exclude => /bak/}


I usually don't do the fancy :location_in_jar stuff myself (I think that's mostly there just to show you that you can do it).
c.jars[:data] = { :directory => 'data', :exclude => /bak/}


Much better. Now run your build task.
jrake rawr:jar
This will build your project, but it will also build a data.jar. You can find this jar inside package/jar. In Netbeans, add this jar to your project's classpath.

For future images, simply drop more images into your data dir, and run your build task to refresh the jar.

Now head back to your form with the image, and hit that ellipsis again. This time you want to pick Image Within Project.
Click on the ellipsis button to the right of the 'File:' (it has a blue boarder in the screenshot above). Then go find your media jar, and pick the file you're looking for.
That'll do the trick! For future images, just stick the jar in the data dir, re-run rawr:jar, and find the image in the jar through Netbeans.

If you need to find images programatically, you'll need a classloader that's not JRuby's classloader (JRuby team, correct me if this has changed). In an all JRuby app, that might be hard to find. Fortunately, Rawr generates a method in the generated Main class that uses its classloader to help you get a resource.

Java::org::rubyforge::rawr::Main.get_resource('my-image.png')

Monday, January 26, 2009

A Weekend Project - Pasting Code Snippets

I submit that the web browser is a double-edged tool. Browsers are very productive, but are also the most distracting application on your machine. They allow us to look up documentation and seek advice and help on certain topics, but every day we are bombarded with YouTube links, web comics, soap-box blog posts, and other things. Inherently, none of these are bad, but when you have to get work done, they just get in the way. On a side note, the browser easily eats up more resources (screen real-estate, memory, processing power) on my machine than any other two applications combined.

One of my goals is to remove the need for a web browser during my work hours as much as possible. Sure, when I need to search for something like an obscure Swing hack to get line numbers to show up next to a text editor pane, the browser is helpful. However, this should be the only reason I fire up the browser. I shouldn't have need for a lingering browser on my machine while I'm working.

This weekend, I used Monkeybars to rapidly knock out an app to eliminate the need for firing up a browser to use sites such as Pastie, RAFB, etc. The web apps are pretty simple: You paste in your code, make sure the language matches, hit submit, and you'll be directed to a page with your code. All spacing is intact, the code is color coded, and you'll even get line numbers. The most important part is that you get a link that you can hand out to folks on IRC, a friend on IM, or even in email. None of these mediums handle code very well in terms of formatting, line numbers, etc. These web apps are very useful, and I use them on a daily basis.

The Monkeybars app really only handles submission, and perhaps even saves a few keystrokes.
Just paste your code into the large text editor show in the middle, and click submit in the bottom right-hand corner.
A few seconds later, the app fills out the small text field above. If you hit the copy button, the app will place the text in your clipboard buffer (the same as selecting all of the text and hitting copy). Then you just paste the text wherever you want. No browser is involved!

Reading other people's pastes would require a browser. However, I contend that you're not looking at a snippet of code that was pasted to you during the entire day. Read the paste, use it, then close the browser. All done.

You can see the submitted code here.

I prefer Pastie and GitHub's Gist, but RAFB didn't care that my app was a bot. Out of courtousy, I need to contact the author at some point to let him know I've made a bot that interacts with his site, but since it's just me using the app currently, it can wait just a little bit.

Sunday, January 25, 2009

Dialogs in Monkeybars

Monkeybars currently has a problem with making an owned modal dialog. Some dialogs need a owner passed in upon construction, and they need a way to indicate that they are indeed modal. To help with this, we added this method that can be overridden in the view:
View#create_main_view_component

All it needs to do is return whatever you want @main_view_component to be. Normally this method takes whatever you have in set_java_class, and calls new on it.

This is great for setting the modal property. However, it does little to allow you to pass in the owner (since you'd need a variable for that). You could use the singleton property on Controllers as a workaround, doing MyController.instance.instance_variable_get(:@__view).instance_variable_get(:@main_view_component), but that's more than a code smell, isn't it?

I've made dialogs modal without a parent, and it works out just fine. I'm not entirely sure what setting the owner does for you.

If you need to throw up your dialog as another event with on_edt, or go off on a thread to do some other things, you can always get the result with a callback instead of waiting for the blocking open to unblock. Enter define_handler:
MyDialogController.define_handler(:window_closed) do |event|
update_view
end
define_handler also exists for Controller instances:

dialog = MyDialogController.instance
dialog.define_handler(:window_closed) do |event|
foo = dialog.result
do_something_with_foo foo
end
dialog.open
...

If you are going the route of dialogs, the easiest thing to do is to go the route of JOptionPane and friends. JOptionPane has a lot of pre-packaged class methods that just throw up a dialog with an icon, title, message, possible input, and buttons for things like yes/no, ok/cancel, etc. JOptionPane can even take a component (which could be a JPanel) where you put together your own input dialog of sorts. I've done this with password fields, because JOptionPane didn't support them out of the box. As much as I like Monkeybars, if JOptionPane gets me a dialog that works in 3-10 lines, then JOptionPane is a better candidate for displaying a dialog.

define_handler works for other events as well, including a button's action_performed inside of another controller! This could be helpful in knowing when to keep controller's states in sync with each other. I imagine a Photoshop like app which has a lot of dialogs and windows floating around would have a large number of define_handlers hooks.

Saturday, January 24, 2009

Fan failure

A couple days ago, the right fan on my MacBook Pro started grinding, buzzing, and even squeaking. Money is really tight right now, this laptop is my only real development ready computer, and combined with the media's constant talk of economic doom and gloom makes for a recipe rich in stress.
My MacBook Pro is a hand-me down, courtesy of one David Koontz, so I don't have AppleCare, which I've heard really good things about from an overwhelming amount of folks in our local Mac-loving Ruby community.
As part of shopping around, I called up Apple's store at Biltmore, and spoke to a cheery rep (an American, I might add) with extremely little wait. Unfortunately, you can't bring your machine into their store for ER so you can work with it the next day. She said at first I could bring it in and have it back in a few hours. I was concerned about the possibility of the job stretching on, so I mentioned that I found that the problem is that the fan is going out. Normally, when I've spoken with any tech services, be it electronic, automotive, whatever, trying to show them that you have an idea of where the problem is has resulted in a non-reply. It's simply ignored. Well done there, Apple (or maybe just that nice rep). Anyways, she mentioned that I might not be able to get it back until Tuesday because they may not have the part in stock. Well, that's a bullet dodged. That didn't work out for me.

I did some searching and found iFixit. They sell Mac parts for stranded folks like myself. I snagged a $5 coupon from Retail Me Not, and for $50-ish I have a fan on the way here. It should be here around... Tuesday. Wait, I could have had a professional work on it and had it by about Tuesday as well. The difference is, I can still use my laptop in the meantime, and I can also save myself some money, because I'm sure Apple is going to run me a bit more than $50 when most tech services have a minimum service fee, and then there's the hardware cost.

But won't my laptop explode if it continues to run? I bought some compressed air from Office Max (it makes you feel stupid like when you buy bottled water), and dusted out both fans. The laptop runs much cooler now, and even when both processessors and the GPU are pegged, the machine doesn't go over 180F like it did. The fans don't have to work as hard, and thus the grinding is now a faint rumble. The replacement fan is on the way, but it's nice to know that this has been a cheap repair.

Oh yeah, and I left out some of those stupid screws that Apple put in. They aren't alan sockets, or phillips or flat head. They are some kind of star configuration. I forgot the name of them. They strip easily, just like phillips... brillant! Anyways, the laptop holds itself together fine without them.

Friday, January 23, 2009

Monkeybars moves to Kenai

Monkeybars is moving to Kenai, project invite courtesy of Charles Nutter. Rawr will be going there shortly as well.

I don't have a lot of time to work on Monkeybars at the moment. The business and paying bills has been more urgent recently, and eats up most of my time. Therefore I can't spend a lot of time getting the project pages all set up and organized, so there's going to be a long transition period. A unified and well known (JIRA) issue tracker is integrated with Kenai, but most importantly there's a Wiki. Some user contributed documentation and samples will really help Monkeybars right now, and we have some users that are eager to post their findings to our Wiki. In this way, setting up a Kenai project saves me time.

One of my complaints about projects like RSpec is that the documentation lives not on their site (their examples are usually very incomplete or very outdated for all but the most trivial uses), but in their developers' blogs. I will blog about new features, and perhaps outline some problems I run into, but I want the wiki to be the authoritive site for Monkeybars docs and samples, not this blog. I may have some samples here, but if it's code you can run from a Monkeybars gem/jar, it'll be in the wiki too (and the wiki version will be more up to date).

Now if only I could find a way to integrate the Wiki with RDoc...

Thursday, January 22, 2009

Do it in the mornings

I've noticed that tasks saved for the end of the night can be kept up for a few weeks, but eventually distractions come up, and you also need to get just that little extra shut-eye for the following morning. The tasks start getting skipped, and then they go away.

Tasks reserved for the morning aren't as easy to skip, if the time is made for them. It's easier to not get disturbed with phone calls, crying babies, friends who need help, and work sessions that went on longer than expected.

My daily blog posts from here on out should show up in the AMs regularly now.

Tuesday, January 20, 2009

Celebrating My New President


This can't be legal

In celebration of the inauguration of my new president, I decided to spend the night admiring my contraband.

Today Barack Obama became my president. I hear a lot of people assume because one didn't vote for him, that one must be doing so on account of race. I think there are some folks out there who are racist, but I also think they are are loud minority. I (and many others I know) voted against him because I disagree with his idea of government's role, financial policy, and most importantly, his stance on guns.

As I recall, he mentioned that we can't stomp on hunters, but we have to keep AKs off the streets (paraphrased). However, his voting record on firearms is what I go by, and I wasn't (and still aren't) convinced.

Contraband you can cling to
To me, firearms are liberty's teeth. They allow lawful individuals to prevent others from using forceful coercion on us that would deprive us of life and liberty. Our Founding Fathers wouldn't have founded much if they didn't have the guns they needed to ward off the Crown. They gave us three means of defending our liberties, way of life, and overall prosperity: The ballot box, the jury box, and reluctantly, our arms. It's why they gave us an amendment for it.

Partly to keep my life simple, and partly because it's very important to me, a firearm stance is deciding factor in how I vote (assuming the position can influence this civil liberty). The Second Amendment defends the others, so it seems logical to focus on defending the amendment itself.

Regardless, I hope Ol' Barry does well, it's my country too.

Monday, January 19, 2009

Monkeybars for other GUI libraries

I just wanted to throw out there that there's very little that stops Monkeybars from being usable in another framework instead of Swing, such as SWT (a very easy addition), to even WinForms using IronRuby instead of JRuby. While myself and the other Monkeybars developers are pretty happy off using Swing due to its capability and compatibility, we'd certainly welcome contribution to make Monkeybars something more folks can use. We could assist anyone making an SWT (or other library) adapter, but we can't write it ourselves.

We have had one JRuby user who really was eyeing Monkeybars, and liked what he saw for a big project he was about to take on. However, the risk of adding an SWT adapter on top of pushing this library which may or may not have panned out for him was just a little too much. I don't blame him for it, but it makes me think there is some demand out there for Monkeybars in SWT, or even something else.

Sunday, January 18, 2009

Monkeybars Videos to Date, and wrapping Swing

David Koontz with Monkeybars 0.5 Screencasts (somewhat outdated, but you can get the feel for it) - scroll to the bottom.

David Koontz with Monkeybars at RubyConf (much more recent!)

Martin Slader on Monkeybars - Also Shoes

There's also a few lightning talks, and a Phoenix Ruby User Group video out there somewhere, although the lightning talks are like 2-3 minutes of video in an hour of video, and I don't think the PRUG video is hosted.

Martin Slader did a pretty good job showing off Monkeybars, and even pointed out pros and cons. One con that Martin pointed out was that Monkeybars does little to wrap or hide you from Swing. I don't think Martin is wrong in saying this, or in any way out of line, but I would like to reflect on the topic a bit.

When writing Swing apps (pre-Monkeybars), we quickly realized that Swing had lots of quirks, and had some really flexible capabilities if we were willing to override the right classes and such (hey, it's Java). We felt that hiding Swing from a MB developer would defeat some of the big advantages to using Swing. Thus, we made the view a 'landing area' for your Swing code, where you jump into all of the gnarly Swing stuff, adding PlainDocuments to your JTextFields, or coercing your model data into something a TableModel could understand.

The beauty of this is that Swing developers jumping into Ruby would be at home in this section. Also, it meant that we could do Swing could do, and there was no need to add any wrapping code. This let us get Monkeybars where it is right now. It also meant that a lot of Swing examples out there (how many years of examples? 10+?) could be used with little transformation.

I concede that this is a mixed blessing. There's no JRuby + Swing for Dummies book that I'm aware of. Ruby developers that come from a PHP background, or just someplace that doesn't include Swing or Java will probably be at a loss. My defense to this is three-fold:
  1. You could use some of the Swing wrapper libs out there in conjunction with Monkeybars, such as Profligacy or Cherry(sp?) to generate the form. You could even use SwiXML + Builder.
  2. Big web frameworks that everyone loves such as Merb or Rails don't hide you from HTML. In fact, they make rendering that HTML as contained as possible, just like Monkeybars does. But hey, that's MVC.
  3. If we wrapped Swing, you wouldn't be able to use things like JXDatePicker from the SwingX library, or other custom components.

Now, bindings might change this a bit. Some Swing quirks might just not be an issue anymore when the correct binding is invoked. However, my goal with bindings is just to make Monkeybars development easier and faster overall, not to wrap Swing. I'd love for as many people to use Monkeybars as possible, but you will always be able to get to raw Swing, and Monkeybars developers will need to know Swing.

Saturday, January 17, 2009

Tighter code/test cycle

I thought I might steal a Rails feature and stick it into Monkeybars - Reloading files after they change. This might be problematic if classes are being reopened elsewhere. Since code can be executed as a class is evaluated, Ruby can do some really powerful things. We use them in Monkeybars for things like set_model, set_view, and the automatic method->event handler creation. The drawback is that classes and code don't just 'exist' in Ruby as they would in Java or .NET. While not always true, require order can make a difference.

I'm not sure how this will work for Netbeans, which seems to copy/compile everything to the dist folder by default. Perhaps the auto-loader also needs an auto-publisher? Either way, I'm sure this feature won't take too long. No implementation of this could possibly be perfect in a Ruby environment, so anyone capitalizing on this feature will need to just restart the app from time to time, and know that any run-through tests against the app could easily be incorrect when editing and auto-reloading.

Thursday, January 15, 2009

Dark Reapers


Death from afar.
I've yet to hear of an Eldar player who didn't see Dark Reapers as useful. At 35 points per model, they'd better be. Their Reaper Launchers firing two shots from 48" at BS 4 S 5 AP 3 let them pulverize heavy infantry without retaliation. You certainly have to keep them protected. It doesn't take long for opposing players to bring their crosshairs upon your expensive yet tender reapers.

Last night, I started and finished my Dark Reaper unit of five. It took me about an hour and a half. I've been applying a Principle of Lesser Ambition (limit the scope of your work so you can actually get it done). Instead of putting in lots of colors (six or more), I just picked three.
All of my models now get the following:
  • A primary color
  • A secondary color
  • A unit color
The primary color is the first color you identify the model with. The second provides some contrast and detail. The unit color provides just detail, and is unique to the units in the army.

My Dark Reapers have the following color scheme:
Primary: Chaos Black
Secondary: Midnight Blue
Unit: Mithril Silver

Black and Midnight Blue (it's really a purple) are standard Dark Reaper colors. Mithril silver is a color used for Necrons. The 'Fluff' (backstory of the game) pegs the Dark Reapers as an aspect of their god of war. This particular aspect is aquired by the god when battling a Necron god. The Necron god explodes, leaving a shard of himself in the god of war. Thus, the god of war is given the aspect of the reaper.

The leader of the group, the exarch, is typically where I reverse the color schemes. The unit color becomes a much more dominant color, and shows the leader's devotion to his men. It also helps the leader stand out more.

The fluff is my favorite part of Warhammer 40K. In the story of the game, war is ancient and undying. Struggle is eternal.

Monkeybars is 1.0

Monkeybars is now 1.0! We haven't actually touched Monkeybars (aside from a few branches) in a while. The API shouldn't have changed much between 6.2 and 1.0. The only thing I think could have changed is how define_signal is handled with the new :name => name, :signal => signal syntax. However, I believe the old form still works, even though it is deprecated.

My hope is to make Monkeybars releases a little more frequently. I also hope to get us a wiki going so some of our eager users can build up some documentation for us.

Over the next few days, I may move some parts of Monkeybars over to Kenai, and get our new logo up.

JotBot Extreme, Part 2

Today, I worked from about noon to 6:30PM. I feel like I worked over 5 hours, but JotBot said I had only done 2.5 hours worth of work. Granted, I could work really hard on limiting my distractions, I may just have to allow myself a little more forgiveness. In the end I'm not charging $200/hr. Perhaps I could bump up to 10 minute intervals, and see how that works for me.

Tuesday, January 13, 2009

JotBot Extreme

Using our company's time tracking tool, JotBot, not only tracks my time, but increases my productivity. Unless you're really in the zone, it's difficult to stay on task for even 15 minutes. Every 15 minutes, JotBot pops up and asks "What did you do in the last 15 minutes?". Fortunately, I don't have to give it a unique answer every time (it uses the previous log entry). Today, most of my entries fell into "Fixing quirks in JTree with CheckBoxes". JotBot groups those together, but I'm sliding off topic.

When this little window pops up, it helps remind me that I'm at work, and that my evil web browser with my favorite webcomic isn't work I can bill for. So I get back to the task at hand, or I simply lose time in my day.

I just watched a full season of 24. It's an awesome series, but there was something I noticed. Many of the characters work in this information hub, where they can search records, look at maps, track phones, and other things a fictional big government crime stopping organization should be able to do. These folks working here really have to stay on task. One person being slow on processing some data might be holding up someone else, and in the end costs folks on the field precious time. In the show, minutes count. It almost seemed like they accounted for every minute they had. I didn't want to go that far, but I wanted to try out the concept...

The last two days, JotBot's popup interval has been speed up to 5 minute intervals. In an hour, JotBot will come up 20 times. This actually keeps me really on task. It's easy for 7 minute to go away when I'm on 15 minute intervals, and then do 7 minutes of real work, and I'll still log the time, because I got something done. Now I can only slack for about 2 minutes, reasonably. The first day it felt really frantic. Today, not so much, but I was still cranking away.

Another added benefit I see to is is that I get stuff done really fast. Over a long period of time, it's easy for those few minutes here and there of slacking and losing concentration to really add up. I think this is why we, as developers, often are incorrect in our estimates by a factor of 3. My tasks thus far have been only 50% off, and they felt like they took longer than I thought they should. That number may get updated as time goes by, as I've only been doing it for a little bit.

This makes JotBot a great app for even those who don't need to track their time so it can be invoiced later. Give it a spin, the free download has a 30 day trial.

JotBot is the first commercial app for Monkeybars, JRuby, and (we're pretty certain) Ruby.

Monday, January 12, 2009

Some debugging/testing tools for Monkeybars

It quickly becomes apparent how many Ruby libraries are out there that cater to Rails (and work quite well for Rails), but become clumsy when outside of Rails. RSpec is one such library. In RSpec, it's impossible to properly mock constructor logic without making accommodations for RSpec. When certain methods you call from within your constructor need to be mocked out, you have to do some really crafty method aliasing, and then put it back once your test is over. Ew. I'd be happy to be corrected on this. No, telling me not to call methods in my constructor doesn't count.

Well, once you get past those little hurdles, then you run a little problem: Your framework isn't Rails. I actually write Monkeybars code as my fulltime job, so it's not like I'm running away from the safety of Rails only to come back by the end of the week, ready to play with ActiveRecord and ERB some more. RSpec has lots of little matchers such that make it really easy to test if your controller can work with Ajax, renders the right partials, etc. The Rails part of RSpec is rich in features and mature. With a framework like Monkeybars that has a whole lot less magic than Rails, there's still a lot of work to get anywhere near that kind of support. That brings me to my next observation (I promise I'll tie this in to the subject at the end).

I've really tried to embrace BDD with Monkeybars, but the results I got weren't what all of the agile guys scream about. Cursing myself to get flamed/trolled forever, I'm going to go out on a limb and say BDD isn't always a good idea. 100% BDD isn't productive. BDD is great for calculations, where you can elbow calculate what the answers should be, and your methods are in the input/output form. Sometimes, we just can't write code that way, and then testing gets harder. You need to mock stuff out. You need test things inside of initialize. This is the point where you start fighting your testing framework, and it gets ugly. The end result is that you have a bunch of brittle tests (which will get scrapped anyways), and you're behind on your schedule.

I submit that there are two different kinds of useful tests (I can't speak for Rails). First, there's input/output tests, which are functional (LISP functional). There's no state, you pass some stuff in, you get something out. Second, there's integration/user acceptance tests. In Monkeybars, I don't care if a mapping gets kicked off, a signal is invoked, or whatever. What's important is that I clicked on a button, and a dialog with certain text appeared, not that Tomato has many Seeds.

Enter tons of Cucumber testing. It's inside the trunk of Monkeybars right now. It's not complete. There's lots of problems. In trying to solve these problems, I've come up with a few things:
1) The Debug Server.

The debug server is basically telnet + eval. It could use a lot of work, but it's a start. See, when your app quits as part of your test, you'll shut down the Java process that's running your tests. So what do you do? Run the app as a separate process. When you kick off your app, pass it --debug-server (this might change in the future), and it'll open up a telnet port on 4848 (you can also pass in a port number). Any text sent via telnet is evaled. It's not very secure, but it's a start. The return value of the eval is printed back to the telnet client.

2) EDT Recorder
The EDT recorder simply does a puts on all events that hit the EDT. With some tweaking, you could record relevant events while you run the app, and then play them back later as an automated test.

Testing in Monkeybars is going to take a lot of work. My focus is to get it so I can write Cucumber tests for my apps. There's lots of Swing trickery involved, and I've often run into the problem of tests passing on one machine, but not on another. That's because Swing runs on its own thread. When you post an event, it might not have processed by the time you go to test the outcome of the event. You can use things like invokeAndWait (which we do inside of on_edt), but then Foxtrot comes along and messes things up. Foxtrot pumps the EDT while your process does its thing. That means your event gets processed long before the work you're waiting for is actually done. I'm sure we can work around it, but that's where I left off with this stuff. Some time soon I'll have to post my Cucumber tests (that run!)

Sunday, January 11, 2009

View Binding, the Repo

http://gitorious.org/projects/monkeybars/repos/Monkeybars-view-binding

To elaborate a little more:
You declare a binding to be used by calling View.bind. View.bind doesn't do anything right away. Instead, something will happen when the view is instantiated.

Any subclass of ViewBinding is held in a list (so custom view bindings only need to be required).

When the view is created, we run through that list of subclasses, asking each one using use_binding? and passing it the properties given to View.bind, along with a few other things needed for detection (main view component, view, and model). We always take the first match. Default bindings will be provided, but overridable.

ViewBindings then register any listeners they want (such as document listeners for a text field), and can put a listener on the view (View#before_update).

Anytime a view is updated (Controller#signal, Controller#update_view), Monkeybars will invoke the callbacks registered through View#before_update. This allows a ViewBinding to update the model and view and seemingly keep them in sync at all times.

Now, if you reach into the view from the controller using @__view.foo_text_field, you'll get no love from me.

So far, this worked really well for a JTextField's text property, but what of the other components? Some components have lots of interesting things to bind to, such as a Table's row/column data vs the selected row/selected cell. As I flesh out more default bindings, I'll have to establish a reasonable convention.

Speaking of conventions, bind :foo can create some ambiguity for foo_text_field and foo_button. The short answer is that you just don't do that. Make your naming more distinct. Also, this means your bound text fields (perhaps all text fields) will have the _text_field decoration.

On the decorations, I've tried a more non-hungarian style of naming for the components, and I've found that appending the component name really helps me understand what's going on. 'process' could be a list, a text field, or even a button. Many of those have action listeners tied to them, including a 'text' property, so usage of the component/variable isn't indicative of component type. Changing component types is not a lightweight change typically, and is not done often. It usually means reorganizing the form.

Some things I need to do:
  • Add more default bindings (Just JTextField and JTextArea)
  • Document how to use bindings, how to author bindings, and the default bindings
  • unshift new bindings, so newer, custom bindings will have a chance to be picked up by ViewBinding.use_binding? before the defaults.
  • View.bind needs to take *args, or a hash. This part I'd particularly like to get some feedback on. Use cases for certain arg forms vs. others would be greatly appreciated. Although I'm leaning for a symbol or hash as possible values.
  • MethodMappings (most Monkeybars users know this as the :using stuff). View Bindings don't absolve the need to translate the data between the view and model with a little massaging/transforming.

Chuck Remes described View Bindings as basically View.map V2. I'd say that's a fair appraisal.

Saturday, January 10, 2009

View Binding in Monkeybars

What? Don't we have mapping to handle that for us?
We do, but I wanted more. Being as lazy as I am, this stuff was kind of annoying after the 100th time:
View:

class MainView < ApplicationView
set_java_class 'main.MainFrame'

map :view => 'random_text_field.text', :model => :random
end


Controller:

class MainController < ApplicationController
set_model 'MainModel'
set_view 'MainView'
set_close_action :exit

add_listener :type => :document, :components => {'random_text_field.document' => :random}
def random_text_field_insert_update
update_model(view_model, :random)
end

def random_text_field_remove_update
update_model(view_model, :random)
end

def randomize_button_action_performed
length = rand(7) + 1
string = ''
(1..length).map {string << (97 + rand(26)).chr}
model.random = string
update_view
end

def shout_button_action_performed
puts model.random
end
end


Model:

class MainModel
attr_accessor :random
def initialize
@random = 'foo'
end
end


Ugh, all this code does is makes sure that when the user types something, we update the model directly. I think in order for Monkeybars to really take off, we need Monkeybars to handle some of that for us. My alternative is view bindings. View bindings are like mappings, except you can drop in your own. They also allow you to set up handlers and such against your components so you can bind directly to your model. The end result is that Monkeybars has more easy, yet optional 'magic'. And this magic you can override and add to.

Here's what I have working in my sandbox project:
View:

class MainView < ApplicationView
set_java_class 'main.MainFrame'

bind :random
end


Controller:

class MainController < ApplicationController
set_model 'MainModel'
set_view 'MainView'
set_close_action :exit

def randomize_button_action_performed
length = rand(7) + 1
string = ''
(1..length).map {string << (97 + rand(26)).chr}
model.random = string
end

def shout_button_action_performed
puts model.random
end
end


Model:

class MainModel
attr_accessor :random
def initialize
@random = 'foo'
end
end


As you can see, there's a lot less code here. Any time the controller goes off to the view, the view gets synced with the model through the binding (in this case, you don't see the update_view call in randomize_button_action_performed). My plan is to introduce at least one binding to each of the major components (or at least the ones listed in Netbeans as non-container panels). That means that arrays can be bound to JLists (along with a selected value), numbers to progress bars, boolean fields to check boxes, etc.

I need to add a way to do mapping-like coercions to the binding API, and we'll be set.

Programming with Purpose

The highest form of software development has to be in writing software that makes one's own computing easier. Such endeavors may not be immediately profitable, but it certainly can help through building a portfolio, or simply be turned into a profitable thing later. The thing is that these little apps can get you accustomed to writing something usable quickly (which is one of Ruby's strengths), give you practice for the wishlist (we all need that - feature creep is our enemy), and they hopefully give you a boost in productivity. It could also serve as a portfolio that you wear on your sleeve (or in this case, laptop/website) - imagine if you're paying top dollar, do you want to have a skinny chef, a mechanic with a car that backfires, a taylor whose close don't fit, or a programmer who doesn't use a single app he has written?

It's also a testament to the power of the tools used to create these apps. JRuby and Monkeybars have let me create a twitter desktop client. This way, I can stay plugged into Twitter without yet another browser tab open (the web browser is a very counter-productive application for me, which stinks up a lot of resources on my machine, and adds infinite distraction). While the client isn't a complete replacement for the website, that is the eventual goal. Currently, it auto-refreshes my tweets, shows twit (user) images, and allows me to post to others as well as update my own status.

Another quick project I've worked on is a quick Rails app for tracking job leads that myself and James Britt will eventually need to follow up on.

Colloquy has drawn the last straw. OS X has a terribly small pool of IRC clients (the best of the bunch is Colloquy). However, Colloquy has its own problems. Now they are taking away my Drawer (which displays users) and my transcript browser (which didn't handle searches very well). It's hard to complain about free software, but I need an IRC client that fits me (such as separating lurker channels from channels I want to be active in).

I also have a few other projects that might turn into money in the future, but started off because I needed something to make my life/job easier.

Friday, January 9, 2009

First post!

Ok, I'm actually going to keep this blog. I've tried a few topic-specific blogs before, but I just don't think committing to a topic is really a good way to go.
Some things I'll talk about (but not limited to) here:
  • JRuby, Swing, Monkeybars, Gemini, and Rawr - Because of work
  • Business, money, capitalism - Because I like money
  • Warhammer 40K - Because victory is 1 part planning, and 9 parts faith
  • Games and Video Games - Because games are fun