In Defiance of Titles

Just another WordPress.com weblog

Building a new blog

leave a comment »

Although I’ve loved using WordPress for the duration of this blog, recently I’ve been working on a custom replacement blog platform that I can host and maintain myself. This probably sounds odd, especially since there are already so many excellent blogging platforms available, but I’ve pushed ahead with it for a couple of reasons I think most developers will understand:

  1. Here at wordpress.com, I’d have to pay for certain features I can get for free with a self-hosted solution; I’d rather pay for hosting than pay for, say, custom templating.
  2. Although I could run WordPress or Drupal on a self-hosted domain, I still wouldn’t really be in control of the platform; a tailor-made solution will do exactly what I want it to, no more, no less.
  3. Most importantly: I blog primarily on my free time, mainly about projects I’m doing to hone skills I don’t typically get to use during my day job. I use Drupal all day at work, so using it for my blog wouldn’t really teach me anything.

The new platform is based on my favorite open source framework, Zend Framework, and makes heavy use of the Doctrine ORM library; I’ve been using Zend Framework for several years now, but Doctrine is new to me (and fantastic, by the way) …so I’m learning some very helpful new skills, and that makes me happy.

If you’d like to take a look at the new blog, it’s actually already live at jazzslider.org; I still haven’t worked out all the kinks, especially as far as IE compatibility is concerned, but I believe it’s a step in the right direction.

Check it out and let me know what you think!

Written by jazzslider

November 25, 2009 at 10:56 am

On Music and Tradition in the Modern Church

leave a comment »

Recently my blog has been predominantly tech-oriented, which is likely not much of a surprise to people who know me well; I really enjoy working with computers, and I like helping others do so more effectively. However, I never envisioned this blog as a one-subject pony, and as such, I’d like to take some time today to post about something else important to me.

See, I’m also a musician, and even more importantly, a Christian; accordingly, I’ve been thinking quite a bit lately about the role of music in the church. I’ve been to a lot of different types of churches and experienced a lot of different types of church music: choral hymns with organ accompaniment, choral hymns with orchestral accompaniment, contemporary praise and worship with a rock band, jazz services…it goes on and on, and part of the reason it goes on and on is because of my very first point:

Church music has almost as long and variegated a tradition as secular music.

Every generation attempts to redefine (in their own words, “improve upon”) the role of music in the church, and done properly, this is a good thing. Each generation gets its own time to shine, its own opportunity to express its faith in its own style, its own chance to punt what it believed was weighing the earlier generation down in its great upward quest. To put it more simply, believers of every generation think that their style of music communicates and engages with the love and glory of God more effectively than their fathers’ did.

Unfortunately, we humans have a tragic tendency towards sin in everything we do; more often than not, our attempts to kick aside the sins of our fathers simply leave us with a new set of problems, many of which we may not even recognize for years and years and years. This is my second main point:

The new is never wholly better than the old.

No matter what we do to try and improve upon previous ways of doing things, it is always ourselves, not our fathers, who tie the noose that hangs us (incidentally, this is also true if we change nothing at all).

Consider, for instance, the manner in which my generation is attempting to change church music. My generation’s experience of popular music happens, for the most part, through the iPod and the downtown club. We love the music of the indie rock band…gritty, emotional songs performed by soaring tenors to the accompaniment of driving guitars. Church folks, noticing the vast difference between this club scene and traditional organ-and-choir hymn-singing, decided some time ago that it would be easier to connect with the younger generation if they gave us this same kind of music in their services; this, in turn, was to lead to a greater incidence of genuine Christian life change (and often has). Thus was born the contemporary praise and worship genre.

So is this a good thing? I mentioned earlier that I don’t have a problem with each generation redefining how music is done in church; after all, in Luther’s day, the organ was a bar instrument! And, Biblically speaking, there is exactly zero justification for saying that a rock band would be inappropriate for Sunday services…the Bible says pretty much nothing about musical genres, especially in the New Testament. Given that the genre is Biblically acceptable and that the effect (connecting emotionally with the unchurched) is laudable, it would seem that this is, in fact, a good thing.

Most folks would end the argument there. In fact, if you’d talked to me four or five years ago I would have ended the argument there myself (probably). But as I pointed out earlier, the new is never wholly better than the old. Over the last year or two I’ve started to see that, by solving one problem (musical irrelevance), we may have inadvertently introduced another; this brings me to my third and primary point:

We have improved upon our ability to connect with the younger generation on its own level, but we have lost a great deal of community, participation, and humility as a result.

That’s a bold claim (and not just because of the typesetting…har, har), but you don’t have to take my word for it; as it turns out, the scriptures are pretty clear about this. No discussion of the role of anything in the church would be complete without a quick glance at 1 Corinthians, particularly the 12th chapter. Please read that chapter in full before continuing on*.

Done reading yet? Good. Now, let me risk a definition or two:

  • spiritual gift: an individual believer’s talent in and propensity toward a certain skillset, granted by God for use in lay or professional ministry. Although not everyone agrees on this point, I consider musical talent to be a spiritual gift, even though Paul never lists it explicitly; his lists do not appear to be exhaustive in any case, as they are never quite identical.
  • body: when Paul uses this term here (and in quite a few similar passages), he’s referring to the Body of Christ, a common metaphor for the church. I believe that the Body metaphor is applicable both universally (to all Christians in every place and time) and locally (to individual churches, and even smaller groups within those churches).
  • members: Paul talks about the body being made of many members (hands, feet, etc.); these members are symbols of individual believers qua their spiritual gifts…so, musicians qua musicians and preachers qua preachers, as opposed to musicians qua warm-bodies-that-could-do-anything.

The first part of the passage (vv. 15-18) is very frequently preached upon. Here are some of the takeaways:

  • We need to be involved in the church.
  • We need to be using the spiritual gifts God has given us.
  • We shouldn’t be jealous of other people’s gifts, even when they receive more honor for them than we receive for our own.
  • Neither should we refuse to participate in the church simply because we’ve been given a less impressive gift; if we do, we’re missing out on an important part of the Christian life, and robbing others of the benefit of our gifts.

The second part of the passage, on the other hand, is almost always ignored by preachers, possibly because it’s the part for which church leaders are most directly accountable. In verses 21-25, Paul states (oh, to heck with copyright):

