Categories
entity systems games design massively multiplayer programming

Entity System 1: Java/Android

Please note: the design described in this blog post has been much improved and updated and put up – with full source – on http://entity-systems.wikidot.com/.

On the wiki linked above, there is now a wholly new Entity System design, based on this one, but much improved. There’s a brief post about it here, recommended instead of this ES design: http://t-machine.org/index.php/2011/08/22/entity-system-rdbms-beta-a-new-example-with-source/.

I’ve been writing about Entity Systems sporadically for the last few years. Recently, I finally had the time and the excuse to build one of my own (i.e. not owned by an employer). If you haven’t read the main series of ES posts, you should do that first. There are many things in the world masquerading under the Entity/Component banner – and even more that just coincidentally share the name, but describe something else completely. It’s worth understanding which variant I’m talking about before you read about what I’ve done :).

Why build an Entity System?

At a generic level, this is covered in the other posts. But it’s taken years for me to have the time/inclination to write a new one from scratch outside of my day-job. What happened?

  1. I left my iPhone in America, and it took 2 months to get it back
  2. Google gave me a free Nexus One, in the hope I’d write something for it (ha! Their cunning plan worked…)
  3. The Android marketplace is such a miserable morasss of third-rate crap that eventually I was compelled to write my own Android game … just so that I would have something to play (there are very few games on the Android store that are even worth the time it takes to download them)

I’ve been making games for a long time. I know how much effort will go into it, how much time, and how much slog there is before it becomes worth it. Writing a game on your own often means putting in 90% of the effort to get 10% of the reward.

Enter … the Entity System. If I were to pick a game-design that mostly used data-driven game features, I could implement it around an ES, and massively reduce the amount of planning needed to get the game running. I could maybe have a working game after a mere 20% of the effort. Hmm…

Building the ES for Android

Android runs something that’s *almost* Java (although more on that later – Android’s version of Java is very slow at some of the core libraries, and it really shouldn’t be). Technically, Android supports all the core data structures from Java (Collections), and the templating system (Generics).

If I were writing an ES in C++, I’d do it using templates without pausing to think; I wondered how well the same might work with Generics, given that Generics is *not* a complete templating system, although it provides quite a lot.

Getting started: early ES decisions

How to design/implement this thing? Well, we know one thing for sure:

Entities have a single name/label/global-ID. Entities MUST NOT contain ANY DATA: these are NOT objects, this is NOT OOP!

There you go, the Entity class wrote itself:
[java]
public class Entity
{
public int id;
}
[/java]
This immediately raised some concerns for me, being the seasoned coder I am (ha!). How the heck was I going to write any code that dealt with these things if I didn’t have references to them? Obviously, sometimes you do have references, but other times you expect to follow refs from within the objects you have, to get to the objects you need. That wouldn’t be happening here, since there are no inter-object refs.

[java]
public class BaseEntitySystem implements EntitySystem
{
/** I’m too lazy to write a "safe" method to get a globally-unique ID; for now,
I just return 1 the first time I’m called, 2 the second time, etc… */
protected int getNextAvailableID();

/** Whenever you create an entity, you’d better invoke this method too!*/
public void registerEntity( Entity e );

/** The method to solve my fears above */
public Entity getEntity( int id )

/**
* Merely removes the entity from the store. It becomes a GC candidate
* almost immediately (since all other refs are transient)
*/
public void killEntity( Entity e )
}
[/java]

…but, again, being a Veteran coder, the survivor of many painful battles on the field of programming … I didn’t trust myself in the slightest to “always remember” to invoke registerEntity. Quick trick: give the Entity class a static reference to a default EntitySystem, and have each EntitySystem check if that reference is null when starting; if so, set itself as the “default”.

[java]
public class Entity
{

public static EntitySystem defaultEntitySystem;

public Entity( int i )
{
id = i;

if( defaultEntitySystem == null )
throw new IllegalArgumentException( "There is no global EntitySystem; create a new EntitySystem before creating Entity’s" );

defaultEntitySystem.registerEntity( this );
}

}

public class BaseEntitySystem implements EntitySystem
{

public BaseEntitySystem()
{
if( Entity.defaultEntitySystem == null )
{
slog( "Setting myself as default entity system (Entity.default… is currently null) self = " + this );
Entity.defaultEntitySystem = this;
}
}

}
[/java]

W00t! I can create Entity’s, and I can find them later on. Awesome. What about those Components, then?

Getting started: Components in Java

I’ve done ES in C++ before, with real templates, so I wasn’t really thinking at this point … I just ran with what seemed natural based on prior experience. The thought process (had there been one) would have been something like this:

  1. This is java, I use Eclipse: I absolutely *must* have the IDE know what data/fields exist in each component so that Content-Assist/Autocomplete works 100%. Otherwise I will gouge my own eyes out having to remember, and doubly so each time the app compiles but dies at runtime because of a typo in a field-name.
    • Requirement: each unique Component must be defined as a java Class, with each of the fields being a public member of that class
    • Requirement: to access a Component of a given Entity, you must invoke a method which returns something that is typed (as in language typing) to the correct Class

I made a Component class, and had all Components extend it; there is a particular reason for this, but it doesn’t matter right now – essentially, it lets you define shared behaviour for all Component subclasses, and just saves you time on typing.

My first real Component:

(NB: I defined this *inside* another class, because I couldn’t be bothered having N source files for the (large number of) N Components I was bound to create. Hence the “static”):
[java]
public class MyEntitySystemExperiment
{

static class Position extends Component
{
float x, y;
int width, height;
float rotationDegrees;

@Override public String toString()
{
return "("+super.toString()+" @ ("+x+","+y+") * rot."+rotationDegrees+")";
}
}

}
[/java]

Great. I have a component. Now comes the largest single piece of work in the entire implementation of the ES: writing the methods to:

  1. Add a component to an Entity
  2. Fetch a component from an Entity
  3. Remove a component from an Entity

Fetching a Component from an Entity

This is the win/lose point: if this works well, our ES will be nice and easy to use. The other two methods (add and remove) are simply twiddling bits of data. This one is the challenge: can you make it *easy* to write code that uses the ES, and for that code to be clearly *understandable*?

