debuggable

 
Contact Us
 
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29

30 minutes are more than you think

Posted on 4/9/08 by Felix Geisendörfer

Hey folks,

So I'm now 15 days into the 30 day challenge I set for myself. So far I have covered quite a bit of ground and would like to use this post (#16) to share some of the experiences I had.

First of all lets look at the posts:

  1. requestAction considered harmful
  2. String substitution using UUIDs
  3. Hacking the Wires
  4. Private methods - Follow Up
  5. Two CakePHP tricks
  6. Simple Data Access Control
  7. I believe in Symmetry
  8. Passing controller variables to your JavaScript
  9. HDD surgery for my MacBook Pro
  10. Normalizing CakePHP model records
  11. Lookupable Behavior
  12. Cloud Behavior
  13. Akismet datasource
  14. Datasources, Models, Components, Behaviors
  15. TextExpander & Apple Mail recipient name auto insertion

As you can see some of the posts are not necessarily CakePHP / JS specific. However, 10 out of the 15 posts contain previously unreleased code which is a figure I'm quite happy with.

Much more interesting however is that I pretty much planned out none of these posts. I set my alarm to 7:30am in the morning but quite a few times I also allowed myself a little more sleep if I was up too late the night before. So when I got up, I used whatever time was left before 9am to come up with an idea for a post and write it.

In general I would guess that about 50% of the posts so far were written in 30 minutes or less. Some of the posts above were even written in 10 minutes.

This came as an incredibly suprise to me, because I would not have thought that it was possible to write a decent blog post in less than 1 hour. One could of course argue that the quality of my posts suffered, but I haven't seen too much evidence of that. No here is what I think:

If you are given nothing but 30 minutes to contribute to society - you act. You don't let yourself be stopped, distracted or second guess yourself. There simply is no time for it.

Never have I experienced such powerful evidence of Parkinson's law before. But the more I do, the more I start to believe that our biggest productivity bottleneck is having too much time!

I mean we have a whole life time for our accomplishments. But if you look at the achievements of the vast majority out there, you'll surely agree that most of it could be accomplished in less than a year.

Quite seriously, I think I would be excited if at any point of my life I was told I had 90 days left to live. Don't get me wrong, this is not a suicidal kind of fantasy after too much dealing with internet explorer. I obviously hope to live much longer. But I'm really happy to have come to the realization that no matter how much time we have at our hands, there are incredible things we can do with it.

So I am already exploring new ideas to enforce time constraints with other aspects of my work. I have a few side projects I'm quite excited about, but that seem to move at an incredibly slow pace. The main problem is that there are no consequences of not having them move rapidly and so they don't. I will update you as I start to implement new approaches for them.

Anyway, I want to thank everybody for helping me with this! A few people have email'd me about the money because they missed my post updating my reference time zone (EST now) or were a little too early when I posted an article 10 seconds before the deadline ended. Amazingly pretty much all of them wanted to donate the money to the cake software foundation which is great. However, I will still try to not loose my challenge : ).

So stay tuned for the new and exciting posts to come beginning tomorrow.

-- Felix Geisendörfer aka the_undefined

 

TextExpander & Apple Mail recipient name auto insertion

Posted on 3/9/08 by Felix Geisendörfer

Hey folks,

this is post #15 of my 30 day challenge.

Today I want to share a little Mac productivity trick for Apple Mail that I came up with yesterday. I'm in the process of switching from my long-time E-Mail client Thunderbird. Thunderbird and I had a good time, but I can't deal with its problems anymore. UTF-8 emails break text selection, line breaks are off, and a few other things here and there annoy me. But most importantly, Thunderbird does not do a good job on osx integration.

So one of the things I was used from Thunderbird was an extension called QuickText. It basically allowed me to define a response template where I could use the recipients first / last name as a placeholder variable. After doing some research in the Apple Mail world, I found that MailTemplate seems to do what I needed. However, I wasn't too happy to have to do 2 mouse clicks for invoking it.

Meet TextExpander. TextExpander is basically a tool that can auto-insert custom snippets wherever you need them. There are tons of tools like this out there, but most Mac folks seems to like this particular implementation.

Anyway, the big problem with it is, is that it has no direct Apple Mail integration. Therefor you cannot use the first / last name of the recipient in your templates. However, it does support AppleScript, so after a little tinkering I was able to come up with this:

tell application "Mail"
	set selected to selection
	set msg to item 1 of selected
	set sentBy to (sender of msg)
	"Hey " & word 1 of sentBy & ",\n\n\n"
end tell

My abbreviation for this snippet is "hey". This is a huge help for me since I have to answer tons of different people every day and addressing them with their first name is usually a nice thing to do. I also have some snippets using the last name (mainly for Germans who are all Mr. and Mrs. with each other ^^) , all you have to change is "word 1 of sentBy" to "word 2 of sentBy".

-- Felix Geisendörfer aka the_undefined

 

Datasources, Models, Components, Behaviors

Posted on 2/9/08 by Felix Geisendörfer

Hey folks,

this is post #14 of my 30 day challenge.

In my previous post people were wondering why I had chosen a datasource for my implementation of the Akismet API. Some people felt Models, Components or even Behaviors could be more appropriate.

