20 April 2011

shrtn: A URL-shortener

Everyone should have their own personal URL shortener, shouldn't they?
I figured that this wouldn't take more than a couple of hours to write. And, indeed, the core functionality didn't take much more time than that. But then we start designing our way round the shortcuts and quick-and-dirty hacks we've used to "get things going quickly", writing unit-tests and comments explaining our thinking, adding some JSP pages so that we can exercise the whole mess, brewing a couple of batches of beer in between times... let's just leave it at a little bit longer!


Why?

Indeed! Why would anybody want Their Very Own Personal URL Shortener?


First: I don't really trust all the "cloudy" hype going around right now. For a start, I have no good reason to trust bit.ly, is.gd, goo.gl or any of the other several-dozen public shorteners. Not that I have much reason to distrust them, but really, I don't know them or the people behind them from a bar of soap. And why should I, like a sheep, participate in generating value[1] for someone who gives me little or nothing in return aside from a shorter, opaque URL that requires an extra network round-trip? And let's not forget that these entities have a nasty tendency to vanish, sometimes rather abruptly. Companies get bought and the acquiring company borgs the product, or sees no value in it, or any of a thousand other corpthink accidents may happen.

Then, too, what sort of assurance do I have that I'll ever be able to get my data (and if I shorten a reference, it's my reference) out of their service ever again? Granted that Google does make some effort in that direction (or at least nods benignly while their engineers do it), but, like the actions of the kakistocracy throughout history, things are only good until a single bad apple rots the barrel.


Second: I don't have PHP deployed on my servers and have no wish to add to the system-administration burden I already have to deal with, so I distinctly want something written in Java...


Third: A whole lot of the URL-shortening services out there don't give any analytics. At least not of those that I can self-host. I think that the analytics angle is compelling. Conventional web analytics - like Google Analytics - are only accessible to the people who created and host the content under analysis. They know where their audience came from, when and how, but nobody else does. If I refer people to some web-stuff[2] I'd like to get an idea of how many people I influenced - how many people followed my recommendation. It is a measure of my own reputation and influence, so highly personal[3]. URL-shorteners give us a way to measure, with a reasonable degree of accuracy and assurance, the influence we have in persuading others to follow our webby blatherings.

I will confess that Google's shortening service is pretty good, and has some nice-ish analytics, but I still think it's in our own best interest to keep at least some stuff out of Google's (or anybody's) mitts. Just on general principles.


An Unexpected Bonus

As it turns out, this is a really, really nice project to use for teaching a JSP/Servlet course, so I'll be reversing it into my Java web-dev course. It covers all the principles I like to get across, from container-managed security through session management and clever use of error-pages, to exploiting the underlying infrastructure properly (instead of hoping that some crapulatious web framework will substitute for your own lack of knowledge or understanding.)


Where?

I'll be releasing the code under the GNU Affero General Public License (probably via Google Code). Just have some tidying-up to do first (like getting license notices in place.) The first deployment is very feature incomplete - there's quite a bit I'd still like to add to the app - and some downright dodgy implementation details that need replacing in time, but for now its working for me.


Drop me a line if you're desperate to have it work for you and can't wait...

[1] At least I assume they get some value out of hosting their shorteners, otherwise why would they do it?
[2] I despise the word "content", despite using it quite frequently.
[3] And, YES, ego-gratifying[4].
[4] Or ego-destroying, as the case may be.

15 April 2011

SEO Fail

So. I've been working quite hard at getting course material together... mainly for OO Software Analysis Design courses and a Design Patterns course. The motivation comes from years and years of teaching Other Peoples Courses and experience a deep and abiding dissatisfaction with the material I am handed to work with. I strongly suspect that my students sense this...

Not Good!

So - after a very, very long time umming and aahing over it - I've put my own course materials together. Blatantly stealing tricks and tips from the HeadFirst books, plans include incorporating video and even music. Dare I say I've done a whole lot better than the usual run-of-the-mill courseware? Order of magnitude? But that would be presumptuous, wouldn't it?

Along the way I realised that I needed to pay a whole lot of attention to my (business) website. The old one sucked. Bad! Not at all descriptive of what I'm now doing or trying to achieve in the OO design and architecture space. So I spent a little time reading up on the website of that famous search engine about how best to structure my site and its content for searching. How to better market what it is I do. I read all about "not using Black Hat SEO" techniques. I paid strict attention to their advice! And I went forth and restructured... but only in a good way! What you see is what the googlebot gets. No tricks!

The result?

Falling from a page-rank of nearly fuck all, I now have a page rank of... zero. Thanks, Google! I guess I'll take my advertising business over to Microsoft, now.