[java]
public class EntitySystemSimple extends BaseEntitySystem
{
HashMap<Class, HashMap<Entity, ? extends Component>> componentStores;

public <T> T getComponent( Entity e, Class<T> exampleClass )
{
HashMap<Entity, ? extends Component> store = componentStores.get( exampleClass );

T result = (T) store.get( e );
if( result == null )
throw new IllegalArgumentException( "GET FAIL: "+e+" does not
possess Component of class\n missing: "+exampleClass );

return result;
}

}
[/java]

Boom! It works.

Let’s just stop briefly and I’ll explain why. Reading Java generics code from cold (just like reading C++ templates) often takes a lot of hard thinking.

Looking at the “result” of this method, we want it to be (enforced by the compiler):

  1. “an instance of a class that extends Component”
  2. “an instance of the particular class/Component that we requested – not just any old subclass”

[java]
/** based on comments at end of blog post, think this is correct,
but not checked */
public <T extends Component> T getComponent( Entity e, Class<T> exampleClass )
[/java]

It causes you to write application code that looks something like this:

[java]
public void doSomethingWithAnEntity( int globalId )
{
// remember, we NEVER hold refs to Entity objects for long
Entity e = entitySystem.get( globalId );

Position position = entitySystem.getComponent( e, Position.class );
position.x = 5;
}
[/java]

…and what’s important is that the “type” of the “Position position = …” line is already hard-typed to “Position”. So, the content-assist will *auto-complete* anything put after a dot on the end of that line, e.g.:

[java]
entitySystem.getComponent( e, Position.class ).AUTO_COMPLETE
[/java]

…so you can instead write your method much quicker, and yet very clearly, as:

[java]
public void doSomethingWithAnEntity( int globalId )
{
// remember, we NEVER hold refs to Entity objects for long
Entity e = entitySystem.get( globalId );

entitySystem.getComponent( e, Position.class ).x = 5;
entitySystem.getComponent( e, Damage.class ).hitpoints = 145;
entitySystem.getComponent( e, Renderable.class ).foregroundColour = Color.red;
}
[/java]

Time-out: HashMap

HashMap is the “correct” class to use in Java for this setup: it’s the exact equivalent of Hashtable / Dictionary / etc in other languages. We need to map (somewhere, somehow) from one thing (an entity) to another thing (a component).

NB: this does not mean that you have to use HashMap as your data-store for the ES; I positively encourage you to consider other options. I used it here as the most obvious, simplest possible structure that would do the job. If you think back to my posts on Entity Systems for MMO development, I’ve often suggested that the data store could *and should* be any of many different things. In particular, SQL databases make for an excellent data-store (and remember you can get in-memory SQL implementations that do away with all the expensive write-to-disk stuff).

Unfortunately … Android seems to only partially support HashMap. You can use the class, but it runs an order of magnitude slower than you expect for a normal JVM (compared to the speed with which it runs other methods). It seems to have problems with the hashcode methods, but also even with basic iteration over the Map contents. Odd. Later on, I had to do some tricks to speed up the ES, just because of this problem.

Fetching a Component from an Entity: Redux

The examples I gave above for accessing components were lean and clear on the right hand side (thanks to autocomplete and strong typing), but terrible on the left-hand-side. By the magic of OOP, I’m going to clean up the LHS. BUT (and this is a big “but”) … make sure you fully understand what I’m doing here. With what I’m about to do, it would be very easy to fall into one of the traps of ES development: slipping back into OOP techniques.

Looking at the example:

[java]
entitySystem.getComponent( e, Position.class ).x = 5;
entitySystem.getComponent( e, Damage.class ).hitpoints = 145;
entitySystem.getComponent( e, Renderable.class ).foregroundColour = Color.red;
[/java]

… applying OOP mindset, we see that the first argument is redundant; the Entity already knows about the EntitySystem to which it’s registered.

Also, we know that the Entity class will never have any methods or data other than the ID. If that’s the case, the only thing we’d ever “get” from an Entity is a Component. So, we can add this to Entity:

[java]
public class Entity
{

/** Gets a filtered view of the entity’s data, only returning the subset that
* corresponds to a particular one of its components */
public <T extends Component> T getAs( Class<T> type )
{
return source.getComponent( this, type );
}

}
[/java]

…which converts our usage example to:

[java]
e.getAs( Position.class ).x = 5;
e.getAs( Damage.class ).hitpoints = 145;
e.getAs( Renderable.class ).foregroundColour = Color.red;
[/java]

Using the ES with Systems

Recap: right now, we can:

  1. Create entities
  2. Add components to entities
  3. Read/Write the data inside each component, on a per-entity basis
  4. Fetch entities by globally unique ID

One last thing is needed before the ES can work: we need a way to fetch Entities “by component”.

e.g.:

[java]
public class MyEntitySystemExperiment
{

public void runLoop()
{
while( true )
{
// move all the entities
positionSystem.move( MOVEABLE_ENTITIES );

// check for collisions
collisionDetectionSystem.process( MOVEABLE_ENTITIES );

// render all the visible entities
renderingSystem.render( RENDERABLE_ENTITIES );
}
}

}
[/java]

We need a way to provide the arguments that are capitalized above. We know that these should be plain-old lists of entities. We know they have to come from the EntitySystem. Finally, we know that the only defining characteristic of these lists is that everything in the list has *at least* a particular Component.

(respectively, in the example above, the lists contain: “all entities that are moveable”, “all entities that are moveable AND all entities that are barriers to movement (e.g. solid walls)”, and “all entities that should be displayed on-screen”)

So, one more method for the EntitySystem interface:

[java]
public interface EntitySystem
{

public List<Entity> getAllEntitiesPossessing( Class… requiredComponents );

}
[/java]

“Class…” is just a convenience; in many cases, you’ll be insisting on a single Component. In many other cases, you’ll be insisting on a set of components. Java varargs provide the minor convenience of doing both of those in one method, while retaining type-safety.

The implementation of this method is obvious: it iterates over every entity that’s been registered, and checks it against ALL the required components. If it possesses all of them, it goes into the output list.

Finis

That’s it. So easy! Obviously, there’s more to it – the other methods you need to create should be mostly self-evident – but this should be enough to get you started.

Now, I’m not sure where to go from here. I’ve got a working Java ES. I’ve got some performance improvements and feature improvements. But … in practice, hardly anyone writes games in Java (except Android programmers, and there aren’t many of those), so … is it worth it?

Alternatively, I might just run through some of the practical pros and cons I encountered when actually using the ES in writing the game-logic. There’s some interesting things that came up which most people encounter sooner or later when doing their first ES, and which might be worth looking at in more detail.

One last thought…

Did it work? Did this ES allow me to write a decent Android game?

Yep. I wrote a space-invaders / bullet-hell game with it. It worked fine on Android phones for a hundred-odd enemies and bullets on screen. On Android, thanks to the crappy JVM, it started to chug after that (dropped below 30 FPS), so I had to make some substantial performance improvements, and now it’s happily rendering 300 things all flying around at 20-30 FPS. The game is far from finished, but it’s playable and fun for a minute or so – a definite achievement considering how little of it I’ve written so far.

many-entities-at-10-fps

NB: it’s got some way to go before I’ll be happy releasing it. But, given a few more spare evenings, I hope to get this up on the Android Market as a free download in the near future.

I’m pleasantly surprised that the Android phones can handle something as high-level as an ES, in a pure, unoptimized “simplest possible” implementation.

Did this post help you?

You can say “thank you” by giving me your email address, and letting me contact you next time I make a game of my own:

[smlsubform emailtxt=”” showname=” mailinglist=”pif-entity-systems”]
Categories
agile dev-process MMOG development programming startup advice web 2.0

How to FAIL, from the world of Open Source: Eclipse

The problem

It’s a great piece of openness to put your bug lists in the public domain. It makes it easier for your customers and partners to make decisions that save you time because they can see what’s coming and when (and save you money in reduced support requests). It saves you money in that you get free QA / testing from your users.

The downside is that it exposes to the world the places where you are especially incompetent, lazy, or just plain self-centred.

This is a recurring theme I’ve seen with corporates looking at both Open Source and also Web 2.0:

We say we’re the best, but secretly I believe we’re the worst; if we expose ourselves to the public, people will ridicule our mediocrity, and refuse to do business with us.

Also … I will probably get fired because my colleagues and my boss will finally realise what a clusterfuck I preside over on a daily basis

Eclipse, and a tale of two bugs

I was going to log two high-impact bugs that Eclipse has had for several years. Then I did a search on that area of Eclipse, and realised that the current Eclipse maintainers don’t give a **** about this whole section of the IDE – some of the core bugs we see every day were logged in 2001, and are still open:

https://bugs.eclipse.org/bugs/buglist.cgi?query_format=specific&order=relevance+desc&bug_status=__open__&product=&content=syntax+coloring

What you find when you do some basic research

If you go looking through the bug history for some of the more “obvious” bugs there, you often find little gems of passive-aggressiveness from maintainers. That’s an exceptionally effective way of making sure people stop helping and supporting any Open-Source project…

You’ll also find endless re-logging of the same old bugs from 10 years ago, revolving around the basic problem that Eclipse lets you set everything you could possibly imagine … EXCEPT the colours that it prints text in.

(all IDEs let you set the colours; most dont give you enough control over the other parts; Eclipse fails on the basic challenge, and succeeds on the advanced challenge)

This wouldn’t be so bad, except that its default is very bright with low-contrast – i.e. very hard to read on laptops when outside, and bad to read for long periods of time. As of about 5 years ago, you are finally “allowed” to set the colours yourself – except that the app breaks if you do, because they “didn’t bother” to allow you to change the colours on 20% or so of things.

Final thoughts

The next time someone – especially at a corporate – resists openness and transparency … in any form … ask yourself this:

What have they got to hide?

Often, once you ask yourself that question of the right person at the right time, it very quickly becomes obvious what they’re hiding (if not why). A little more digging, and you can pry open the can of worms, and see what trouble they’ve been up to…

(Incidentally (and unsurprisingly), in the face of the point-blank refusal of Eclipse developers to make basic usability concessions across the board, I didn’t bother logging either of the two bugs I’d found)

Categories
design entity systems games design massively multiplayer programming

Entity Systems are the Future of MMOs Part 5

(Start by reading Entity Systems are the Future of MMOs Part 1)

It’s been a long time since my last post on this topic. Last year, I stopped working for a big MMO publisher, and since then I’ve been having fun doing MMO Consultancy (helping other teams write their games), and iPhone development (learning how to design and write great iPhone apps).

Previously, I posed some questions and said I’d answer them later:

  • how do you define the archetypes for your entities?
  • how do you instantiate multiple new entities from a single archetype?
  • how do you STORE in-memory entities so that they can be re-instantiated later on?

Let’s answer those first.

Categories
iphone programming

How to sort an NSDictionary on iPhone

(because I googled it, and on the first page of hits I couldn’t find any copy/pasteable source for this common problem, here’s an answer with (poor) public domain source code)

Categories
iphone programming

How to make an iPhone static library – part 1

I’ve now deployed iPhone static libraries in two (live) applications, and numerous updates.

This is a process that is seemingly (*) 90% undocumented by Apple, despite being (IMHO) absolutely essential for any professional iPhone developer.

UPDATE: Apple changed everything (again) without telling developers (again) and broke everything (again).

Current versions of Xcode (the minimum that Apple allows you to use) will *not* work with the architecture-link part of this blog post.

Instead, see this StackOverflow question I asked (and answered) with an updated technique: http://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4

[(*) – if there’s docs, then I’ve not found it in over 6 months of googling, searching Xcode doc libraries, and asking everyone I know. I will feel stupid if it’s there and I haven’t found it, but I have honestly tried very hard to find it!]

I have sought help in numerous expert forums and mailing lists – and generally discovered that no-one else is quite sure how to do it either, although I’ve seen some funky ideas and methods that others have come up with.

Through trial and error I’m pretty sure I know how to do it now – but I still have no idea what the “correct” approach is – so I’m writing up my best knowledge here, and I’m going to spread it to as many people as possible to get feedback from the 30,000+ other iPhone developers around the world.

Categories
iphone programming

How much do iPhone developers cost (contract)?

(this is off the top of my head, probably some glaring errors; it’s intended to give a general idea rather than be authoritative. How do YOU calculate your hourly rate for contracts?)

It seems there’s an increasing number of people around who have no prior experience of this, and are taking their first steps into freelance/contracting while doing iPhone dev in particular.

There are also an increasing number of clients offering impossibly low daily rates. I’m sure some of these are sharks taking advantage of first-time contractors, BUT … I know from personal experience that some are merely naive. Sometimes, it’s just that they are themselves ignorant of the realities of contracting.

So, to help first-time contractors, and to help clients trying to work out why they’re having trouble getting decent people on their seemingly “sensible” budget, here’s some quick thoughts on the standard practice on contract pricing.

By the way, to answer the titular question: Bad ones – about £250 / $350 a day; good ones – about £750-£1250 / (guess, but I haven’t asked any USA guys recently: circa $1200-$1500?) a day; Really really bad ones who have no idea what they’re doing and are probably teaching themselves programming as they go, on *your* budget – about £200 / $200 a day.

(note: the weak (disappointing, but bearable) and the worst (total waste of your time and money) are duking it out on price at the bottom end of the scale, that’s no coincidence. That’s all they can sell themselves on)

1. Salary is not remuneration

By law, in the UK and throughout Europe, companies *must* provide employees with cash and benefits above and beyond their salary. Whatever your official salary, the govt mandates that your employer pays you X% more than that (X varies from place to place and situation to situation).

X is made up of, among other things: “employer” tax, “employer” pension payments, sick pay, holiday pay (typically around 10% of base salary!), local govt taxes, various kinds of mandatory insurance, etc.

Some people get company bonuses as well, often from 1% to 20%.

Of course, at most companies, you also get a whole load of stuff “for free”. The rule of thumb at many companies is that *every* employee costs approx 10% on top of their base salary – and that any bonuses, benefits, etc, are extra on top.

TOTAL: 120%-150%

Finding work is an unpaid activity

Contractors are required to spend some number of hours every month looking for their next contract. This can start simple – trawling websites – but even when a good match is found, the contractor has to take UNPAID time off work to speak to recruiters/hiring managers, attend interviews, etc.

Assuming everything goes perfectly and it takes you 2-3 days of preparation, search, interviewing, bidding, viewing specs, etc, and you work 2-3 month contracts on average, this is 5% of your working time.

If just one project gets cancelled / doesnt come through, that is immediately doubled. Any slowness on the part of recruiters again increases the cost to the contractor.

TOTAL: 110%-125%

The numbers above are off the top of my head, and are far from complete. When you add it all up, and average over time, the rule of thumb for experienced contractors is that your hourly contract-rate should be at minimum 2 times your hourly employee salary, and as much as 3 times.

This is getting pretty long for an LI post, and I’m sure there’s a lot wrong with it, but hopefully it’s enough to give people an idea of the realities of the situation.

Categories
conferences games industry iphone programming

Brighton: 3 free iphone talks + networking, tomorrow

If you’re in Brighton this week for the Develop conference … there’s a few places left at the free networking/talks event we’re doing tomorrow night:

http://upcoming.yahoo.com/event/3017732/?ps=6

(if you can’t make it, I’ll get all the slides on-line afterwards, so long as the speakers don’t mind)

…although we’re getting very close to capacity. Some people probably will change their minds and not turn up, so it might be worth coming along anyway, even if there’s apparently no space left (and the venue have said they can make room for up to 10 more if they have to, althoguh it’d be a real squeeze, apparently).

PS: the organizers of the Develop Conference manage to be arrogant, rude, ****s for the third year running. They didn’t even deign to respond to my offers to schedule this event at a time that would be least conflicting with their evening schedule for the conference. I am constantly amazed at how many people they manage to piss-off every year, and rather sad, because I suspect it’ll gradually erode more and more of the value of the conference (all the people who refuse to come back, or refuse to speak in future) – and that would be a huge shame, because a summer conference in Brighton is great thing. If they can manage to stop being such ****s and doing their best to screw it up. Sigh.

PPS: FWIW, my reference to “third year running” is based on the things that I know they did / said to friends and colleagues in previous years. I learnt early on to expect nothing but rudeness from them, although I’ve been studiously polite each year, giving them the benefit of the doubt. Perhaps foolishly – but I hoped they might, you know, learn some basic courtesy at some point. Not yet.

</rant> ;)

Categories
computer games design games design iphone MMOG development programming

Want to help write a simple RPG for iPhone?

Now I’ve recovered from GDC illness, I’ve got a little free time again, and I’m starting one of the iPhone games I wanted to write. This is a “for fun and learning” project, so it’s deliberately chosen to be low maintenance / easy to make a first version / easy to extend later / etc. I need artists, designers, quest-writers, and programmers.

Well, I don’t *need* anyone; I can do this all myself. But I’d rather do it with other people, and I thought there might be some hobbyists reading this who’d like to do something similar.

EDIT: there’s now a googlegroup for people working on this. You *must* contact me first via email (see below) or your request to join will be automatically rejected. http://groups.google.com/group/dmclone

Categories
conferences massively multiplayer network programming programming

Everything you need to know about being an awesome MMO Tech Director

Really? O, RLY?

Well, no, probably not – but this is the kind of opening statement I often make at industry-conference parties. In this rare case, at LOGIN this year, I was showing something on my laptop at the time and happened to *type* my opening salvo, rather than just say it.

Categories
databases programming

Export spreadsheet to plain XML with OpenOffice 3.x (works!)

Microsoft Office:

  1. Costs stupid amounts of money
  2. Isn’t very good
  3. Is only available on windows
  4. …but “usually” works

OpenOffice:

  1. Is completely free
  2. Is an almost exact clone of Microsoft Office circa Office 2000/XP
  3. Is open-source (so that sometimes you can easily fix it yourself, quite surprisingly!)
  4. …but apart from the Microsoft Word part, “often doesn’t work”

I’ve been using OpenOffice’s Word clone as a complete replacement for Word for the past 3 years, and it’s been perfect. Previously, I used to use Word *and* OpenOffice, because the latter had some big bugs left in it.

Sadly, OpenOffice’s Excel clone is … often shockingly buggy. I won’t go into the details. But this post is about one missing/broken feature in particular: OpenOffice by default saves / exports XML which (for most people, and all simple uses) is unusable/unreadable – and is very hard to convert with XSLT. Read on for a script that will fix this for you…

Categories
PHP programming

Now I remember why PHP is so easy to hate…

(aka “why do my include/require/include_once/require_once files not work / seem NOT to be included, even though they are?”)

PHP has a mechanism for including files inside each other. The architects of PHP didn’t really think much about what they were doing with a lot of the core language features (witness the foolishness over Register Globals), and file import/include/require is a classic example.

This is one of the most fundamental features of the language, and it’s screwed up. It “seems” to work, so long as you write simplistic enough / small enough apps. The bigger your app, the more likely it is you’ll discover how poor this part of the language is.

Categories
PHP programming security

PHP: Anti-spam CAPTCHA using photos

I’m just finishing up a quick PHP project at the moment, which allows anyone to register an account – so as the final step before launching it, I needed to add some form of CAPTCHA system. I tried a couple of 3rd party ones and source code ones and none quite worked for me. This post gives full source for a simple user-friendly photo-based CAPTCHA in PHP. Use at your own risk – but it’s short and easy to integrate.