And the eye cannot say to the hand, “I have no need of you”; or again the head to the feet, “I have no need of you.” On the contrary, it is much truer that the members of the body which seem to be weaker are necessary; and those members of the body which we deem less honorable, on these we bestow more abundant honor, and our less presentable members become much more presentable, whereas our more presentable members have no need of it. But God has so composed the body, giving more abundant honor to that member which lacked, so that there may be no division in the body, but that the members may have the same care for one another.

Here, Paul seems to be pointing out the same issue from a different perspective. Not only are we to avoid being jealous of others because they have different gifts from ours, but we must also avoid designing our ministries in a manner that implies that gifts God has granted are not actually necessary.

Considering this half of the passage, we really ought to add another couple of takeaway application points to our original list:

  • You should never let your church tell you that your gifts are unnecessary; that would be unbiblical, and despite the fact that church leaders have legitimate Biblical authority, they can still be wrong, and must still be held accountable to the Scriptures when they are. Questioning the church leadership isn’t the same thing as opposing God, and any church that thinks it is should terrify the junk out of you.
  • Churches must never let their ministry philosophies dictate which gifts (or how individuals with a particular gift) are necessary in their church. Doing so ignores the sovereignty of God in the composition of a church; if, for instance, you’ve got more teachers than you think you need, don’t assume that God made a mistake…reduce your class sizes or encourage team-teaching to make use of the extra talent that God has given you.
  • Churches must never exclude gifted believers from participation in ministry simply because they “already have enough [musicians, teachers, evangelists, etc.].”
  • The man-measured merit of a spiritual gift is not necessarily proportional to its necessity. Paul says that those members that “seem weaker” are in fact necessary, and should be given special honor, to preserve the unity of the body. Keep reading if this isn’t clear; it will be in a few paragraphs.

So how does this apply to the church rock band? Well, most secular rock bands (after which church rock bands are modeled) have very few members, at least compared to choirs, orchestras, or concert bands. Church rock bands often follow this same paradigm; each Sunday service is played by a single group of fewer than ten musicians.

This isn’t necessarily a problem if there are only ten musicians in your church, but what happens if you’ve got twenty? Do you put them in a rotation, such that each ten-person group plays every other week? What if there are thirty? Forty? Fifty? The larger the number gets, the harder it becomes to involve all the musicians God has brought to your church; if you’ve got several hundred skilled musicians (which in large churches is not that uncommon), you end up either cycling them all through once every six months or so, or simply saying to some of them, “sorry, we have no need of you.”

There’s another problem. If you’re OK with excluding some of them (which is already biblically problematic), how do you determine who gets the gig? Suppose you have twenty musicians in your church; ten of them are famous, gigging professionals, and the other ten are amateurs who clearly have a musical gift (they can carry a tune or pick out a beautiful harmony), but aren’t quite as good as the pros. Since you’ve only got ten spots in the Sunday service, do you tell the amateurs (the ones that “seem to be weaker”) that you “have no need of” them? If so, where will they use the gifts God has given them? (You could take the reverse approach by putting the amateurs to work in Sunday services and telling the pros that they’ve already got plenty of opportunities to use their gifts outside the church, but that’s not exactly right either. Or, you could tell the amateurs that they can serve in less public arenas, like small groups or children’s church…but this doesn’t really uphold the “more abundant honor” principle Paul is espousing.)

There’s a third problem. Suppose you have exactly ten gifted musicians in your church, but three of them are only classically trained, and have no penchant for indie rock. Or what if their primary expertise is in orchestral or band instruments? Where do they fit in? Ultimately, if you’re fully committed to the relevant rock band, you have to say to those folks, “sorry, we have no need of you.”

All of these examples clearly show the danger of my generation’s insistence on limited-participation contemporary worship services; it seems that no matter what we do, implementing this kind of service results in a violation of the guidelines Paul presents in 1 Corinthians 12. Our goals may be laudable, but we need to find another way of accomplishing them, a way that doesn’t run contrary to the scriptures. Please note once more that I am not criticizing the genre here; if one of you can come up with a way to maintain cultural relevance (for everyone) without sacrificing participation (for all gifted believers), I am all ears.

Before you do that, however, I’ll leave you with one further problem, which is less Biblical and more paranoid dystopian (for what it’s worth). I’ve said several times in this post that “the new is never wholly better than the old;” really, though, what I’m suggesting is that there is an importance to tradition, not just insofar as we can learn from history, but insofar as we are a part of it.

I remember one occasion, shortly after I committed my life to Christ, when I sat down with my pastor back home in North Dakota to talk through some of the new things I’d experienced since that leap of faith. I told him that I really appreciated the authenticity of contemporary praise and worship services…that I felt like singing with your eyes out of the hymnal and your hands lifted high was a more honest form of worship, a more sincere way of connecting emotionally and spiritually with the Lord. Looking back on that conversation, I really appreciate that he didn’t punch me in the face, since that was a pretty stinking rude thing to imply. But instead, he said something along the following lines:

We sing hymns because they are a part of our tradition; they connect us with generations of Christians gone by, reminding us that we are a part of a long and storied faith, whose truths are timeless.

Tommy Nelson, lead pastor of Denton Bible Church, said pretty much the same thing a few months ago; this time, however, I think I finally understood it. The thing about tradition is that it grounds you deeply in a real world, whose strengths and weaknesses you know as intimately as you know yourself. The other thing about tradition is that it reminds you that what you’re doing, what you’re believing, is as authentic as it gets. Finally, the third thing about tradition is that it keeps you safe in the context of established, tested cultural norms. Throw those out, and the only thing left is the loudest voice, the biggest fist, the squeakiest wheel. And with all its faults, I choose tradition over that any day.


* I haven’t reproduced it here because I’m not totally sure of the copyright ramifications…strangely enough, most translations of the Bible are very strictly protected under copyright law, despite the age of the original work…but translators need their wages too, so I don’t suppose I can object too much.

Written by jazzslider

October 5, 2009 at 6:01 pm

My Home NAS, Part 10: Mac OS X Automounting

leave a comment »

So, uh, some time ago when I wrote the last post in my home NAS tutorial (for reference, here’s all previous posts in the series), I made a rather bold omission:

Once you’ve got the tunnel running (ideally you’d set it up to run automatically), all that’s left is to mount the NFS share(s) to appropriate locations in your filesystem. This process varies by operating system (even across UNIXes), so for now I’ll leave that up to you.

Unfortunately, yesterday I found myself deeply regretting the decision not to document this step; somehow, when I upgraded my Mac to Snow Leopard, my NFS share configurations were wiped out, leaving me with nothing but scp to get files off of the NAS. So, to avoid future headaches, I’ve decided to finish my documentation.

