Monday, 24 January 2011

On Minecraft

Sound in games is very difficult to get right - it's a bit like make-up - a little makes everything a lot better, a lot makes things worse. And having none at all is better than too much.

Minecraft gets it right - the sound is functional and pretty spooky at times. When there's a zombie hanging around outside your door or down a passageway that you can't see, the sound of it is incredibly atmospheric, as well as being informative. What you don't get (and would be added in a big budget software house) is the sound of birds, crickets and various paraphenalia that you simply don't need. In some ways the sounds of minecraft reminds me of that from a very old game, Dungeon Master - functional, informative, and downright terrifying at times.

Minecraft also gets music right. Instead of being constantly on, the music fades in and out - there will be long periods with no music at all, but when it does arrive, it's incidental and adds to the experience rather than distracts from it. A bigger budget game would have swamped the music channel with crap that 95% of people turn off. (Seriously, game designers: If I want to listen to music whilst playing a game, *I* will choose what it is, not you). The one proper commercial game that I can think of that does music right is the GTA series - again, it's not always on - it's incidental and doesn't distract.

Wednesday, 6 January 2010

To write a spider, you'll need some kind of batch script that reads the tables and creates the entries in your keywords table. Generally, this is pretty simple, along the lines of (sorry about the horrible pseudo-code, mixture of 4gl and java, sorry!)....

for each customer
split_into_words(customer.name, 100)
split_into_words(customer.address1, 10)
split_into_words(customer.address2, 10)
....etc....
end foreach

for each invoice
store(invoice.number,100)
store(invoice.customer_reference_number,20)
end foreach

.... etc .....

function split_into_words(string, significance)
string[] str = split(string)
for each str
if exists in [keywords table]

update it, adding significance
else
insert into [keywords table]
end foreach
end function

function store(string, significance)
if exists in [keywords table]
update it, adding significance
else
insert into [keywords table]
end function



---------

This then needs to be able to be called from just about anywhere, either respidering a particular customer, or a particular subset of accounts, or a particular subset of invoices, etc.

The section field within the keywords table is an indicator to whatever is reading this table as to where to redirect. eg. If an invoice, put an "I" in the section, the function that reads the keywords table should know to to produce a link to an invoice. If a customer, put a "C" in the section, the reader of the keywords table should produce a link to a customer. Etc, etc, etc.

The difficult parts are

1) assigning significance. If you have customer id 32800 and invoice id 32800, which is more important? Is "Chester Street Motors" more important than a company that's on "Chester Street"? Significance tuning is an art, but if what the user wants is in the top 10, it'll be ok. Important: Watch what users search for, and code your spider accordingly.
2) When and what to respider? Ideally, the spider runs every time something new gets created on the system. You need to be able to respider from anwhere, from any system, whether it be the modern Java or C# or from your legacy cobol systems. Make sure, however you write your spider, you can call it with multiple options (respider this account, these invoices, etc), from anywhere, at any time.
3) Creating the keyword index is an intensive process. You MUST not affect the running of the live system. In practice, when running a full respider, this means creating a temporary table that is then renamed and replaced over the live table (renaming a table, once built, is inexpensive for a database). And, how do you cope with additions during the re-indexing process? I leave that answer to you, or possibly, to google :-)
4) Finally, how do you cope with mis-spellings? For example: Refrigeration Supplies Ltd. Is that spelt right? Are you sure it's not Refridgeration Supplies Ltd? So, it might be spelt wrong in your database, or in the users search. How do you deal with that. (I suggest further reading on Soundex, and Double-Metaphone, I don't really have a great solution for you!!!)

Friday, 7 August 2009

How to do search programmatically

Here's a common problem - you have deep data - you have invoices in multiple different database tables ; you have customer reference numbers somewhere else ; you have customer details in a further table ; you have order numbers; you have products you sell; etc.

How do you provide a single simple search interface that finds exactly what the user wants from a single 'search box'?

Well, it's actually pretty simple. But it does get complicated later on, but don't worry, all problems are surmountable! Let's describe what we need in terms of sql...