NB: this was more a quick-and-dirty practice exercise than a serious attempt at a CAPTCHA. I don’t believe in CAPTCHAs, generally – but if you ARE going to use them, it’s best to have a lot of them in the wild, so it’s harder for crackers to do “crack once, spam everywhere”. See the section at the bottom for links to suggestions for other people’s CAPTCHAs that I reckon would be better for production use if you can get them to work :).

Categories
bitching dev-process fixing your desktop iphone programming

Unity: First impressions

I had to do some iPhone prototyping recently, and we had a trial copy of Unity to hand. I thought this was a great excuse to try using it. First impressions of the editor/IDE/environment – at least on OS X – are not good.

NB: In general, in terms of what can be done with it etc, I’m a fan of Unity. But I’ve never developed with it directly myself, and I’m now finding it surprisingly painful / steep learning curve.

Need to know basis

None of the built-in tutorials work, flat out, because the startup code has apparently changed substantially since they were written. The tutorials keep talking about things like “create a new project; by default it will X and Y and Z” but Unity no longer does any of those by default. Sadly, the tutorials don’t tell you how to get any of those manually – because, you know, they’re done for you by default, why would you ever need to know how to do them by hand?

File Association Theft

I was also *extremely* unhappy to discover a short while later that Unity has stolen the file association for PHP files. Under OS X (thanks, Apple) managing file associations is a surprisingly irritating business, as bad as with Microsoft Windows (Apple deems users too stupid to be allowed to simply edit associations – but applications are allowed to overwrite each other with absolute trust from Apple, and no user intervention allowed), so this is a pain to fix. In particular, I have an entire *suite* of applications and IDE’s for doing web editing, including a specialized high quality PHP IDE. Not any more; Unity has clobbered that with a crappy text editor that does nothing more than basic syntax hilighting. This is pretty offensive: firstly, don’t steal my files without asking, and secondly – give me back my IDE!

NB: I have no idea how it has done this, but Unity appears to have overridden OS X’s systems for file association management – following the standard procedure (e.g. here) has no effect, and Unity keeps stealing control of the files immediately that you confirm you want to give the assocation to some other app.

At this rate, if I can’t find out what it’s done to my OS and undo it, I’ll be uninstalling and deleting Unity with extreme prejudice in the very near future. Sure, this is partly Apple’s fault for assuming all apps are perfect and all users are not, but at a simpler level I just cannot afford to have a non-functioning development computer just because of one badly behaved application.

Categories
PHP programming

PHP: how to fetch all possible values of an ENUM from MySQL

Sadly, the code snippets on MySQL’s main website for PHP are mostly untested and buggy (try running them – half of them don’t execute because of silly mistakes).

After much trial and error, here’s one that *actually works*:

// Missing feature (?) from MySQL: find the list of valid ENUM values for a given ENUM
// (actually, returns all the value-arrays for ALL the enum fields in a given table, by name)
// ---------------------------------------------------------
function fetchEnumValuesForTable( $tablename )
{
	global $db; // assuming you're using PEAR:DB here, and throughout (I use it, or MDB, exclusively)
	
	$enumresult = $db->query("SHOW COLUMNS FROM $tablename");

	// Makes arrays out of all ENUM type fields.
	// Uses the field names as array names and skips non-ENUM fields
	while( $enumrow = $enumresult->fetchRow() )
	{
		extract($enumrow);
		if (substr($Type, 0, 4) != 'enum') continue;

		$Type = str_replace('enum', 'array', $Type);
		
		// Add to array
		eval( '$tmp = '."$Type;" ); // I'm not sure why, but I had to do this
		// intermediate step to get it to work
		
		$results[$Field] = $tmp;
	}
	
	return $results; // returns an array mapping each enum's "column name"
	// to "array of elements valid fo that ENUM"
}
Categories
iphone programming

Using shared libraries for iPhone with multiple projects

You would think this is easy, seeing as how it’s an essential, simple, part of any programming project. HA! You obviously haven’t used Apple’s shockingly bad IDE (Xcode) much, have you?

You can read the extremely widely-linked blog post – http://www.stormyprods.com/blogger/2008/11/using-static-libraries-with-iphone-sdk.html – which is incomplete, and doesn’t work properly if you want to do auto-updates when source changes (which, in most cases, you do). Unfortunately, it doesn’t give any pointers to making linked projects work. I don’t blame the author for stopping at that point, their solution “works”, but I wanted to get the full benefits of auto recompilation.

You can google to try and find some documentation from Apple. I can’t find any, although I can find lots of other people on forums asking for documentation on how to do it themselves.