First, a word of warning for you Linux folks out there: Mac OS X handles NFS mounting differently than a lot of other UNIXes do; you’ll be tempted to start out in /etc/fstab, but don’t do it…it’s deprecated. OS X offers a more flexible solution allowing you to automatically mount various volumes from various kinds of directory services…but that’s kind of beyond what we’re looking for, so we’re just going to make a few simple changes to the automount configs instead.

The end goal here is to take the NFS shares we previously exported (critical, standard, pictures, and music) and mount them all in one directory under /Volumes. To do this, we’ll first want to create an automount map file called “/etc/auto_your-server-name”. The contents should look something like this, assuming you used the LOST-inspired port forwarding from my previous post:

critical -tcp,port=48151,mountport=62342,resvport,locallocks localhost:/export/critical
standard -tcp,port=48151,mountport=62342,resvport,locallocks localhost:/export/standard
pictures -tcp,port=48151,mountport=62342,resvport,locallocks localhost:/export/pictures
music    -tcp,port=48151,mountport=62342,resvport,locallocks localhost:/export/music

So far so good. Next, we’ll need to tell the automounter to use this new file to populate a particular directory under /Volumes; to do so, add the following line to /etc/auto_master:

/Volumes/your-server-name auto_your-server-name

Finally, tell the automounter to re-read the configs by executing the following command:

sudo automount -vc

If all goes well, you should see your four new mount points show up as shared directories under /Volumes/your-server-name; assuming, of course, that you’ve got your SSH tunnel running as per the previous tutorial. Hope this helps someone!

Written by jazzslider

September 10, 2009 at 6:38 pm

A Reusable Zend Framework Content Module

with 2 comments

As a sort of proof of concept for the ideas I discussed in my previous post, I’ve put together the first draft of what could become a very helpful reusable module. With this post, I’d like to introduce my new Zend Framework “content” module, which provides several abstract components for a reusable model layer, along with a concrete framework for building a variety of content types sharing a common database-based persistence layer. With some (OK, a lot of) refinements, a module like this could easily form the foundation of an extremely extensible Zend Framework-based content management system.

You can check out the current trunk by issuing the following svn command in your project’s modules directory:

svn checkout http://jazzslider.org/svn/zf-content/trunk content

Here’s a more detailed look at the features:

  • First off, it provides a reusable abstract model-and-mapper[1] system with sensible defaults for persisting those models in a MySQL database (other kinds of persistence layers are easily supported). Both pieces incorporate a plugin architecture similar to that used in Zend_Controller_Action, so that new functionality can be added to all models compositionally.
  • It also provides a concrete implementation of all this called Content_Model_Post; this model is essentially just your basic revision-controlled title-and-body content type. The nice thing about the post model is that it’s designed to be extended; if you need additional fields, you simply need to write a child class and a mapper plugin that describes how to find the extra data. (The design concept owes a lot to the Drupal CCK module, but without any of the administrative bells and whistles; this module is still very much a programmer’s toolkit.)
  • The view layer for the posts system comes with a few handy helpers and filters; the filters are mainly for implementing things like HTMLPurifier, Markdown, GeSHi syntax highlighting, etc. in the view layer when rendering your content. The idea is described in more detail in one of my previous posts, but the solution I’ve implemented here is much better. One caveat: the filters won’t work unless you’ve got the associated libraries installed somewhere in your include_path (as described in the INSTALL.txt file in the root of the project).

I’m releasing the current version of the source code under the GPL for now so that anyone who wants to can see how it works; that said, I wouldn’t say it’s ready for use in a high-profile production environment, owing to a couple of factors:

  • While the system does keep track of content authorship right out of the box, it would do a much better job of it if it knew how its parent application kept track of the current user. The only expectation it enforces is that when you assign an author to a post, it either has to be a Zend_Acl_Role_Interface object implementation or a string role ID that can be resolved to such an object at runtime (you can control this part of the process through a model plugin). Once I’ve written my reusable “users” module, things may work more predictably.
  • While we’re on the subject of related modules…one of my next projects is to develop a “comments” module that provides comments to all posts (and all dependent content types). For that matter, I’d also like to piece together something that allows for tag-based content classification. These will all be separate, optional modules, in keeping with the idea that people should be able to drop in what they want and leave the rest aside.
  • The process of designing a new dependent content type is still a little over-complicated; I’m going to try writing a tutorial soon, and when I do, I’d love some feedback on how to simplify the process.
  • The code is not yet unit tested; I wasn’t quite sure of the best way to bootstrap my unit tests now that Zend_Application is involved, and so far I haven’t found any definitive guides on the matter. I’ll be looking into that soon, and if what I discover is useful I’ll certainly make a post about it.

At any rate, please take a look and tell me what you think; remember, this mainly serves as a proof of concept for some of the stuff I’ve been talking about in previous posts…and once I’ve got the other helper modules put together, I think it’ll be a lot clearer what I’m aiming at. Anyway, thanks for reading!

Footnotes

  1. [Back] The data mapper logic in this module accomplishes some of the same purposes as the proposed Zend_Db_Mapper component, but is in no way intended (or suitable) to replace it. My goal here was mainly to demonstrate how such logic could be built out as a distributable, reusable plug-and-play module now that Zend_Application_Resource_Modules is out of the gate. I’m looking forward to future developments on Zend_Db_Mapper, and if it finds its way into the official framework you can bet I’ll be using it for projects like this.

Written by jazzslider

June 15, 2009 at 6:38 am

Distributing Zend Framework Modules

with 8 comments

It’s been almost a month now since the release of Zend Framework 1.8, and although I was very excited about some of the new features, it’s taken me awhile to digest that excitement into something bloggable. As a result, I apologize if I’m a bit late to the party…but I’d like to take a moment nonetheless to discuss the implications of my favorite 1.8 feature: Zend_Application_Resource_Modules.

Zend Framework has provided what it calls a “conventional modular directory structure” for quite some time now: specifically, Zend Framework modules are supposed to “[allow] you to separate different MVC applications into self-contained units, and re-use them with different front controllers”. Unfortunately, up until 1.8, I have never found this to be entirely accurate. Based on module architectures I’d seen in full-stack content management systems, I’d always kind of hoped that installing a module would be as easy as this:

  1. Download the source code and copy it into your application’s modules directory.
  2. Hooray, it works now!