I can only speculate what might have brought this on. Perhaps I got listed on some directory site that Google's software considers Bad News. That's the most likely thing I can think of... Or did I just use words like "software design and architecture" a time or two too many? Perhaps it was the word "Java"...

Unfortunately - like The Borg - there's no Human Person one can contact at Google to say, "Hey! I'm really a Person. What went wrong here and how do I fix it?" Pretty much I'm screwed. Where my site was ranking very well for searches on stuff like "software design training", "Java training"  and "software architecture course" last week, this week I'm nowhere to be seen. Instead you'll see listing from schmucks offering the same-old same-old. The same tired, half-hearted training crap that led me to start developing my own course material in the first place!

So what's a Real Human to do? I guess I'll just have to live with it. After all, my reputation amongst intelligent human beings is top-notch... not something I have to worry about. So do I need to get upset over how some software see me?

Probably not.

15 February 2011

Test-First for Mental Health

I've been thinking recently about how a Test-First approach to development is good for our emotional well-being and psychological balance, and I believe this may be the most important reason to adopt test-driven  development.

Consider how we would traditionally develop software using a conventional Test-Last approach. We read our requirement spec (whatever form that takes), perform some design work -- as much as we feel we need to go forward with some confidence, and we start cutting code. Time goes by. Our codebase grows. We're doing some informal testing as we go along to feel confident that the code under development does what we think it should be doing...

And here's Important Point Number One: "the code does what we (the developers!) think it should be doing". Not what the business thinks it ought to be doing. See? We're inherently unsure -- even if only subconsciously -- whether we're doing work that actually serves the business. And unsureness is insidious and destructive to our well-being. We feel much better about ourselves as developers when we know that we're producing useful stuff that really has value. So here's the first way that having tests defined up-front helps us preserve our mental balance: With a reasonable set of tests1, defined together with our business partners, there's no bullshit involved; no trying to convince ourselves of the (probably shaky) value of our ever-growing codebase. We have an external, automated, objective, easily understood yardstick of value.

But there is, I think, a deeper psychological value to the Test-First approach.

So much of the time -- I will thumbsuck something like 99% of the time -- our code is broken. The system we're working on doesn't work. This is inherent in the fact that it takes us time to design and write software, and the continual not-workingness can be powerfully demoralising. Especially when we (finally, right towards the end of the project lifecycle) start formal testing, and our tester (often users) start coming back with bug after bug after bug after bug, and all that beautiful code we're so proud of is labelled "Less Than Satisfactory" -- usually in much stronger language than that.

Herein lies the secret destructiveness of Test-Last. Our code is always broken, and we can never do more than run after the brokenness trying to patch it up, until, at last, demoralised and exhausted, we move on to the next job or project.

Contrast this with a Test-First pattern.

We first write a bunch of tests. Sure it takes some time, can often be pretty tedious, and is frequently little more than a first-pass best-guess at what the code is supposed to do. Almost certainly we will add more tests as our code grows and evolves and begins to tell us the shape it wants and needs to be. But at least we start with a battery of (automated!) tests. And we start with the expectation of them all failing. This is by definition! We haven't written the necessary code, yet. A short time later we may have enough of the boilerplate in place that we can at least compile everything and actually run our tests, but we still expect them all to fail because our methods all read

throw new UnsupportedOperationExcetion( "TODO" );

So we run our tests, and they all fail. And we're happy about that! Everything went as we predicted. We feel in control.