Eventually I worked it out, after hours of trial and error, and reading as much of the Xcode docs as I could find that seemed to relate to what was going on.

  1. Make a new project to hold your shared library
  2. Put all the .m and .h files for your library in that project (drag/drop them to the groups and files list)
    • XCode “feature”: it will by default fail to copy the files, even though that means everything will break later on, when you delete the originals. You need to tick the “copy files if necessary” checkbox)
  3. Create a “Static Library” build target
  4. Drag the .m files *only* to the static library build target’s “sources” twisty
  5. DO NOT DELETE THE FILES FROM THE MAIN PROJECT (because you’ve just created references, not copies, although it doesn’t tell you that … so Xcode will silently delete them everywhere, and OS X still doesn’t support undelete; Sulka tells me that Undelete will be coming to OS X in the next version. Oh, how I laughed)
  6. DO delete the files from the main Build Target
    • (again, they’re not actually files there, just references, so “deleting” them merely gets rid of the reference, not the file)
    • is this another bug in XCode? It seems strange that you use the “delete” funciton to do something that isn’t really a delete
  7. Click the NEW build target (the static library) and right click and select “build”.
    • XCode “feature”: if you highlight the thing you want to build, and hit Cmd-B to build, it WILL NOT BUILD the selected target, it will instead build the main target and ignore the target you actually wanted built
    • The *only* way to make cmd-b build the thing you want is to change some of the options on the Target dropdown at top left of the window – but you’ll have to change it back and forth each time you want to build somethign different with cmd-b … there seems to be no context-sensitive Build command in Xcode (bug?)
  8. If you want to test that your static lib built correctly (hint: you probably do)
    1. Add the static library to the main target
      • XCode bug: you can add the static library to the “direct dependencies” section. This has no effect; don’t do it. The static library MUST be added to the “linked libraries” section, i.e. the bottom panel of the General tab of the Inspector for the Build Target
    2. Write some code that uses your static lib – I suggest putting it in the app delegate class that Xcode auto-generated when you created the new project – and try building the main target (you CAN use cmd-b for this … unless you switched targets above, in which case you’ll need to switch them back first). If you have added the static lib in “the wrong place” or created it “in the wrong way” then this will fail with missing class errors etc

    All that has achieved is to compile your source code. No, seriously – it is THAT HARD. Now you have to actually try using it from another project.

    This is where the StormyProds link takes the easy way out (which only partially works): it simply copies the .a file (generated by the compiler) to somewhere on your hard disk, and has you hard-link to that file from other XCode projects. This will work; but it will also get out of date rapidly, and cause all sorts of bugs if you forget to update it. It will never auto-compile when there are changes.

    What Apple wants you to do (and for once I agree with them :) – this makes sense for most developers who aren’t using an external build system) is to link the projects directly, so that changes in one cause the other to automatically recompile *if necessary*.

    NB: for all my disappointments with Xcode, this is one feature I think has been extremely well done – it handles “links” between discrete Xcode projects extremely well, and (although the menus and docs for it are a bit hard to find) it mostly Just Works.

    1. Link the two projects
      1. Following Apple’s instructions here: http://developer.apple.com/DOCUMENTATION/DeveloperTools/Conceptual/XcodeProjectManagement/040-Files_in_Projects/chapter_5_section_7.html#//apple_ref/doc/uid/TP40002666-CJBJHJCJ – i.e.:
      2. Open the project that will import the static library
      3. Go to the “Project” menu and select “Add to Project”
      4. Find the .xcodeproj file on your harddisk that representst the other project, and select it
      5. Check it worked:
        • At the top of Groups and Files panel, you should see a blue twisty for your project, and just inside it a blue twisty for your imported / linked project
        • Inside the second twisty MIGHT be a .app file (representing the main target of the imported project, which you won’t need – you MIGHT have created a project wihtout a main executable, or deleted the spec for it, but by default you’ll have this)
        • Inside the second twisty should be a .a file (representing the static library from the imported project, which you DO NEED)
    2. Make the secondary project import the compiled static library from the first project
      1. Drag the .a file from inside the second twisty, and drop it inside the “Link Binary with Libraries” section of the main Build Target of the main project
        • DO NOT drop it anywhere else in the Built Targets section – it will work, but will have no effect (you do that in the next step)
        • If you do it correctly, you should see the static library appear with the same icon as each of your included Frameworks (all iPhone projects have at least 2 Frameworks normally: UIKit.framework, Foundation.framework), and appear right next to them in the same twisty underneath Build Targets
        • ALSO open the inspector for your build target and add a second dependency in the main dependencies section to the static lib – NOT the app – from the imported project.
        • (if you don’t do this, you’ll see weird things like the build compiling for iPhone, but not for the Simulator, for no apparent reason)

    Finally … drag and drop the header files from the original project’s location in Finder into the new project’s source folders. Do NOT check the “copy files if necessary”. Xcode will do a reference / softlink, so that changes to the header files in the original project are picked up. NB: you will need to do a drag/drop each time you add a new header file to the original project.

    (You *might* be able to get away with putting all the header files in a sub-fodler of their own in the original project, and drag/dropping that FOLDER into the new project, but … I tried that, and it seemed to sometimes fail to notice the new header files, so I’m not sure I’d risk it).

    Some fun errors:

    Line Location Tool:0: “_OBJC_CLASS_$_ScoreUploader”, referenced from:

    Various causes of this useless error message:

    1. you added a class to the source project … but forgot to drag/drop that .m file into the “Compile Sources” part of the Target for the Static Library in the source project (or you did so, but you didn’t link your xcodeproj’s directly … but forgot to recompile the source project (linking the projects, as described above, triggers auto-rebuilds and you dont see this problem so often))
    2. you had all the source in one project originally … but haven’t deleted FROM YOUR HARD DISK the source files for the source inside the original, main project

    (this is IMHO another bug in Xcode: it silently leaves the files in place, by default, and yet silently (secretly) uses them when compiling – but ONLY when dealing with imported libraries, NOT when dealing with local compilation. Huh?)

    Line Location Tool:0: literal-pointer@__OBJC@__cls_refs@NSMutableList in libhiscorelib.a(XMLSuperParser.o)

    You haven’t added the static lib as a non-lib dependency

    Some things to be aware of

    The header files that you drag/dropped from one project to the other have NOT been copied to the new project and are therefore NOT real files – they are references.

    If you delete the original files (in the statically compiled lib project) then the references in all other projects will vanish; be careful!

    If you updarte the original files (in the statically compiled lib project) then the referneces in all ohter projects will automatically update (with no UI indication of this).

    Unlike most normal IDE’s, there is no obvious UI indication that the files are not inside the current project (you can check by doing cmd-i on any of the files and looking at the value of the “Full Path” field, but otherwise you won’t see a difference).

Categories
agile games design iphone programming recruiting

iPhone Creators: Brighton pub meet March 9th

http://upcoming.yahoo.com/event/1917163/?ps=5

If you have any interest in iPhone development (you have ideas for apps, or you want to start coding for your iphone, or just want to meet other like-minded folks over beers), then come along.

Bring friends. Bring iPhones (I’ll bring my laptop so you can download and try my current work in progress)

If you’ve got anything you’ve made yourself, definitely bring it along!

We had a quiet first meetup last night, I’ll be adding screenshots / app descriptions for the two apps shown on the night to this post later.

EDIT:

Snooker Scorer

snookerscorer1 This is a simple app that keeps score of a snooker match. You can use it in a club, watching a match live or even following on tv.

Just tap the ball that has been potted. Hit the ‘swap’ icon to swap players. If a foul happens, hold the ‘foul’ icon and tap the ball fouled. Free balls can be added as well through the popup actions icon.

Future additions will make the information line adapt to show the most relevant info such as current or maximum break, difference and points remaing, balls potted in current break, match history, undo mistakes, and whatever else I can think of.

Categories
bitching programming Web 0.1 web 2.0

phpMyFAQ: don’t use it, part 2

Disappointing

No spam filter (there is one, allegedly, but it’s invisible, non-configurable (!), and missing obvious spam words)

(there are comments on the official forums from 3 years ago saying “we need some basic anti-spam tools” and the author replying with “we’re working on it”)

Annoying

No spam controls for reactive processing (banning users, marking comments as spam, etc).

Unforgivable

Each comment can ONLY be deleted one, by one, by one, requiring 6 mouse clicks per deletion!

The concept of a list of comments, and a checkbox next to each, and a “delete selected comments” is now well over 10 years old – and it only takes a few minutes to implement with PHP + SQL. If you ever find yourself making a web app for general usage, please don’t forget this core feature :).