Now, this was true enough for modules that only provided a couple controllers and view scripts, but the second you introduced, say, controller plugins or models in the include_path, you’d have to modify your application-level bootstrap file, providing it with detailed knowledge of what the module provides. Because of this, the framework hasn’t really inspired a lot of distributable, reusable third-party modules; after all, the process for installing them would actually have looked something like this:

  1. Download the source code and copy it into your application’s modules directory.
  2. Adjust your application entry point (index.php) to include the module’s models folder in the include_path.
  3. Adjust your application-level bootstrap file to register the new modules directory with the front controller, if you haven’t configured it that way already.
  4. Adjust your application-level bootstrap file to register any plugins or plugin paths it might provide.
  5. Install any database schemas that might have come with the module.
  6. Hooray, it works now!

The problem here is that the parent application (and the person installing it) has to know all sorts of nitty-gritty details about how the module does its business. In my opinion, a truly “self-contained” module would be able to handle a lot of the above process all by itself, without any modifications to the parent application; otherwise, it’s not really self-contained, and not particularly easy to distribute to other developers.

Enter 1.8

However, as I mentioned earlier, this situation has changed dramatically in Zend Framework 1.8, due to a wonderful little component called Zend_Application_Resource_Modules. Among other things, it provides the following:

  • Modules can now provide their own bootstrapping logic; no more need to register module-provided plugins, paths, etc. in the application-wide bootstrap file.
  • Autoloading of common types of module-provided classes is now automatically set up for you; no more need to add modules to your include_path, or even to require_once your module class files before you use them.

See the benefit? All of the application-level configuration we used to have to do can now be encapsulated in a bootstrap process provided as a part of the module itself. This cuts the above workflow down to something like this:

  1. Download the source code and copy it into your application’s modules directory.
  2. Install any database schemas that might have come with the module.
  3. Hooray, it works now!

Suddenly, the prospect of downloading somebody else’s reusable module is a lot more appealing.

Some further issues

You’ll notice, however, that this still doesn’t quite match my first ideal workflow. Although Zend_Application_Resource_Modules provides a lot of assistance in getting your modules bootstrapped once they’re installed, it cannot yet provide much assistance with the installation process itself. As a result, if you’re trying to install a distributed module that involves database schemas, you’ll still have to install those by hand.

It’s also worth noting that Zend_Application_Resource_Modules does not yet provide a way to track and enforce module dependencies. For the most part this isn’t necessary; by the time everything is bootstrapped, all module-provided code is available through autoloading. However, there are a couple of situations in which it would be necessary:

  • If Module A needs to use a class provided by Module B during Module A’s own bootstrap, Module B must have been bootstrapped first…otherwise the autoloader for Module B’s classes won’t be ready yet.
  • If Module A provides a plugin that, for whatever reason, assumes that a plugin from Module B always fires before it, then Module B’s plugins need to be registered before Module A’s.

I’m working (in my copious spare time) on a distributable module of my own right now that could really benefit from both dependency tracking and database installation…but with how much better module architecture has already gotten in 1.8, I can only assume that future releases will be even more elegant. In the meantime, keep an eye out for my new module; I’d love the benefit of community review once it’s ready.

Written by jazzslider

May 21, 2009 at 7:43 pm

Design Choices for Zend_Auth_Adapter_Flexible

leave a comment »

Well, I’ve finally gone ahead and posted a Zend Framework component proposal: Zend_Auth_Adapter_Flexible. It’s the same idea I wrote up in my last post, but with a few key modifications; I thought I’d take a minute or two to discuss those modifications here.

First, the new proposal does not involve a user model; it pulls authentication credentials directly out of the strategy class’s Zend_Form instance. This change is mainly due to the framework’s lack of a formalized model layer…plus, it reduces the complexity of the idea, which is always a good thing.

Second (on a related note), the new component does not make any attempt to standardize what type of identity gets stored by Zend_Auth. Since authentication strategies will be written on an ad-hoc application-by-application basis, I figure that developers will want to take their own approach to this.

Third, the new proposal will hopefully take advantage of Zend_Navigation to automatically generate a list of links to available authentication strategies. I’m really not sure of how that would happen yet, since the plugin loader class doesn’t have any methods for retrieving all available class names—but if the community thinks it’s a good idea, there will likely be suggestions on how to take care of it.

I did keep the basic class name structure intact, which may or may not be a good thing. Zend_Auth_Strategy_Interface would require a new namespace under Zend_Auth, and I don’t know that I have a good justification for that. I do know that authentication strategies need to be distinguished from regular authentication adapters, since they do more things and have more dependencies.

So there you have it—my very first Zend Framework proposal. If you’re a Zend Framework developer and what I’ve described sounds interesting to you, please go take a look (and leave comments)!

Written by jazzslider

May 7, 2009 at 6:44 pm

Flexible User Authentication with Zend_Auth

with 3 comments

The Zend_Auth component of the Zend Framework can really help simplify the process of developing a custom authentication system for your next web application. The basic process is already very well-documented, so let’s try something a bit more complex.

For this example, we’re going to allow our users to authenticate in one of multiple ways: e.g., against a database table, against an LDAP server, or by OpenID [1]. Zend_Auth already provides the necessary authentication adapters, so what we’ll be concerned with here is how to implement all three systems without ending up in an FSUC situation.

As I see it, the controller layer ought to have very little awareness of the underlying authentication mechanisms. Here’s what such a controller might look like:

class AuthController extends Zend_Controller
{
  public function loginAction()
  {
    // one composite authentication adapter encapsulates
    // all the possible auth strategies, and provides appropriate
    // form instances for each
    $adapter = new My_Auth_Adapter_Multipath();
    $adapter->setStrategy($this->_getParam('via', null));
    $form = $adapter->getForm();
    $this->view->form = $form;

    // we'll also need an empty user object for this
    $user = new My_User(array());
    $adapter->setUser($user);

    // and then, if the user has submitted the form and it
    // passes simple validation, go ahead and try to authenticate
    if ($adapter->shouldAuthenticate($this->getRequest(),
                                     $this->getResponse())
     && $form->isValid($this->_getAllParams())) {
      $user->populate($form->getValues());

      $auth = Zend_Auth::getInstance();
      $this->view->authResult = $auth->authenticate($adapter);
      $this->render('result');
    }
  }
}

Looks pretty clean to me. The view script is even cleaner:

<h1><?= $this->translate('Log in') ?></h1>
<?= $this->form ?>
<h2><?= $this->translate('Other ways to log in') ?></h2>
<ul>
  <li><a href="<?= $this->url(array('via' => 'email')) ?>"><?= $this->translate('Email') ?></a></li>
  <li><a href="<?= $this->url(array('via' => 'euid')) ?>"><?= $this->translate('EUID') ?></a></li>
  <li><a href="<?= $this->url(array('via' => 'openid')) ?>"><?= $this->translate('OpenID') ?></a></li>
</ul>

The real magic is all happening behind the scenes in the model layer. Let’s take a look at the authentication adapter next:

class My_Auth_Adapter_Multipath implements Zend_Auth_Adapter_Interface
{
  protected $_strategies;

  protected $_user;
  protected $_strategy;
  protected $_request;
  protected $_response;

  public function __construct()
  {
    $this->_strategies = new Zend_Loader_PluginLoader(array(
      'My_Auth_Strategy' => 'My/Auth/Strategy/',
    ));
  }

  public function shouldAuthenticate(Zend_Controller_Request_Http $request,
                                     Zend_Controller_Response_Http $response)
  {
    if (null === $this->_strategy) {
      throw new Zend_Auth_Adapter_Exception('cannot determine; must set strategy first');
    }
    $this->setRequest($request);
    $this->setResponse($response);
    return $this->_strategy->shouldAuthenticate();
  }

  public function authenticate()
  {
    if (null === $this->_user || null === $this->_strategy) {
      throw new Zend_Auth_Adapter_Exception('must provide both user and strategy');
    }
    return $this->_strategy->authenticate();
  }

  public function getForm()
  {
    if (null === $this->_strategy) {
      throw new Zend_Auth_Adapter_Exception('must provide strategy first');
    }
    return $this->_strategy->getForm();
  }

  public function getUser()
  {
    return $this->_user;
  }

  public function setUser(My_User $user)
  {
    $this->_user = $user;
    return $this;
  }

  public function getStrategy()
  {
    return $this->_strategy;
  }

  public function setStrategy($strategy)
  {
    if (!($strategy instanceof My_Auth_Strategy_Interface)) {
      $strategyClass = $this->_strategies->load(ucfirst($strategy));
      $strategy = new $strategyClass();
      $strategy->setAdapter($this);
    }
    $this->_strategy = $strategy;
    return $this;
  }

  public function getRequest()
  {
    return $this->_request;
  }

  public function setRequest(Zend_Controller_Request_Http $request)
  {
    $this->_request = $request;
    return $this;
  }

  public function getResponse()
  {
    return $this->_response;
  }

  public function setResponse(Zend_Controller_Response_Http $response)
  {
    $this->_response = $response;
    return $this;
  }
}

A few things worth noting here. First…usually in this type of workflow the controller would check $this->getRequest()->isPost() prior to firing the authentication method; however, certain authentication strategies may require authentication to fire on other conditions (for instance, the OpenID adapter should fire when the openid_mode parameter is set, regardless of the request method). So, we leave it up to the adapter’s shouldAuthenticate() method to determine if the request warrants authentication.

Second, note that we still don’t have much in the manner of authentication code; that’s because, in order to keep things as flexible as possible, we’ve offloaded the actual authentication work to an arbitrary collection of strategy classes [2], provided dynamically through a Zend_Loader_PluginLoader instance (to make this worth it, we’ll also eventually want to add methods for registering new plugin paths, but I’ve left that out for the sake of brevity). Each strategy class will need to conform to the following interface:

interface My_Auth_Strategy_Interface extends Zend_Auth_Adapter_Interface
{
  public function setAdapter(My_Auth_Adapter_Multipath $adapter);
  public function getForm();
  public function shouldAuthenticate();
}

Internally, each authentication strategy will simply configure one of the core Zend_Auth adapters, run its authentication method, and, if successful, ensure that the identity returned in the Zend_Auth_Result instance is the completely-loaded user object. Let’s take a look at the simplest of the three examples, which checks the user’s email address and password against a backend database table:

class My_Auth_Strategy_Email implements My_Auth_Strategy_Interface
{
  protected $_adapter;

  public function setAdapter(My_Auth_Adapter_Multipath $adapter)
  {
    $this->_adapter = $adapter;
    return $this;
  }

  public function getForm()
  {
    $form = new Zend_Form();
    $form->addElement('text', 'email');
    $form->email->setLabel('Email address')
                ->setRequired(true)
                ->setFilters(array('StringTrim'))
                ->setValidators(array(
                  array('EmailAddress'),
                ));
    $form->addElement('password', 'pword');
    $form->pword->setLabel('Password')
                ->setRequired(true);
    $form->addElement('submit', 'submitBtn');
    $form->submitBtn->setLabel('Submit');
    return $form;
  }

  public function shouldAuthenticate()
  {
    return $this->_adapter->getRequest()->isPost();
  }

  public function authenticate()
  {
    $user = $this->_adapter->getUser();
    if (null === $user->email || null === $user->pword) {
      throw new Zend_Auth_Adapter_Exception('must provide email and password');
    }

    // use an internal Zend_Auth_Adapter_DbTable instance
    // to do the actual authentication
    $internalAdapter = new Zend_Auth_Adapter_DbTable(
      Zend_Registry::get('dbAdapter'),
      'users',
      'email',
      'pword'
    );
    $internalAdapter->setIdentity($user->email)
                    ->setCredential($user->pword);

    $result = $internalAdapter->authenticate();
    // per the stated requirements, we also want to make
    // sure that Zend_Auth stores a fully-completed user
    // object as the user's identity; so, we'll populate the
    // user object from the retrieved row and then set up
    // a new result object containing the correct identity
    if ($result->isValid()) {
      $user->populate($internalAdapter->getResultRowObject());
    }
    $result = new Zend_Auth_Result($result->getCode(), $user, $result->getMessages());
    return $result;
  }
}

We’ll use the same principle in designing the remaining two authentication methods (LDAP, which our users will know as their “EUID” or “Enterprise User ID”, and OpenID). I’ve left getForm() and setAdapter() out of these next examples, because the basic technique won’t be much different.

class My_Auth_Strategy_Euid implements My_Auth_Strategy_Interface
{
  // ...

  public function shouldAuthenticate()
  {
    return $this->_adapter->getRequest()->isPost();
  }

