Questions and Answers
"Make everything as simple as possible, but not simpler."
- most recently attributed to Albert Einstein, but variants date back as far as Occam, Aquinas, and Aristotle
This page documents the rationale behind many of the decisions about JIFFEE, rationale that would otherwise be hidden or forgotten. Most of it will probably be of interest only to people really interested in framework and library development, but at least this records the information so it doesn't get lost.
Precise communication requires precise language, so I choose my words very carefully (sometimes even to the extent that I annoy my friends). Most of the questions here are unlikely to be asked "frequently" so the term "FAQ" would not be accurate.
I don't. Like virtually every IF author, I'm doing it as a labor of love and because I want to give something back to the community.
That's a valid question, because it's a waste of effort to develop multiple systems that all do basically the same thing. However I believe that systems like TADS, Inform7, and JIFFEE are each exploring different aspects of the design space, so — to stretch an analogy a bit — rather than reinventing the wheel each of them is experimenting with new ways of using wheels. In addition, the purpose of JIFFEE is not to "poach" existing users of other authoring systems; I don't expect anyone who is happy with a system like Inform to switch to JIFFEE, nor do I want them to. My goal is to appeal to people who have never written any IF before, and thus to make the pie bigger rather than than redistributing the existing pie.
I've tried to keep in mind a rule of thumb from John Gall's Systemantics: How Systems Really Work and How They Fail:
"A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system."JIFFEE started very simple and is still relatively early in its evolution, so it's quite possible that there simply hasn't yet been time to add a particular feature.
I've also tried to follow a general principle that it is better to provide a few powerful features and many specific recipes, rather than many specialized features. Thus there are many features that I will deliberately never implement because it would add unnecessary complexity to the system, but instead there will be a recipe in the documentation that explains how to achieve the effect that you want.
Finally, the extension mechanism is a better way to add features that are useful but only to a limited number of authors. Because you have access to all the code and a full programming language, this is a very powerful mechanism.
An idea, like a baby, is fragile and vulnerable when first born. It needs time, often a lot of time, to find itself and grow strong enough to benefit from criticism. During the first 3 years of development, the flaws and shortcomings in JIFFEE were so obvious even to me that I really didn't need any help finding them. :-) Those early implementations were so rough that they would not have convincingly communicated or demonstrated the ideas I was trying to wrap my head around — I wasn't even satisfied with those implementations myself. Once the system began to mature a bit, then it was (will be) solid enough for constructive criticism to improve it. One good indicator was when I started ripping code out instead of just adding more, since that usually means you're starting to understand the problem.
A second reason for waiting until JIFFEE was reasonably complete and functional is that you only get one chance to make a good first impression.
The current name has the following nice properties:
I wanted a logo for jiffeegames.com that would provide a gentle cue that you're still on the same web site without being visually intrusive. If you put your logo at the top of the page in the conventional way it disappears as soon as the user scrolls, so I decided to put a tall skinny logo off to one side where it doesn't demand attention but is always visible. (Putting it in the left margin also helps if you want to print out hard copies of the web pages, since it allows you to punch them for a 3-ring binder without losing anything important.)
The final design is my homage to the original Adventure game: You're in a maze of twisty little passages, all different ... Each circle represents a room, and under the constraints I chose for determining which paths are legal, there are 81 unique ways to connect two consecutive rooms in the sequence. In keeping with the spirit of "all different," the logo includes each of the 81 ways exactly once before the whole logo repeats. This ensures that on any but the very largest displays, the paths visible at any given time within a single window will indeed be all different.
The same theme is echoed in the favicon, where there is only enough space for two rooms and their connected passages, but that's just sufficient to form the shape of a "J" for "JIFFEE."
Because I use UTC. You must have been in the Americas, where it was still yesterday.
Yes, but I prefer a lean web design that doesn't distract you from the content. Besides, it really doesn't cost much to run such a small web site, so there's no need for it to pay for itself.
It's worth the effort for every page. Much of the hard work you put into creating a web site is wasted if some of your potential viewers can't see it properly. Of course it's important to test on as many browsers as you can, but with so many different browsers in use the single most effective way to increase accessibility is to formally validate your HTML (and your CSS). As you can see from the Web Site Validation page, for a site of modest size it's surprisingly easy to do and it will pay dividends in maximizing your audience.
Of course, if you really want to come across as a pro, check for dead links and run a spell-checker while you're at it. Your web site is your only chance to make a good first impression, so make the most of it.
"Everybody" knows that it's better to split up your files — if you control all the files and if you expect people to load many pages that share files.
In this case, no single person controls all the files: you control your game code, and I control the JIFFEE library code. I don't want the correct and predictable functioning of your game to be at the mercy of changes in JIFFEE, and I in turn want to be able to improve and update JIFFEE (even in incompatible ways) without worrying about breaking your game. Putting the whole library into your HTML file is the equivalent of static linking and protects you from changes.
Of course you could just make local copies and link to those, but that would make game distribution more awkward (you'd need to distribute a whole directory instead of a single file), and there's little to be gained. Unless someone is going to play multiple JIFFEE-based games, all from the same site, one after another, there's nothing to be gained at all.
With the entire JIFFEE source code incorporated into every game, aren't I afraid people will start tweaking it for individual games? Not at all; if anything I'm afraid they won't. I'm sufficiently realistic to know that most authors will have little desire to mess with low-level code, but I'll be a bit disappointed if nobody tries to modify it. JIFFEE is designed to be malleable to encourage experimentation and innovation, and when someone implements an idea that works out well, it should be easy to incorporate that back into the main system.
There is also a "string obfuscation" feature planned which will make casual cheating much less tempting.
The extensive error checking is an attempt to compensate for not having control of the language parser (since JIFFEE is not a language). There is a modest cost (increased execution time) but I feel that price is well worth paying in exchange for helpful error diagnostics. As for turning them off, the proper time to do that is after you've found the last bug — and we all know that in practice you'll grow very old waiting for that to happen.
At first I didn't, although I was pretty religious about backing up my hard drive. As a system gets bigger, though, the changes and refactorings get bigger, and the odds go up that someday you're going to change hundreds of lines of code and then realize "Oh no, that was a terrible idea. I wish I hadn't done that." Subversion gives me a clean way to back out mistakes, even big ones. It also provides a history, in case anyone ever cares - and sometimes you actually do want to go back and review the details of some dimly remembered change from six months ago. You still have to back up your hard drive, though.
Case in point: Three weeks after I started to use subversion, a shell script I was updating ran amok and destroyed the contents of almost every one of my web pages. Although the previous day's version was safe on the web hosting server, I was very glad I had done an "svn commit" on my development system only a few minutes previously, so that I didn't lose all the other work I had done that morning.
Someday it probably will be, but as a prototype it's still too squishy and changes too often for that to make sense. You can already read every line of source code and even play around with the code yourself, but until the design stabilizes I'm afraid that allowing redistribution could lead to multiple incompatible versions proliferating and that wouldn't be good for anyone. I'm keeping the "all rights reserved" in the copyright notice so that when I do decide to open the source, I will be free to choose the best license without being hamstrung by any previous loose copyrights.
Yes I do agree, and thank you so much for offering to implement it. :-) But seriously, developing a decent IDE for anything is an enormous effort that I simply don't have the time to take on. Creating a nice development environment would be a worthy and productive task, but I've chosen to focus my limited resources on different aspects of IF authoring.
Besides, three of the major advantages of an IDE are already at least partially available in the current JIFFEE system:
In any effort there is a point of diminishing returns, and for normal browser-based software you can assume that most of your users are running a relatively recent version of a popular browser. Testing on a lot of older systems would affect only a very small percentage of your potential users, and thus would be a poor use of effort that you could more productively invest in adding features, improving documentation, and so forth.
JIFFEE faces somewhat different trade-offs. It is intended to be especially useful in schools, and schools are often woefully underfunded and thus forced to get by with outdated and obsolete software and hardware. This isn't true of all schools, but students in the districts sufficiently well-funded to have good computer labs are going to get a good education anyway. I'd like JIFFEE to make a contribution to the students who need help the most, i.e. the ones in struggling schools.
Absolutely, because the extent of my cross-browser compatibility testing far exceeds normal standards. Fortunately, that kind of testing is unnecessary for game authors, for the following reasons:
To use any IF authoring system, you have to learn a little bit of something. That something may be a formal language (even if it looks a lot like English but really isn't) or a system of GUI menus and dialogs, but one way or another you have to learn something. An important goal of virtually every authoring system is to make that something as simple and easy as possible.
So to answer the original question, no it does not defeat the purpose. You don't have to learn much to get started, that little bit is no harder than any other system, and the growth path as you become more ambitious is actually smoother.
The second issue is making the authoring system accessible. JIFFEE is intended to be useful in education, which means it must be easy for teachers to bring into the classroom. One problem is that some teachers are still learning about computers themselves so simpler is always better, but a bigger problem is that in many school systems the computers are "locked down" so teachers cannot install random software on them. Only the official IT staff is allowed to change the configuration, in order to maintain some semblance of consistency and make support manageable. (In a small school the IT staff may well consist of of one math teacher staying late on Friday, and in a large system it might be 10 full-time techs supporting 10,000 machines spread across 100 buildings, but either way you can safely predict that they're understaffed.) You and I could have a long and interesting discussion about the pros and cons of such a policy, but the bottom line is that we have zero influence over it. If we want to play on their playground we have to play by their rules, and those rules often say "web-only."
I could have used some other consistent syntax, like noun.trait = "value", but if I'd done that the error messages would stink. Good diagnostics are one of the toughest nuts to crack when not inventing your own language, so it's really important that I do the best possible job with whatever tools are available. Making everything be a function call allows me to intercept everything the game author does and inject a lot of consistency checking on all the arguments, especially on the names of things like nouns and traits, so I can produce far more helpful diagnostics when the author misspells something or tries to assign an illegal value.
Because I had no choice. Multilingual support is one of the biggest design goals for JIFFEE, and if a game is going to work in multiple languages the handling of language-specific strings had better be very, very clearly separated from the processing logic. Creating such a really clean division between syntax and semantics is hard, but any fuzziness here will lead to real nastiness in the code so the effort is well worth making.
Using this standard hash algorithm allows JIFFEE to provide strong protection against accidental collisions, but if you want to create a collision deliberately, no fingerprints will stop you. Since the game source code is readable, a malicious author can simply mimic the names of nouns and traits of the game with which he wants to collide. Although other members of the SHA-2 family are technically more secure than SHA-224, they have bigger fingerprints, and there is no point in consuming extra bits in the cookie to prevent incredibly rare accidental collisions when deliberate subterfuge is far more likely. (If some low-life does try to do this, all you need to do is ban him from the archive. The cookies can only collide when both games are hosted on the same domain.)
A more interesting question is whether it can be embedded into programs written in other languages, and the answer is: probably. I haven't played with it myself, but I expect that by using Rhino you could fairly easily embed JIFFEE into an arbitrary Java program. If you try it let me know how it works out.
Any designer must choose between a traditional programming model and a rule-based model, or some mixture of the two. Both approaches are workable and each has advantages and disadvantages, so there is no clear-cut right or wrong choice.
At first glance, writing rules may seem more intuitive, but for simple situations both ways yield acceptably simple results so you really need to look at the complex cases to appreciate the differences. The key observation is that both approaches are formal specifications of behavior that, when sufficiently complex, can yield unexpected and surprising results that manifest themselves as program bugs.
I have some limited exposure to a large, purely rule-based programming system, and it was not a happy experience. Once you have thousands of lines of code, I personally found writing and debugging with such a system to be no easier than working with a large traditional program, and if anything it's harder because the relevant code can be spread out among a large and hard-to-identify set of rules instead of being localized in procedures or functions that can be traced in a more straightforward way.
An additional consideration is that most IF authors won't have a lot of mentors available who have experience with any rule-based system, so if an IF authoring system is understandable by traditional programmers it will be much easier for an author to find someone who can help him or her track down the inevitable obscure bugs.
Considering all these trade-offs in the design of JIFFEE, I opted to incorporate just enough of the rule-based approach to take advantage of its strong points, but I made that part very constrained and stylized with clear ordering rules to make it easier to understand. Then I kept the rest of the system structured in a more traditional way to make JIFFEE games simpler for the average programmer to debug.
It's good programming practice to have clean separation of modules and to use consistent designs. Even more importantly, relying on the extension mechanism throughout the system is the best way to make sure that your mechanism really works correctly and is comfortable to use. (And in fact the design of the extension mechanism has already benefited enormously from being exercised by the core system.) Looking ahead to a day when JIFFEE will likely be Open Source, this also makes it easier for people to hack the core system if they want to experiment with modifying parts of it.
This was a personal choice. There is no law that prohibits mutual or other circular dependencies, but I find that the discipline of removing those leads to simpler, clearer designs. In addition to doing the dependency injection, the module interconnection mechanism also allows you to do module initialization and system phase change (from initializing to running) in the same simple, clearly-defined order. So far nearly everything in JIFFEE has fit fairly well into that pattern.
There are two standard ways of "wiring together" a bunch of modules which call each other's methods, both of which are simply different ways of injecting dependencies. Both have problems:
The simplest way is to pass each dependency as an argument to the constructor (or to an init function). This works, but if you have a lot of small modules this method creates the ugly "long parameter list" code smell, and it's a major pain to keep all the calls in sync when your software is in constant flux and the dependencies keep changing.
Another common method is to pass a service locator to each module in the constructor or init function. This is simple and avoids a lot of code churn during development, but it hides the dependencies and allows anything to depend on anything, introducing many of the same drawbacks as global variables.
Implicit in all this is the assumption that modules are objects, not namespaces or global libraries. This is what allows you to do nice unit testing, so it's an important property I wanted to preserve.
I wish it could, but there is a chicken-and-egg problem here: If a constructor or an init routine is called incorrectly, I want to produce an intelligible error message. The routines that do that are non-trivial and are in the Checks module, so they would not be available when needed if the service locator was used to find them.
I wasn't willing to give up good diagnostics in the name of abstract purity, and I didn't care to replicate the message-formatting code in each module, so the necessary compromise was to treat Checks as a global library instead of a normal module object. This isn't too bad because Checks is completely stateless, and it's so simple and basic that you're unlikely to want to stub or mock it out.
This makes each method a closure, which has access to the local variables of the enclosing function invocation. Since "init()" has a local variable that points to each module that is used, it makes it easy to say things like "traits.set(blah blah blah)" without needing any extra qualifiers or look-ups.
JIFFEE and JIFFEEgames.com copyright © 2007-2010 by Michael S. Kenniston. All rights reserved. This page was last updated on 2010-01-17.