(I’ve been too busy for the past month making actual iPhone apps to finish my free PHP FAQ platform, but watch this space, shouldn’t be too long now…)

Categories
iphone programming

High Score Server for iPhone (free)

I’ve made a highscore system for iPhone, complete with registrations, email confirmations, global highscore board, and iPhone client-side rendering.

I’d like to make it available as a free service (it’s live already, and included in a game I’m about to publish). I’m looking for volunteers who want to try integrating it into their games.

If you are such a person, or know someone, drop me an email (adam.m.s.martin at gmail).

A couple of very basic screenshots to give you an idea of what it does at the moment:

Admin features

In-game UI

(I’m not sure how much of this I’ll put in the download, but I’ll at least give you working sourcecode for it all and you can customize the UIView instances to display whatever you prefer)

Categories
agile dev-process programming web 2.0

PHP: Looking for some Best Practices

PHP is weak, crappy, and encourages people to write terrible code. But … if you know what you’re doing, all of those might actually be really really good things.

(by the way, if you haven’t already, you should read Eric Ries thoughts on PHP…)

“Best Practices” are one of the best guides you can get for sailing between the Scylla and Charybdis of “crap code” and “over-engineering”.

So I’d like some, please.

Perfection

Anyone with zero computer science education can write crap code; that’s easy. At the other end of the spectrum we have the people who write Perfect code.

Anyone who writes perfect code is either:

  1. a liar
  2. too rich to work for money
  3. works in an industry that is immune to marketing

…because marketing is always a cheaper and more effective way of making more money, compared to writing “perfect” code.

(disclaimer: in the past, I’ve been the first, and lusted after the third, but never quite managed the second)

The skill that marks out the difference between a competent programmer and a good (or great) one is knowing which of the language’s strengths to play up, and which to play down. Sometimes, the fact that a language allows extremely sloppy code is a very good thing. e.g. most scripting languages – especially any that run on an “intelligent” runtime like the truly Awesome JavaVM – where being grossly inefficient is not only “OK” but in fact “doesn’t happen”, because once it notices what stupid thing you did, the runtime silently recompiles everything into decent C code while you’re not looking.

So … how the heck do you win?

You look for Best Practices, language-specific (and domain-specific, but that’s obviously of more niche value).

I recently did two moderate sized PHP projects. I figured: OK, so PHP is very easy to hack code together knowing very little about the platform (and I’d been using my Perl experience most of the time when writing PHP) – but Perl showed us that Best Practices are damn useful and not too hard to stick to. There must be lots that the PHP community has worked out by now!

(as Quake3 would say, in a bass rumbling voice:) Denied!

Um, no. Apparently not. Google – with *considerable massaging* – threw out a few dozen attempts from different people.

There was some interesting stuff in there. I found some obscure bits of standard and near-standard extensions I hadn’t noticed previously when reading the manuals.

But, to be honest, nearly all of it was a waste of time – it simply wasn’t PHP specific. Telling people that they should “document function headers” is meaningless as a “PHP Best Practice”. It’s not a PHP Best Practice, it’s a general programming practice. You can find it in *any* textbook (and if you don’t know stuff like that, I suggest you go read a few key books like Code Complete, for starters).

There’s also – and this quite upset me – a lot of BAD practice out there being passed on from PHP programmer to PHP programmer and hailed as if it were “a good thing”, when often it’s about as wise and valuable as staring down the barrel of a loaded gun so you can see better while you clean the inside.

What is PHP good for? Why?

I have recently realised that the majority of PHP programmers cannot answer these questions, and that many of the rest aren’t great at answering them either. If you can’t answer them, you can probably never be a great PHP programmer, and it’s debatable exactly how “good” you are. (/me ducks and runs for cover)

I’ve not done enough PHP to know what it does from the inside.

But I’ve done tonnes of code in “languages that are not PHP”, and I have a really really good idea what it does from the outside. And most of the Best Practices I saw for PHP were stolen from other languages (especially C derivatives) and are totally inappropriate for PHP. Because PHP is not C, and PHP programmers will never be decent C programmers, no matter how big their inferiority complex, and no matter how hard they slave to try and write “high quality code”.

Some things PHP is good at: (in no particular order!)

  1. It’s a Scripting Language (like JavaScript, and ActionScript, and Perl. But not like C, and not like C++, and not like Java)
    • It’s intended to be trivial to read and write code; the core language is “easy for a non-programmer to grasp”
    • There’s no feature in the language that requires thinking to understand what’s going on, by design (unfortunately, some of the libraries broke this. c.f. the great Register Globals disaster too)
    • idiots can code effectively…
    • …which means that highly intelligent individuals who were never trained as programmers can ALSO code effectively, with minimal pain and suffering
    • …and that changing (modifying, fixing, extending) other people’s PHP code is trivially easy
    • There’s no compiler. No cached builds. What you see is what you executed, literally.
  2. It’s very easy to grasp two of the three most important structures of a web application (the third one is “data flow” – PHP sucks at that one). The two it does great are “program logic” and “program inputs + outputs”; together these sum to “execution structure”
    • One page == one source file : you read an output (FORM or A link) to an HREF? Or a page is crashing in the browser? You know exactly which file to find it in
    • One source file == one page : all the logic (PHP tags) and the input/output parts of the user-interface (HTML tags) are in one file. So you can’t make assumptions and the resulting mistakes
  3. It’s a context-free language. This is a by-product of being so tightly integrated with HTTP/HTML. It is one of the things that “real” programmers sneer at PHP for – how can you have a context-free language that isn’t Functional and expect it to be any good? That’s some kind of mutant offspring of Fn and Imp that ought to be strangled at birth. Or … maybe … just maybe … it’s one of PHP’s greatest strengths (although admittedly it is a mutant offspring too)
    • When a single source file is executing *there cannot be any other context* (except for the Session, sadly – but this is a strange piece of context-that-is-not-context because of all the rules about what can and cannot be in a session)
    • Oh, OK: there cannot be any context from other threads, other users, other simultaneously executing code. This is one of the hardest, nastiest parts of all systems languages, the multi-threading stuff. And PHP completely wipes it out as a problem. Nice.
    • All source files – hence all user-interaction points – are (semi-)atomic by definition: either they execute, or they don’t (by default, if they start, they dont stop, not even if a crash-level event happens; more on that later)
  4. Code is mingled with presentation, but is “together but apart” because it’s guarded (in the computer science meaning of that word, sort-of) by enclosing magic PHP tags
    • You can copy/paste move around code without the risk of it becoming part of the presentation code (this problem happens A LOT (and causes some awful security holes and application crashes) in some languages, especially in templating languages, even though it seems like such a simple thing. I kid you not.)
    • Any decent IDE (/wave at Eclipse (download PDT to add PHP to it)) can do a lot better at second-guessing what the programmer wants to type next, thanks to the explicit context of being either “in code” or “in presentation”. Saves a lot of time, in very small pieces many times a day.
  5. It’s a mainstream scripting language: very very fast to write code, code is very very fast to read + understand (it CANNOT DO complex things like STL or Operator Overloading), and you can “make it up as you go along” when writing a program – it doesn’t expect you to plan ANYTHING in advance
    • No declarations : you don’t have to plan your variables in advance
    • No declarations = faster “flow of mental programming” : you can aribtrarily change your mind “mid sentence” when writing code, and not have to move backwards in the source file to fix a declaration as a result
    • No memory management : you don’t have to plan the LIFECYCLES of your variables in advance
  6. Writing basic imperative code. Fast. (Imperative == “not Functional”; if you don’t know what that means, look it up – Fn programming is awesome)
  7. Templates for pages.
    • If you’re going to use a template method (or, god forbid, “library”) in PHP, make sure that its source code looks *exactly like PHP*. Because PHP is an excellent templating language.
    • This begs the question of “why aren’t you just using PHP in the first place, fool?”. The answer to which is usually “I didn’t read Adam’s Best Practices on this website and wrote long waffling PHP source that no-one could understand”, or “I have some truly stupid accomplices who will overwrite the PHP tags whenever they see them, just for fun” (anyone using DreamWeaver has almost certainly done this at some point, without even realising it; in that case, it’s not the human’s fault, it’s the fault of their editing software – DW – but the PHP programmer can’t really tell the difference, it’s the same net effect)