  public function authenticate()
  {
    $user = $this->_adapter->getUser();
    if (null === $user->euid || null === $user->euidPword) {
      throw new Zend_Auth_Adapter_Exception('must provide EUID and EUID password');
    }

    $ldapOptions = $this->_getLdapOptions();
    $internalAdapter = new Zend_Auth_Adapter_Ldap($ldapOptions,
                                                  $user->euid,
                                                  $user->euidPword);
    $result = $internalAdapter->authenticate();
    if ($result->isValid()) {
      // again, we'll need to populate the user object from the
      // database here, only this time we'll need to actually load
      // the user in manually since LDAP is a different system
      $table = new My_Db_Table_Users();
      $select = $table->select()->where('euid = ?', $user->euid);
      $userRow = $table->fetchRow($select);
      if (null === $userRow) {
        // the user has a valid LDAP account, but doesn't have an
        // account on our site yet, so we'll need to create one
        // programmatically...I won't demonstrate this here, though
      }
      $user->populate($userRow);
    }
    $result = new Zend_Auth_Result($result->getCode(), $user, $result->getMessages());
    return $result;
  }

  // ...
}

And finally, a strategy class for OpenID. Note that this is a bit more difficult owing to the necessity of client redirects; the OpenID strategy needs to be aware of quite a few more details, most of which are stored in the request object injected from the controller during the shouldAuthenticate() method.

class My_Auth_Strategy_Openid implements My_Auth_Strategy_Interface
{
  // ...

  public function shouldAuthenticate()
  {
    $request = $this->_adapter->getRequest();
    if ($request->isPost()
     && $request->getParam('openid_action', null) == 'login'
     && null !== $request->getParam('openid_identifier', null)) {
      return true;
    }
    if (null !== $request->getParam('openid_mode', null)) {
      return true;
    }
    return false;
  }

  public function authenticate()
  {
    $user = $this->_adapter->getUser();
    if (null === $user->openid_identifier) {
      throw new Zend_Auth_Adapter_Exception('must provide openid');
    }

    $storageDir = APPLICATION_PATH . '/../temp/openid_storage';
    $storage = new Zend_OpenId_Consumer_Storage_File($storageDir);

    $internalAdapter = new Zend_Auth_Adapter_OpenId(
      $user->openid_identifier,
      $storage,
      null,
      null,
      null,
      $this->_adapter->getResponse()
    );

    $result = $internalAdapter->authenticate();
    if ($result->isValid()) {
      // again, load the user from the database and populate
      // the user object; note that if the user doesn't yet have
      // an account on our site, the above code would be very
      // easy to modify such that it uses the OpenID simple
      // registration extension to create the user automatically
    }
    $result = new Zend_Auth_Result($result->getCode(), $user, $result->getMessages());
    return $result;
  }
}

The end result of all this is an extremely flexible (and extremely extensible) user authentication system with very little business logic in the controller.

Footnotes

  1. [Back] The idea is similar, but not identical, to the Zend_Auth_Adapter_Chain proposal from January 2008; the main difference here is that instead of authenticating against a series of several adapters, we’re simply going to have one main adapter that orchestrates the whole procedure via easily-selected strategies. Only one authentication technique will ultimately fire.
  2. [Back] If you look at the code later on, you’ll see that my authentication “strategy” interface is just an extension of Zend_Auth_Adapter_Interface allowing each implementation to provide a few extra standard features (forms, request analysis, etc.). I suppose it would have been reasonable to simply call them adapters, but I decided on using a new (still fairly standard) name to make it clear that they’re doing more than the standard Zend_Auth adapter would do. It was also necessary to namespace these classes separately from any other Zend_Auth adapters that might be included in a given application, so that the plugin loader never accidentally loads a different implementation of Zend_Auth_Adapter_Interface.

Written by jazzslider

April 9, 2009 at 6:52 am

Output Transformation in a Zend Framework Model Layer

with 4 comments

A few weeks back, Matthew Weier-O’Phinney wrote a very helpful discussion of model layer infrastructure using various components of the Zend Framework. I especially appreciated his advice on using Zend_Form as an input filter inside the model class itself; it provides a very clean way to keep validation and filtering logic properly encapsulated.

Zend_Form’s use of Zend_Filter and Zend_Validate also makes it very easy to get precisely the filtering and validation rules you need. You can even filter through an external library like HTMLPurifier if you find you need the extra functionality, just by writing a new filter class; this has already been covered quite well (for example, see Part 8, Step 3 of Pádraic Brady’s Zend Framework blog tutorial). As Weier-O’Phinney demonstrates, you can then use this Zend_Form object as a screening filter in your model class, so that certain properties must always pass through the form’s validation process before they are set in the model itself. I won’t duplicate his logic here either, but you should definitely take a look at it.

However, I’ve run into a minor problem, and I’m not sure my solution is particularly ideal. See, the Zend_Form approach described above does a great job of implementing Chris Shiflett’s Filter Input, Escape Output principle…user input is filtered for invalid HTML before it’s ever saved to the model, and can then be escaped as appropriate in the view layer. But what happens if you need to be able to retrieve the user’s original unfiltered input later?

That might not sound like an appropriate thing to do, but consider this. Suppose that instead of simply sanitizing user-contributed HTML, you wanted to allow your users to use a simpler text input format (such as Markdown) and generate the HTML for them later? It wouldn’t be appropriate to save the generated HTML to the model, since your users would then be unable to retrieve their original Markdown version for later editing. However, if you don’t pre-generate the HTML, then you can’t perform your HTMLPurifier sanitizing at the input stage either, since there isn’t any HTML to sanitize yet.

In this situation, it looks to me like you’d be stuck doing all your input filtering in the presentation (output) layer, which doesn’t really dovetail well with Shiflett’s principle. But then again, there do appear to be two distinct types of “filtering” at work here, one of which is what Shiflett was talking about, and the other of which probably isn’t:

  1. Sanitization, or making sure that user input doesn’t contain any security risks.
  2. Transformation, or converting user input for presentational purposes. (I feel like this is different from escaping, since escaping is mainly concerned with defusing special characters?)

So what do you think? It’s clear that sanitization ought to be done immediately upon input (preferably in the form object), but where should transformation happen?

Rob Allen’s Zend Framework Overview from last year hints at implementing things like Markdown formatting in the view layer through the use of view helpers. This is certainly appropriate from a strict MVC perspective, as output transformation is definitely presentation-layer stuff. However, this isn’t particularly DRY; every time you wrote a view script utilizing this data, you’d need to remember to run it through the appropriate chain of output filters.