Indeed, about 2 years ago I did a previous Akismet implementation using a Model. But that always felt wrong. In CakePHP Models are meant to abstract a relational database table. To map its associations, to define its validation rules and provide easy CRUD functionality.

Unless the web service you're dealing with is a REST interface for CRUD operations, using a Model for its abstraction is way overkill.

So what about Behaviors? Behaviors are meant to abstract re-usable CRUD, validation and association tasks. A behavior might interact with a web service, but should not be the primary means of abstracting it.

Components are tempting. They indeed seem like a good choice for certain tasks. But their strength lays elsewhere. Components are good for abstracting functionality shared among multiple controllers. Often times they aren't even necessary because the logic one is trying to abstract has its place inside the model. Also:

Components are not globally accessible nor do they have a built-in mechanism for configuration like datasources do.

So I am fairly convinced that most web services are best abstracted using datasources. They make it easy to store the API key in your database.php file (which is not semantically perfect but lets be a little forgiving here). They can be accessed from a Component, Controller, Model, Behavior or any other part of your application and that makes a ton of sense. Because some services may allow you to upload data, resize pictures, transform text, detect spam, aggregate information, validate identities - all things that are best done in different places of your application.

There are some imperfections to the whole thing and some web servies might require the combination of a datasource (for the protocol) and a model (for the CRUD abstraction), but if you are in doubt - start with a datasource.

If you are interested in learning, check out some of the datasources we have published so far:

-- Felix Geisendörfer

 

Akismet datasource

Posted on 1/9/08 by Felix Geisendörfer

Hey folks,

this is post #13 of my 30 day challenge.

For our blog here at debuggable we use the excellent Akismet service to protect ourselves from spam. Thanks to CakePHP, our implementation for it is as simple as this:

class Comment extends AppModel{
  var $validate = array(
    'text' => array(
      array(
        'rule' => array('notSpam'),
        'message' => 'This comment appears to be spam. Please contact us if the problem persists.',
        'required' => true,
      ),
    ),
  );

  function notSpam($fields) {
    $akismet = ConnectionManager::getDataSource('akismet');
    return !$akismet->isSpam($this->data['Comment'], Post::url($this->data['Comment']['post_id']));
  }

}

So if you are coding up a little blog or something else that needs (Comment) spam protection, we released our Akismet API datasource for you.

Get it while its hot: Akismet Datasource at the Debuggable Scraps repository.

Alright, hope this helps some of you out there. Please Comment with suggestions and criticism ; ).

-- Felix Geisendörfer aka the_undefined

 

Cloud Behavior

Posted on 31/8/08 by Felix Geisendörfer

Hey folks,

this is post #12 of my 30 day challenge.

While preparing the application we use for our Raleigh, NC workshop, I had to implement an algorithm to display the records of a table in tag-cloud kind of view. Since the approach I took turned out fairly neat I thought other people might like to use this, so I refactored everything into a little behavior this morning.

In order to download & install the behavior, please go here: Cloud Behavior at Debuggable Scraps.

The code for the behavior itself looks like this:

class CloudBehavior extends ModelBehavior{
  var $mapMethods = array('/^_findCloud$/' => '_findCloud');

  function setup(&$Model, $settings = array()) {
    if (!isset($this->settings[$Model->alias])) {
      $this->settings[$Model->alias] = array(
        'scale' => 2,
        'shuffle' => true,
        'query' => array(),
        'countField' => 'count',
      );
    }
    if (!is_array($settings)) {
      $settings = array();
    }
    $Model->__findMethods['cloud'] = true;
    $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], $settings);
  }

  function _findCloud(&$Model, $method, $state, $query, $results = array()) {
    if ($state == 'before') {
      $query = array_merge($query, $this->settings[$Model->alias]['query']);
      return $query;
    }
    if (empty($results)) {
      return array();
    }

    $countField = $this->settings[$Model->alias]['countField'];
    if (!$countField || !$Model->hasField($countField)) {
      trigger_error('CloudBehavior: You have to configure a valid countField for querying this Model\'s records as a cloud!');
      return array();
    }

    $max = $results[0][$Model->alias][$countField];
    $min = $results[count($results)-1][$Model->alias][$countField];
    $range = $max - $min;
    if (!$range) {
      $range = 1;
    }

    foreach ($results as &$command) {
      $command[$Model->alias]['scale'] =
        (($command[$Model->alias][$countField] - $min) / $range)
        * $this->settings[$Model->alias]['scale']
        + 1;
    }
    if ($this->settings[$Model->alias]['shuffle']) {
      srand();
      shuffle($results);
    }
    return $results;
  }
}

Please note how I have to violate the concept behind private methods and properties to make this work. My follow up post on this topic is close to completion ; ).

The elegant part about this approach is that you can really keep your view logic down to a minimum:

$out = array();
foreach ($tags as $tag) {
  $size = 10 * $tag['Tag']['scale'];
  $out[] = $html->link(
    $tag['Tag']['name'],
    array('controller' => 'tags', 'action' => 'view', $tag['Tag']['id']),
    array('style' => 'font-size: '.$size.'px;')
  );
}
echo join(', ', $out);

Anyway, I hope this code is helpful to some of you out there. Feedback is welcome as always. Please comment!

-- Felix Geisendörfer aka the_undefined

 
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29