create table keywords (
keyword varchar(20),
refernce varchar(20),
section varchar(1),
signifcance integer
);

create unique index i_keywords_1 on keywords (keyword, refernce, section);

---
From this basic keywords table (and yes, add your own unique references as necessary), you can construct highly efficient queries. For example, searching for 'Fleetwood'...

select K1.refernce, K1.section, K1.significance
from keywords K1
where K1.keyword = 'Fleetwood'
order by K1.significance desc
;

this is efficient as an sql query - searches down keywords first. If you entered two words, eg. 'Fleetwood' 'Mac'...

-- AND query...
select K1.refernce, K1.section, (K1.significance + K2.significance) sig
from keywords K1, keywords K2
where K1.refernce = K2.refernce
and K1.section = K2.section
and K1.keyword = 'Fleetwood'
and K2.keywood = 'Mac'
order by sig

-- OR query...
select K1.refernce, K1.section, K1.significance
from keywords K1
where K1.keyword = 'Fleetwood'
union
select K2.refernce, K2.section, K2.significance
from keywords K2
where K2.keyword = 'Mac'
order by 3

--
Again, extremely efficient as an sql query. Any half-decent database server will return the result in miliseconds, and the sql is easy to construct.
--

So, now comes the slightly harder part - populating the data.

You will need a "spider" to find the information and put it in the keyword index. This is a pretty intensive database process, requires some art to write, and can have problems when you want a truly up-to-date index.

More tomorrow.

Friday, 20 March 2009

Wicket

Wicket is a java framework for building web applications which we're using at work, and I'm continually impressed with how easy things are to do with it. I've worked on other java projects that were just horrible though, so maybe my experience with Wicket is one that everyone else has with other frameworks - We've been down the struts approach which means holding data in eight different classes and properties files. We've been down the XML route which made the problem even worse, and we've tried out JSF and found it's really not a mature technology and you end up relying on code in obscure tag libraries.

Wicket has a HTML page with special id tags for every element that you want to be controllable from the java side - for example - td wicket:id="description" , but no JSP references or any of the crap that framework designers like to stuff in the html page making it unusable for anybody else. The HTML renders as html on its own - it's actually possible, in a real situation, to get someone to design the HTML and just plonk it into your project. I've not known this to be the case for any other framework.

For every HTML page that you want to be able to change via code, you have a Java class with the same name that sits directly alongside it. This differs from other frameworks which have the controller somewhere, the JSP page somewhere else, the tag libraries elsewhere, the form object in another area, the form validation somewhere else and the XML controlling page flow in another place. Having the page and the code next to each other makes good sense, and it's hard to see why other frameworks have deviated from this.

Also, no XML, properties or other external files. It's a single change to web.xml to get the whole caboodle to work. So effectively, when creating a new page/application, I'm dealing with two files - the html, and the java code behind that page. That's it. Well, there's still stuff to be done in the database classes to get the page to be able to fetch the data properly, but that's common to every project and I wouldn't have it any other way - the view (in this case, the wicket page) should always be separate from the data layer.

There's no real downside that I can see at this stage. The components are extensible and reasonably easy to use. The code in the java class is readable and easy to understand. The one, possible, slight niggle that I have with it is that it encourages the use of inner classes a lot. But that's not necessarily a bad thing, in fact, I'd rather have the code that executes when I click a button right by where I'm adding it to the form - the code would look something like...