So, my best overall idea (building on Weier-O’Phinney’s examples) is to implement it in the getters in my model:

class My_Model
{
  // ...
  public function __get($property)
  {
    $method = 'get' . ucwords($property);
    if (method_exists($this, $method)) {
      return $this->$method();
    }
    if (array_key_exists($property, $this->_data)) {
      return $this->_data[$property];
    }
    return null;
  }

  public function getBody($applyOutputFilter = true)
  {
    $body = $this->_data['body'];
    if ($applyOutputFilter) {
      $body = $this->getOutputFilter()->filter($body);
    }
    return $body;
  }

  public function getOutputFilter()
  {
    $filterChain = new Zend_Filter();
    // add specific filter objects as appropriate, and then...
    return $filterChain;
  }
  // ...
}

This guarantees that whenever the “body” is accessed as a property, it’s correctly transformed for HTML output (a sensible default).

However, both of these approaches still leave us with the same core problem: you almost inevitably end up doing all your input filtering at the presentation stage, rather than prior to saving it to the persistence layer as is usually recommended. This can be a security risk if you’re not careful, and is almost certainly a performance hit for the average visiting user.

Any ideas on how best to resolve these issues?

Written by jazzslider

April 6, 2009 at 7:11 am

Spades in PHP: Play-by-Play versus Play-at-Once

leave a comment »

Earlier this week I posted about my PHP spades project for automated testing of bidding and playing strategies. In that post I highlighted my use of the strategy design pattern to make it easy to test a variety of approaches to the game; however, I didn’t provide much structural detail. Lucky you, as it turns out, because the structure I was using at the time was far from ideal.

My overall idea for running the tests was to be able to use a very thin controller script, something along these lines:

$game = new Spades_Game();
for ($i=0;$i<3;$i++) {
  $game->registerPlayer(new Spades_Player(new Spades_Strategy_Something()));
}
$scores = $game->play();

This simple “play-at-once” approach is very easy to call, as it leaves every last bit of the game’s business logic to the model layer. Unfortunately, it doesn’t leave a lot of room for flexibility, particularly in two areas:

  1. Since the entire game happens in a single function call, it’s impossible for the controller layer to keep track of the game’s progress for output and/or logging purposes.
  2. It’s also impossible for the controller layer to allow user input and thereby facilitate the introduction of human players.

So, today I spent a good chunk of time re-architecting the game structure. In terms of tracking progress, I started to think in terms of atomicity: what’s the smallest sequential part of a game of spades? Well, let’s break it down. A game in its entirety consists of as many hands as necessary to get one team to 400 points without a tie. Each hand consists of each player bidding once, followed by as many tricks as necessary to lay down the entire deck. Each trick consists of every player laying down a single card in sequence. Tricks are won by the team who played the highest card (spades being higher than other suits), and hands are scored based on the number of tricks each player bid on winning.

The most atomic parts of all that are individual players’ bids and plays. So, if the controller layer was to be able to track the progress of the game, it would need to be able to check in after each of those events to see what happened. This led to the following “play-by-play” structure:

$game = new Spades_Game();
for ($i=0;$i<3;$i++) {
  $game->registerPlayer(new Spades_Player(new Spades_Strategy_Something()));
}
while ($nextPlayer = $game->getNextPlayer()) {
  if ($game->getCurrentPhase() == Spades_Hand::PHASE_BIDDING) {
    $game->acceptBid($nextPlayer->placeBid(), $nextPlayer);
  } else if ($game->getCurrentPhase() == Spades_Hand::PHASE_PLAYING) {
    $game->acceptPlay($nextPlayer->playCard(), $nextPlayer);
  }
}
$scores = $game->getScores();

The nice thing about this is that, although there’s quite a bit going on behind the scenes, the controller layer really only needs to be aware of the Spades_Game, Spades_Player, and Spades_Strategy_X classes. As long as the game object returns a player, the controller layer knows that there’s more game to be played.

So what’s going on internally? Well, Spades_Game is basically a facade managing a sequence of Spades_Hand objects, which in turn manage a sequence of Spades_Trick objects. Take a look:

class Spades_Game
{
  // ...
  public function getNextPlayer()
  {
    $hand = $this->getCurrentHand();
    if (null === $hand) {
      return null;
    }

    $player = $hand->getNextPlayer();
    if (null === $player) {
      // this hand is over...score it, register it, and
      // check to see if the game has been won
      $this->_score();
      $this->_handsPlayed[] = $hand;
      if ($this->_isWon()) {
        return null;
      }

      // hasn't been won yet, so we need to start up
      // a fresh hand...
      $this->_incrementDealer();
      $this->_currentHand = new Spades_Hand($this);
      $player = $this->_currentHand->getNextPlayer();
    }
    return $player;
  }
  // ...
}

Notice that, at this point, there isn’t any logic regarding the phase we’re in (bidding or playing); since the two phases each occur once per hand, it makes more sense to manage them within the Spades_Hand class. Each phase is handled by separate logic, so Spades_Hand::getNextPlayer() makes use of a couple of protected methods to keep things distinct:

class Spades_Hand
{
  // ...
  public function getNextPlayer()
  {
    switch ($this->getCurrentPhase()) {
      case Spades_Hand::PHASE_BIDDING :
        $player = $this->_getNextBidder();
        break;
      case Spades_Hand::PHASE_PLAYING :
      default :
        $player = $this->_getNextPlayer();
        break;
    }
    return $player;
  }

  protected function _getNextBidder()
  {
    if (count($this->getPlayerBids()) <= 0) {
      // nobody has bid yet, so this is the beginning of the hand;
      // deal, and then the player after the dealer is the first bidder
      $this->_cardsDealt = $this->getDeck()->deal($this->getPlayers(), $this->getDealer());
      $this->_currentTrick = new Spades_Trick($this->getGame());
      $position = $this->getDealer() + 1;
    } else {
      $lastbid = end($this->_bids);
      $lastpos = key($this->_bids);
      $position = $lastpos + 1;
    }
    if ($position > count($this->getPlayers()) - 1) {
      $position = 0;
    }
    $players = $this->getPlayers();
    $player = $players[$position];
    return $player;
  }

  protected function _getNextPlayer()
  {
    $trick = $this->getCurrentTrick();
    if (null === $trick) {
      return null;
    }
    $player = $trick->getNextPlayer();
    if (null === $player) {
      // the trick is over...score it, register it, and
      // check to see if the hand is complete
      $this->_score();
      $this->_tricksPlayed[] = $trick;
      if ($this->_isFinished()) {
        return null;
      }

      // not done yet, start a fresh trick
      $this->_currentTrick = new Spades_Trick($this->getGame());
      $player = $this->_currentTrick->getNextPlayer();
    }
    return $player;
  }
  // ...
}