As we go along replacing those stubbed-out methods, some of our tests begin to go green. We're making visible progress towards a well-defined end goal. We gain an ever-increasing feeling of confidence and accomplishment. We have tangible, objective evidence that we're making progress. Even when we make some of the "test bar" revert somewhat to red -- because we add new tests, or because we do some large-scale refactoring that breaks stuff -- we still feel good about it, because we know that our self-built safety-net is working! We've actually decreased the likelihood of things going wrong, so we know we're enhancing the quality of our product. (And every good developer I've ever worked with has an inner Proud Craftsman lurking in their soul.)

So it seems to me that Test-First builds our confidence and self-esteem as we go along, whereas Test-Last contains an inherently destructive, soul-sapping subversiveness to it.

I think this value outweighs the sum of all the other benefits (many though they are) of Test-First.

[1] Note that I make no distinction, here, between Unit Tests, Functional Tests, or System Tests (which would probably involve real databases, external systems, and so forth, albeit serving test data to our system-under-test.) I don't really care what form of Test-First is most useful to your team and situation. It's the principle that counts!

08 February 2011

Fusion Cuisine: Slicing and Dicing Courses to Suit Different Palates

Ever been faced with setting up training for some of your developers, but the courses offered by the usual suspects fail to cover the technologies your team uses? Or cover technologies that you don't use? Or lack the depth you're looking for in particular areas? Or too much depth...?

I was recently faced with a request from a client who want to put some of their junior developers through an Intro to Java course. The developers in question come from various other programming backgrounds, and already understand OO concepts and normal development disciplines. The "obvious" choice is the Sun/Oracle SL-275 mainstay course which I have been teaching (on and off) for something like 15 years, now.


But! A good part of SL-275 – and of my own Intro to Java course – delves into developing applications using the Swing GUI toolkit, used to construct desktop applications. This particular client is a company that only does web-applications, so learning a bunch of Swing concepts does them little good. I was happily able to propose that, instead of using Swing for that portion of the course, we could substitute some Servlet and JSP concepts and development. This arrangement serves them much better, as it also equips their developers with knowledge they will be able to immediately put to productive use. Fortunately I have lately put in a lot of work on a Servlet/JSP course, so I'm able to cycle some of that material into the Java Intro course.


It's not as simple as it sounds, though!

The Swing portion of "Intro to Java" also serves some other pedagogic purposes. It reinforces some of the OO groundwork covered earlier in the course by driving home the differences between inheritance, containment and usage. (At least it does the way I teach it!) Swing also provides a good platform for introducing listeners (Observer Pattern in the GoF book), Java's anonymous-inner class mechanism, and the exception-handling framework, along with a bunch of other bits-and-pieces that are useful for new-to-Java developers to learn, like converting between Strings and numbers.

So the challenge, now, is to make sure that I can adequately cover the same territory, and serve the same purposes, using servlets and JSPs. Not too hard, really, but it should make for a fun course where we can do a lot more hands-on, practical development work than the stock SL-275 allows.

The other tricky bit to watch is making sure that the level of detail doesn't overwhelm new-to-Java developers with too many web-application specifics. It is important to keep the focus on "Introduction to Java", and not lose sight of the real objective in a welter of webapp configuration and deployment.

Just a single, simple example of where and when customised courses can much better match the client's needs than any standardised, templatised training provided by a 4-week-per-month manual-pusher.
Contact me for a course customised to your organisation's needs!

18 January 2011

2011 Course Planning

Whew! Looks like March is going to be a busy month. I've planned no less than 3 courses back to back, so hard work ahead...

I'll be kicking off with the 5-day "Intro to Java" course on 7-11 March. It seems like Cape Town's demand for Java developers is insatiable. I've had requests from a couple of clients for this course simply because they just can't find good Java devs for their expanding teams, and they're going to be hiring developers with good OO experience from other (non-Java) environments and training them up for Java development as an alternative. Now, I know that any good developers loves learning new stuff, so I think these clients are doing a Good Thing by offering skills-development as part of their hiring process. My job is to give them the best possible Java Platform course, and I have great plans for delivering just that!

Next up will be the newly developed 5-day "Web Application Development with Servlets and JSP". If you've last looked at JSP technology a few years ago, possibly run away in terror at the sight of all the horrible in-page logic that made scriptlet-based JSPs such a nightmare for maintenance, then you really owe it to yourself to get up to speed with scriptlet-free, tag-based JSP development. The course includes topics on the new, new Servlet-3.0/JSP-2.2 enhancements that use annotation-based configuration.

And last, but not least, will be my much-acclaimed 4-day "OO Analysis and Design" course – thus fitting neatly into the 4 working days that remain after the Human Rights Day public-holiday.

I'm planning to run all the courses in Cape Town. (still looking for a great venue, so please drop me a line of you know of something extraordinary.)

Drop me a line if you're interested in any of these. Miss this opportunity at your own risk – I will probably not be scheduling courses in Cape Town again before August!

I'm offering an Early Bird discount of 20% to anybody who confirms a reservation before the end of January!

07 December 2010

Amazon Route 53: Trustworthy?

As a "user" of Amazon's Web Services (I've kicked the tyres on S3, but not much more than that) I received an email from Amazon punting their new DNS service, dubbed "Amazon Route 53".

I wonder though, in the wake of their termination of WikiLeaks, whether I would trust any part of my DNS infrastructure to Amazon. Suppose I did something to piss off the US governement - hosted a DNS entry for WikiLeaks, perhaps? at, say, http://wikileaks.mikro2nd.net/ - and some US government official notices (pretty unlikely, I know, but...) and whispers into Amazon's ear, would I, too, lose use of this critical infrastructure without review, recourse or refund?

So, no! I don't think I'll be using Amazon Route 53 much...

18 October 2010

HTTP Response codes & msgs as Java enum