Some things PHP is bad at: (in no particular order!)

  1. NOTE: just because PHP is “bad” at something does not imply that this is a bad thing about PHP!
  2. OOP. PHP is poor at OOP. It’s not as bad as Objective C (which is terrible) nor Perl (which is horrifically awful at OOP), but it’s not part of the core language, and it shows.
    • Actually, I don’t even know what to say here. Go on a long rant about how it should look like C++? Hmm. Not really helpful. I’ll just leave it at that. If you *really* need to ask why PHP’s OOP is bad, it’s going to take more than a couple of bullet points to explain it to you.
  3. It’s an “old fashioned” scripting language; it lacks some so-called modern features (many of them are older than the microchip but took a few decades to make it into mainstream programming)
    • Closures? Where are my closures? : without this, it’s much harder to write self-adapting code, and much harder to write code “for other programmers to extend and alter without needing to change my source code”
    • No OOP scripting : without this, OOP is a pain in the ass, taking a lot more typing, and standing out like a sore thumb inside any PHP file
    • No modern Array derefence syntax : (you have to do: “${arr[‘var’]}” instead of: “$arr.var”) this makes getting data out of arrays so hard that people go out of their way not to use arrays in PHP.
  4. Data flow (the third prong of three mentioned in the Good bits section)
    • SQL in PHP is not fun : it’s all manual SQL statements, with practically zero language-level support (check out Perl::DBI for an example of how funktastic language support for SQL can get; I didn’t say “good”, I said “funktastic”. There’s a difference)
  5. Distribution
    • There isn’t any. PEAR doesn’t count – and if it did, well … PEAR has one of the most appalling distribution systems I’ve seen in about 10 years. The fact that I had to hack PEAR’s installer – in 2008 – just to “not crash” let alone to get it to “start installing” says it all, really.
    • No package management. No bundling. No metadata. No repository (PEAR or CPAN? take your pick. I find both fine as manual systems, and frequent failures as automated systems).
    • (if you still don’t believe me, find yourself a Debian sysadmin and ask them to show you Aptitude, a worn-out decade-old text-based front-end to apt. And marvel at how fantastic it is despite all that!)
  6. Register Globals fiasco : the maintainers killed some core features of the language in an attempt to fix a security hole, instead of just fixing the security hole
    • Sadly, the core libraries now force you to use Arrays for evertying, because the language maintainers panicked over Register Globals and destroyed the whole input-sampling system.
    • …which is bad because of the lack of Array-de-ref syntax in the language (see above)

A quick retrospective

If you’re a PHP programmer, I hope you’ve already noticed the implications of some of the good/bad points I hilighted.

There are things that a lot of the PHP community loves with a lack of reasoning that sometimes borders on obsession/fetishism, but which – from the above analysis – are inappropriate for PHP. I’ve tried some of these, and confirmed: whoever thought this was a good idea was either smoking crack or didn’t understand how to build web applications.

Some quick examples:

  • Page Caching. You gotta be kidding me. There’s are plenty of reasons that all other languages push this OUT of the language, and OUT of the application, and most of them apply equally to PHP. Use Memcached instead, and learn to use it properly – that is, externally, not internally.
  • Separating Code from Data. As a gross generalization, if you do this, you should stop writing PHP, because you just threw away most of the benefits of PHP, and you’d be better off writing J2EE from this point on – you’d get the benefits of J2EE and of the Java language AND of the Java standard libs (which kick the living daylights out of PHP’s weak set of “Extensions”) – and you’d hardly lose anything in the transfer.
  • M/V/C architectures. If you do it the way we do it in other languages, then it’s equally stupid as the above point. It *can* be done, conceptually, in ways that fit with PHP – but the majority of PHP systems I’ve poked inside didn’t get that clever, they just tried to do it the traditional ways.

By The Way: I’m probably wrong on some of this. I haven’t spent much time thinking about it. Unfortunately, I’m not sure at this point which points are where I’m Totally Right, Dude, and which ones are where I’m Smoking Something Funky.

Sorry.

Too many words! Argh

I keep being told off (nicely) for writing blog posts that are too long.

In petty revenge, after making you read through the rant-tastic introductory bits (I have my Asbestos suit at the ready…), I’m splitting the rest into a separate post. I almost feel bad about doing this. Almost.

So, on to … PART 2: Best Practice for PHP Programming!

Categories
programming server admin

How to install PEAR on OS X 10.5

The simple guide I found here doesn’t actually work, although it “mostly” works. Several bits are out of date. Even then it only *partly* works, because it leaves all PEAR commands as requiring root to run. That may be what you want, but I doubt it. Not what I wanted.