Notice that the _getNextPlayer() half of the procedure is extremely similar to Spades_Game::getNextPlayer(); we’re still passing the buck along the chain to a smaller unit of play…the Spades_Trick instance.

class Spades_Trick
{
  // ...
  public function getNextPlayer()
  {
    if (count($this->_plays) == count($this->getPlayers())) {
      // everybody's played, so we're done...determine the winner
      // and get on out of here.
      $this->_determineWinner();
      return null;
    }
    if (null === $this->_currentPlayer) {
      // first play...determine the lead player
      $this->_currentPlayer = $this->getLeadPlayer();
    } else {
      // cycle through to next player
      $this->_currentPlayer = $this->getPlayerAfter($this->_currentPlayer);
    }
    return $this->_currentPlayer;
  }
  // ...
}

All these layers taken together make it possible for the controller layer to always have access to the next player in sequence, without having to know much of anything about that sequence.

One nice side bonus of this structure is that it would be dead simple for the controller layer to identify certain players as user-controlled, injecting their input into the system in the $game->acceptBid() and $game->acceptPlay() methods.

The next step in all of this, I suppose, will be to develop a simple web interface for viewing the results, and possibly trying to beat all these wonderful computer players.

Written by jazzslider

March 14, 2009 at 8:43 pm

Spades and the Strategy Pattern

with 5 comments

So lately my wife and I have been playing quite a bit of spades with some good friends of ours; if you’ve never played, it’s quite fun, but you don’t want to be on my team :)

The thing is, it strikes me as the kind of game a well-informed computer would be great at; that is, if one could remember everything that’s been played in a given hand and, from that, calculate the probability of any of one’s cards being beaten in a given trick, one could win the game far more easily.  But I have my doubts about this, so as any good developer would, I decided to test it programmatically.

Here’s the project (and I deliberately didn’t check to see if anyone’s done this before): write a command-line PHP script that runs any number of automated spades games, involving a variety of players utilizing different play algorithms.  Since the algorithms are what we’re most interested in, I decided to use the strategy pattern: each player is an instance of the same basic Spades_Player class, but each has its own instance of one of several Spades_Strategy_Interface implementations that controls how it bids and how it chooses the card to play.  Here are the interfaces:

interface Spades_Player_Interface
{
  public function __construct(Spades_Strategy_Interface $strategy, $name = null);

  // player should have an identity
  public function getName();

  // player is part of a particular Spades_Game, and
  // is seated in a particular position from 0 to 3
  public function getGame();
  public function setGame(Spades_Game $game);
  public function getPosition();
  public function setPosition($position);

  // player has several cards
  public function getCards();
  public function receiveCard(Spades_Card $card);

  // actual playing methods
  public function placeBid();
  public function playCard(Spades_Trick $trick);

  // player should also be able to respond to certain events
  public function preHand(Spades_Hand $hand);
  public function preTrick(Spades_Trick $trick);
  public function postPlay(Spades_Trick $trick, Spades_Play $play);
  public function postTrick(Spades_Trick $trick);
  public function postHand(Spades_Hand $hand);
}

Now on to the strategy pattern. You’ll notice a lot of the same methods here; as I understand it, that’s the idea behind this particular pattern. It implements a lot of its owner’s methods so that different instances of the same owner class can have very different behaviors. Here’s the code I used:

interface Spades_Strategy_Interface
{
  // strategy should know its player
  public function getPlayer();
  public function setPlayer(Spades_Player_Interface $player);

  // convenience methods for getting state information from the player
  public function getGame();
  public function getPosition();
  public function getCards();

  // player hook implementations
  public function preHand(Spades_Hand $hand);
  public function preTrick(Spades_Trick $trick);
  public function postPlay(Spades_Trick $trick, Spades_Play $play);
  public function postTrick(Spades_Trick $trick);
  public function postHand(Spades_Hand $hand);

  public function placeBid();
  public function playCard(Spades_Trick $trick);
}

And, just so you see how it works in practice, here’s a sample method from my actual Spades_Player implementation:

class Spades_Player implements Spades_Player_Interface
{
  // ...
  public function playCard(Spades_Trick $trick)
  {
    $toPlay = $this->_strategy->playCard($trick);
    $trick->receivePlay(new Spades_Play($toPlay, $this));
    return $toPlay;
  }
  // ...
}

So there it is, nice and simple. Testing a new strategy algorithm is as simple as defining a new PHP class.

It’s also probably a good idea at this point to define some sort of reference strategy to test against…something that any intelligent spades player ought to be able to beat. How about randomizing it? (Note that I’ve implemented a lot of the hook methods in a separate abstract class, so there’s a lot less to write here than the interface suggests.)

class Spades_Strategy_Random extends Spades_Strategy_Abstract
{
  public function placeBid()
  {
    return mt_rand(0, 4);
  }

  public function playCard(Spades_Trick $trick)
  {
    $playable = $trick->getPlayableCards($this->getCards());
    return $playable[array_rand($playable)];
  }
}

Hmm, that kind of looks like the strategy I use.

Anyway, there are quite a few places we could go from here; I’ve already implemented most of the classes you see mentioned in the code above (Spades_Game, Spades_Hand, Spades_Trick, Spades_Play, and Spades_Card), but the real fun is in writing new strategies. Some ideas I’ve had:

  • Probability-based: the player remembers which cards have been played and figures out how likely it is any of its playable cards can be beaten by any of its opponents. (More on this later; I’m not quite sure about the math here.)
  • Evolutionary: the player starts out playing at random, but always remembers whether a given card ends up beating a given trick state. For instance, if it plays the Ace of Clubs on top of the Two of Clubs and then ends up winning the trick, it’ll be more likely to play the Ace of Clubs against the Two of Clubs in later hands.
  • Cheater: you’ll notice that the Spades_Player::getCards() method is public, and astute readers may have already guessed that Spades_Game implements a public getPlayers() method; as a result, unscrupulous players would technically be able to take a peak at their opponents’ hands and play accordingly.

That’s all I’ve got for now; if anyone is interested, I may post the full code later once it’s finished. Thanks for reading!

Written by jazzslider

March 12, 2009 at 6:26 am