Just in case it saves someone else the tedious typing... Capitalisation of messages duplicates the inconsistencies in RFC2616. Don't ask me...

    public enum HttpResponse {
        HTTP_100( 100, "HTTP/1.0 100 Continue\r\n\r\n" ),
        HTTP_101( 101, "HTTP/1.0 101 Switching Protocols\r\n\r\n" ),
        HTTP_200( 200, "HTTP/1.0 200 OK\r\n\r\n" ),
        HTTP_201( 201, "HTTP/1.0 201 Created\r\n\r\n" ),
        HTTP_202( 202, "HTTP/1.0 202 Accepted\r\n\r\n" ),
        HTTP_203( 203, "HTTP/1.0 203 Non-Authoritative Information\r\n\r\n" ),
        HTTP_204( 204, "HTTP/1.0 204 No Content\r\n\r\n" ),
        HTTP_205( 205, "HTTP/1.0 205 Reset Content\r\n\r\n" ),
        HTTP_206( 206, "HTTP/1.0 206 Partial Content\r\n\r\n" ),
        HTTP_300( 300, "HTTP/1.0 300 Multiple Choices\r\n\r\n" ),
        HTTP_301( 301, "HTTP/1.0 301 Moved Permanently\r\n\r\n" ),
        HTTP_302( 302, "HTTP/1.0 302 Found\r\n\r\n" ),
        HTTP_303( 303, "HTTP/1.0 303 See Other\r\n\r\n" ),
        HTTP_304( 304, "HTTP/1.0 304 Not Modified\r\n\r\n" ),
        HTTP_305( 305, "HTTP/1.0 305 Use Proxy\r\n\r\n" ),
        HTTP_307( 307, "HTTP/1.0 307 Temporary Redirect\r\n\r\n" ),
        HTTP_400( 400, "HTTP/1.0 400 Bad Request\r\n\r\n" ),
        HTTP_401( 401, "HTTP/1.0 401 Unauthorized\r\n\r\n" ),
        HTTP_402( 402, "HTTP/1.0 402 Payment Required\r\n\r\n" ),
        HTTP_403( 403, "HTTP/1.0 403 Forbidden\r\n\r\n" ),
        HTTP_404( 404, "HTTP/1.0 404 Not Found\r\n\r\n" ),
        HTTP_405( 405, "HTTP/1.0 405 Method Not Allowed\r\n\r\n" ),
        HTTP_406( 406, "HTTP/1.0 406 Not Acceptable\r\n\r\n" ),
        HTTP_407( 407, "HTTP/1.0 407 Proxy Authentication Required\r\n\r\n" ),
        HTTP_408( 408, "HTTP/1.0 408 Request Time-out\r\n\r\n" ),
        HTTP_409( 409, "HTTP/1.0 409 Conflict\r\n\r\n" ),
        HTTP_410( 410, "HTTP/1.0 410 Gone\r\n\r\n" ),
        HTTP_411( 411, "HTTP/1.0 411 Length Required\r\n\r\n" ),
        HTTP_412( 412, "HTTP/1.0 412 Precondition Failed\r\n\r\n" ),
        HTTP_413( 413, "HTTP/1.0 413 Request Entity Too Large\r\n\r\n" ),
        HTTP_414( 414, "HTTP/1.0 414 Request-URI Too Large\r\n\r\n" ),
        HTTP_415( 415, "HTTP/1.0 415 Unsupported Media Type\r\n\r\n" ),
        HTTP_416( 416, "HTTP/1.0 416 Requested range not satisfiable\r\n\r\n" ),
        HTTP_417( 417, "HTTP/1.0 417 Expectation Failed\r\n\r\n" ),
        HTTP_500( 500, "HTTP/1.0 500 Internal Server Error\r\n\r\n" ),
        HTTP_501( 501, "HTTP/1.0 501 Not Implemented\r\n\r\n" ),
        HTTP_502( 502, "HTTP/1.0 502 Bad Gateway\r\n\r\n" ),
        HTTP_503( 503, "HTTP/1.0 503 Service Unavailable\r\n\r\n" ),
        HTTP_504( 504, "HTTP/1.0 504 Gateway Time-out\r\n\r\n" ),
        HTTP_505( 505, "HTTP/1.0 505 HTTP Version not supported\r\n\r\n" );

        private final int intValue;
        private final String msg;

        private HttpResponse( int intValue, final String msg ){
            this.intValue = intValue;
            this.msg = msg;
        }

        public int intValue(){
            return intValue;
        }

        public String responseString(){
            return msg;
        }

        public static HttpResponse forResponseCode( int responseCode ){
            for( HttpResponse v : values() ){
                if( responseCode == v.intValue() ) return v;
            }
            throw new IllegalArgumentException();
        }
    }
Related Posts Plugin for WordPress, Blogger...