add(new FeedbackPanel("feedback"); // any "error" or "info" stuff automatically appears here
Form form = new Form("monday");
Button b = new Button("submitButton"){
@Override
public void onSubmit(){
// Validation checking here
if(itsMondayMorning)
error("Go away I'm still hungover");
else
db.updateSomething();
}
};
form.add(b);
add(form);

---
Using inner classes happens all the time when doing Wicket - it does make things a bit more readable and the code flow nicely.
I'm told by someone who's worked with Swing components that the logic is similar to that, despite being in a HTML stateless environment. I don't really know having never worked with it, but it seems a doddle to get/set objects on forms.
And even when things get complicated, with fields being made invisible, buttons appearing/disappearing depending on user priveleges, validation being complex because there's a ton of fields or multiple combinations not being valid, it's still easy. It doesn't suffer from the old Visual Basic problem where to get something that looked good took 5 minutes but to get something that actually worked took a lifetime and a lot of Windows API calls.

Upsides: It's easy. It's easy to do difficult stuff and still have readable code. It's easy to bolt your database layer to. Ajax is remarkably easy to do with it. It's easily extensible (too much so?). You can write a full scale working application with just the examples from the wicket book and your code won't be any more complicated than the simple examples. The forum people are wonderful at answering questions.

Possible downsides: I think it's quite heavy on the Session object, but we've had no problems with memory usage or speed so far with a ton of users hammering it at the same time (the bottleneck is the database). Um, oh, I don't like the way it handles custom images, but there's several better ways of doing that than the default. Errrrm, and I don't like the way the URLs look by default (but again, this can be changed).

---
So, if you're struggling with your current Java framework, go and try out wicket. Even if it's not for you, it's probably worth a look.

Wednesday, 11 March 2009

In my job, I have to use several programming languages. Normally several a day. I've looked at asp, java, informix 4gl so far today, and it's not even lunchtime!

I'm not a programming snob, I do like some of the things "bad" languages do and detest some of the things "good" languages do.

For example - Visual Basic is generally regarded as a Bad Thing, but the fact that 'true = -1' is a brilliant coup. I'm sure C/Java programmers will read that with horror, but the fact is, if true = -1 then logical and bitwise are the same. Effectively, there's no need for having | and || to represent bit-wise and logical or statements because they are one and the same. I'm not saying that Visual Basic is good in general (it's not), but this is simply a better way of doing it.

Java's generally regarded as a Good Thing, but its error handling is one of its worst features. In theory, it provides wonderful error handling. In practice, everyone who writes library modules throws runtime exceptions instead of requiring those exceptions to be caught. This is wrong and leads to buggy code and vast error stacks that spit out Pythonesque gibberish that bear little relevance to the actual problem. I think designers don't throw normal exceptions because it breaks the "black box" model. But the black box model is decidedly broken in Java anyway, with objects merging, passing black box objects into other black boxes, and other problems.

Thursday, 5 March 2009

I love the BBC, well, more specifically, I love BBC radio 4. I've just listened to the latest In our time episode which covered the "measurement problem in physics" (essentially, the problem of resolving the quantum weirdness we observe at the macro level to the newtonian mechanics which are understandable). The programme was deep, complex, thought-provoking, and suprisingly comprehensible. I do have an A-level physics qualification, but we barely covered quantum malarkey. Melvyn Bragg presented it and I was suprised how well he refereed the eminent guests (eg. Roger Penrose) despite his (probable) lack of knowledge on the subject.

That Auntie can even attempt to broadcast this in primetime to millions of listeners (Radio 4 is one of the largest radio stations in the UK) is a superb example of why you need independent broadcasters that don't depend on advertising revenues. I'm trying to think of an example of where you'd get such rich deep content without it, but I can't.

Radio 4 is pretty much unique. It's a news/spoken word radio station, it's top or close enough to being the number one listened to radio station in the UK. It doesn't do sport (unlike most other talk radio) except of course, for the incomparable test match special. It presents radio plays (eg. Douglas Adams' The Hitchiker's Guide), comedy that is either brilliant on radio permanently (I'm sorry I haven't a clue, The Now Show, etc) or can be transposed to TV too (eg. Goodness gracious me, The Frost Report which spawned Monty Python, etc), or documentaries and debate shows like the one I'm praising today. Worth the licence fee on its own!
Seduced, shaggy Samson snored.
She scissored short. Sorely shorn,
Soon shackled slave, Samson sighed.
Silently scheming,
Sightlessly seeking
Some savage, spectacular suicide.