A flexible team- five things to get right

On the first of November 2012 I joined CouchCommerce to lead the frontend development. Here are five things that I highly enjoy here and that I think make my life easier and more fun.

1. Use a notebook + monitor  approach rather than a PC + monitor approach

At my previous job I used a regular PC at the office with three monitors attached. Not that they forced me to use that, I could have had any system when I started my job. But since nobody worked on a notebook, it was the obvious choice to use a PC as well. It was the fasted machine one could think of. 16 GB Ram. Core i7. Fast SSD drives. The machine was super swift and never let me down.

At my new gig here at CouchCommerce everyone used MacBooks with only one monitor attached. Since every web developer seems to work on a MacBook these days it again was the obvious choice to align with that 🙂 It’s the fastest retina MacBook you can  buy. I don’t like to make compromises when it comes to speed. I take my work seriously and same goes with my tooling.

It was a bit of a hassle at first to get used to work with only two physical screens but since you can use multiple virtual screens on OSX  I quickly got used to it. I don’t want to go into too much detail about how the switch to OSX went. There are plenty of other good posts on that topic.

The point is: using a notebook/MacBook + monitor is so much more convenient than using a stationary computer + monitor. Previously I used to work on three different machines:

– my office PC
– my PC at my home office
– my notebook

Multiple systems lead to multiple problems:

– I had to maintain three different machines with tooling, updates etc
– I often forgot to push code so when I worked from home I had to ask a team mate at the office to boot my computer. Or even worse I forgot to push code after a day of doing home office so I was lacking the code when I returned to the office

I really enjoy having only one system. I’m sometimes in the middle of a coding session when I decide to close the lid and go home. At home I can directly continue with my work. I also have the latest stuff with me. May it be on the train, at a conference or at the office. I also only reboot once every couple of months or so. That makes my life so much easier.

2. Be flexible.

That goes hand in hand with the previous issue. In my six month at CouchCommerce I already had four different work places. The team went from 4 people to 10 people within that time. We rearrange desks, switch offices just as it fits our needs. That also relates to everyone working on a MacBook. The setup is just super lightweight. We also regularly try out new software that has the potential to make our life easier.

3. Use dropbox and google docs for file Management.

I remember file management often was an issue at my previous job. We used to put documents on a central file server. Files went quickly out of date and manually versioning with multiple dated file names didn’t make it any easier.

I highly enjoy working with team mates together on one google doc. Everything stays in sync. Automatic version control makes sure nobody has to lose their sanity.

4. Use a company social network like yammer.

Well yammer, has it’s own dark corners. It’s not all milk and honey. However, we also tested several other company social networks and didn’t come across any better one so far. In general it really helps to get everyone up to date dramatically. It’s an important cornerstone of our communication. We always know about who is where. We share code improvements, interesting articles, fun stuff, being off, doing home office.

5. Speak english. Prepare to go international.

One thing that always bothered me at my previous employer was that we used too much German. Code comments where made in German. Some variable or methods where named in German. Technical documents where written entirely in German. That makes it much harder to scale the team.

Here at CouchCommerce three of my team mates don’t speak German as their mother language. We use ca. 95 % English when communicating through yammer and  at least 60% English when talking directly to each other at the office. Our product was designed English-first, German-second. All our technical documents, the entire code base everything is entirely written in English. We can easily scale our team and employ people from all around the world.
Those things might or might not work for your. Works for us.

Advertisements

Improving the hannoverjs.de site

A couple of days ago we came together again at the EDELSTALL to have our regulary hannoverjs meetup. It was that day when someone on Facebook asked me where he should have looked to figure out the date earlier.

My immediate rection was: “It’s every two month and it’s the fourth Thursday.”

Well, while me and a couple of others now about the rhythm and it’s also mentioned on the hannoverjs.de site, we shouldn’t assume that everyone does. It’s a huge fail when we rely on the assumption that everybody knows about that for sure.

So I pulled up my sleeves and automated the appearance of the date on our website so that it always points to the correct next date for our event.

And while I was at it, I rewrote the whole page with AngularJS (it previously used jQuery and Backbone). One of the benefits is that the talk section is much more maintainable now.

1. All talks for one event are written in it’s own file which follows the pattern MM_YYYY.tpl.html (Example)

2. Old talks can be viewed by just changing the date in the URL. (http://hannoverjs.github.com/hannoverjs.de/#/talks/01/2013)
(but I didn’t finish to extract the complete history from the commit logs yet)

3. There’s a default talk template which is automatically shown when nobody added a talk for the upcoming meetup yet.
So whenever one views the talk section, it should always make sense 🙂
On a side note: when you feel something about the site or the meetup in general could be improved. Don’t hesitate. Send PRs. Get in touch. We are a community.

From jQuery Deferred to RxJS ForkJoin

In a recent posting I blogged about how to process some code after several asynchronous operations have finished and how to access each return value of those operations no matter in which order those would finish.

To make this happen I used the new jQuery Deferred API. While this is a great way, I would also like to show you that there are other (even more advanced) ways to do so.

One of my heart warming interests is to dig deep into reactive functional programming and therefore digging into RxJS.

So let’s see how we can rewrite our example to make use of RxJS!

 

$(document).ready(function(){

    var example = function (){
        var deferred = new Rx.AsyncSubject();

        setTimeout(function(){
            deferred.OnNext(5);
            deferred.OnCompleted();
        }, 1000); //Will finish first

        return deferred;
    };

    var example2 = function (){
        var deferred = new Rx.AsyncSubject();
        setTimeout(function(){
            deferred.OnNext(10);
            deferred.OnCompleted();

        }, 2000); //Will finish second

        return deferred;
    };

    Rx.Observable
      .ForkJoin(Example(), Example2())
      .Subscribe(function(args){
            console.log("Example1 (Should be 5): " + args[0]);
            console.log("Example2 (Should be 10): " + args[1]);
          });
    });

As you can see, nothing ground shaking happened to our code. Things are just named slightly different.

Did we gain anything? Yes, we did! ForkJoin not only combines two observable streames and waits until both have finished, but in fact returns a new observable stream. Having an observable stream as an first class object is a major benefit! For example, let’s say we are only interested if first stream matches a certain condition. We can just filter out the undesired values using the Where operator.

    Rx.Observable
      .ForkJoin(Example(), Example2())
      .Where(function(x){ return x[0] == 5; })
      .Subscribe(function(args){
            console.log("Example1 (Should be 5): " + args[0]);
            console.log("Example2 (Should be 10): " + args[1]);
          });
    });

And once again, the Where operator returns a new observable stream. This is great in terms of composability. You can easily just hand this new observable stream over to another component which will react on a stream of data that exactly matches the conditions the component was intended for.

Having events as first class citizen which you can compose and pass on, is what makes Rx so great.

Clean up your code with RxJS!

Today I would like to talk a bit about the Reactive Extensions for JavaScript (aka LinqToEvents).  From when I heard the first rumors about it, I had a very keen eye on the project because I just felt there was something fascinating about it.

Unfortunatly, I didn’t really “got it right” and never found a real use case to test things out. But with all this noise around the new jQuery deferred API I recognized some common ground between those two technics and started digging into RxJS/Rx .NET again.

Finally, I was able to scratch a bit on the surface which I would like to share with you 🙂

So let’s say you have built a web app with a search textbox that fires up an ajax request while the user is typing. This is quite common and I’m sure you have done that before.

You don’t want to fire up the ajax call on every keystroke but only when the user stopped typing instead.  So, you just encountered the first brainer. What does it mean “when the user stopped typing”?

There is no native way to do something like that:

$('#searchinput').bind('StoppedTyping', function() {
  console.log('stopped typing')
});

What you actually mean is, “I want this code only to execute when 500 milliseconds have passed after the last occurrence of the ‘keyup’ event”.

So, maybe u managed this by saving a timestamp inside an outter var. Or you were lucky enough to come up with a solution which doesn’t  rely on an outter var at all.

This is the Rx way to acomplish what I described earlier. How does that look for you? Pretty straight forward, isn’t it?

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .Throttle(500)
        .Subscribe(function(text){
          console.log('fire up ajax call'); 
        });
});

There is no outter var, therefore no side effect. I’m not going much into the details because there are better resources to look this up.

So let’s sum things up so far. While you type, nothing fires. The call will fire after you finished typing. But what if you finished typing a word, the call fires, you type again but end up with the same word for which you just fired the ajax call, the moment before. Let’s say we want avoid such a needless call. It’s trivial with RxJS!

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .Throttle(500)
        .DistinctUntilChanged()
        .Subscribe(function(text){
          console.log('fire up ajax call');
        });
});

Easy, isn’t it?

Or how about avoiding calls, for words with less than three letters?

$(document).ready(function(){
    $('#myInput')
        .toObservable('keyup')
        .Select(function(){ return $('#myInput').val(); })
        .SkipWhile(function(text){ return text.length < 3; })
        .Throttle(500)
        .DistinctUntilChanged()
        .Subscribe(function(text){
          console.log('fire up ajax call');
        });
});

This is just scratching the surface of what can be down with RxJS. I'm just starting my RxJS journey…but I like what I have seen so far!

Accessing return values from multiple Deferreds

It’s been a while since I wrote my last posting. As I feel that I am constantly in a hurry I rarely manage to find some time *sigh*.

However, too many interesting stuff which is worth blogging keeps flooding our beloved tech world! One of those things is the new Deferred object in jQuery 1.5.

I won’t go into every detail about what Deferreds are for because Eric Hynds already wrote an awesome article about it.

Just to give an example: Some month ago, I asked on stackoverflow which was the best way to spin off several async calls and do something when all those async calls have completed. Well, that’s one of the things that Deferreds can solve.

Today I want to show you how to deal with that and also how to deal with it if each call returns a value which you need to have access to afterwards.

Let’s look at this code:

$(document).ready(function(){

    var example = function (){
        var deferred = $.Deferred();

        setTimeout(function(){
            deferred.resolve(5);
        }, 1000); //Will finish first

        return deferred.promise();
    };

    var example2 = function (){
        var deferred = $.Deferred();
        setTimeout(function(){
            deferred.resolve(10);
        }, 2000); //Will finish second

        return deferred.promise();
    };

    $.when(example(), example2())
        .then(function(arg1, arg2){
            console.log("Example1 (Should be 5): " + arg1);
            console.log("Example2 (Should be 10): " + arg2);
          });
    });

jsFiddle: http://jsfiddle.net/cburgdorf/M4JKR/

We created two Deferred objects (Example1, Example2) which both resolve with an return value. In the callback, which is called on $.then we have access to those return values. It might be obvious to you (but wasn’t to me) that those parameters will be sorted in the order in which the Deferreds were registered to $.when. That means, no matter in which order those async operations complete, you will be save to access the values in the expected order.

Here comes the proof with the operations turned around:

$(document).ready(function(){

    var example = function (){
        var deferred = $.Deferred();

        setTimeout(function(){
            deferred.resolve(5);
        }, 2000); //Will finish second

        return deferred.promise();
    };

    var example2 = function (){
        var deferred = $.Deferred();
        setTimeout(function(){
            deferred.resolve(10);
        }, 1000); //Will finish first

        return deferred.promise();
    };

    $.when(example(), example2())
        .then(function(arg1, arg2){
            console.log("Example1 (Should be 5): " + arg1);
            console.log("Example2 (Should be 10): " + arg2);
          });
    });

jsFiddle: http://jsfiddle.net/cburgdorf/vmLfF/

There is a lot more to discover with jQuery Deferreds, but I hope you found this little piece useful 😉

struggleing through the ajax world

We recently decided to port our website over to the Kohana Framework. A great decision! However, we are not only switching over to Kohana and the MVC approach, we also want to make more use of ajax. Not at least because we want to give our users a better experience. Whatever, I will go more deeper into the whole migration process in some weeks. Today Im asking the jQuery heros for their help.

What I want is

1. to save a form

2. to show a modal box, telling the user the form can’t be saved, incase of any validation rule violation

3. to ask the user for confirmation incase of any special conditions. For example, if he changes his zipcode he will be informed that this will lead to loosing his credit points and he must confirm with yes in order to save the form.

What I have

I won’t post every detail but hopefully enough to understand my problem 😉 I should also mention that I use the simplemodal box[1] to show the dialog. And it might be also worth knowing that Im a total noob on javascript and the whole ajax thing.

The View

I have a simple form like that:

<?=form::open('editroot/save', array('id' => 'edit_root'), NULL)?>
<table border="0" cellpadding="5" cellspacing="5">
<tr>
<td width="100">Vorname:</td>
<td><?=form::input('firstname',$firstname, ' class="inputbox_mp" maxlength="50"');?></td>
</tr>
<tr>
<td>Nachname:</td>
<td><?=form::input('lastname',$lastname, ' class="inputbox_mp" maxlength="50"');?></td>
</tr>
</table>
<?=form::close()?>

And my javascript looks like that…


$(document).ready(function()
{
     //attach onSubmit to the form
     $('#edit_root').submit(function()
     {
         //When submitted do an ajaxSubmit
         $(this).ajaxSubmit(
         {
             dataType: 'json',
             success: function(data, responseCode)
             {
                 if (data.category == 'conditionApplied')
                 {
                     confirm("Are you sure you want to ignore condition XYZ", function ()
                     {
                         jQuery.post('<?=url::base(FALSE)?>editroot/save', {ignoreConditions : "ignoreConditions"});
                     });
                 }
                 else if (data.category == 'invalid')
                 {
                     confirm("Your data is wrong (invalid email etc.)", function ()
                     {
                         // do nothing because the user has to change his inputs
                     });
                 }
             }
         });
         //return false to prevent normal submit
         return false;
     })
 }); 

function confirm(message, callback)
{
    $('#confirm').modal(
    {
        close:false,
        position: ["20%",],
        overlayId:'confirmModalOverlay',
        containerId:'confirmModalContainer',
        onShow: function (dialog)
        {
            dialog.data.find('.message').append(message);
            // if the user clicks "yes"
            dialog.data.find('.yes').click(function ()
            {
                 // call the callback
                 if ($.isFunction(callback))
                 {
                     callback.apply();
                 }
                 // close the dialog
                 $.modal.close();
            });
        }
    });
}

The Controller

	public function save()
	{
		if(request::is_ajax())
		{
			$post = new Validation($_POST);
			$post->add_rules('firstname', 'required');
			if(!$post->validate())
			{
				echo json_encode(array('category'=>'invalid','text'=>'Error during saving'));
			}
			else
			{
				if (isset($_POST['ignoreConditions']))
					$this->store();
				else
				{
					echo json_encode(array('category'=>'conditionApplied','text'=>'Error during saving'));
				}
			}
			$this->auto_render=false; 
			return;
		}
	}
	
	private function store()
	{
		//its valid, the user had been asked to accept special conditions etc.
                //we are ready to update the user account in the database
	}

Let me explain what the code does:

1. When the user clicks on the submit button, the $_POST array will be send through an ajax request to the controller.

2. The controller validates the data:

Now A.) If the user made an invalid input (missing firstname in this example) the controller will return ‘category’=>’invalid’. The javascript will show a message telling the user that the data was wrong.

Or B.) If the user made an input that will lead to something special (loosing credit points etc.) the controller will return ‘category’=>’conditionApplied’. The javascript will show a confirm message asking the user if he was sure to save and accept the special conditions coming along with his decision.

The first one is not really interesting because it means the user can not proceed until he changes his input. However the second one is more interesting. Incase the user clicks ‘Yes’ I want to send the $_POST data again and would like to append a value as an indicator for the controller.

It’s easy to send this single $_POST indicator but I need it to be send TOGETHER with the actual data. I find that hard to manage. Does it mean that I need to manipulate the form by appending a hidden field or anything?

And somehow, I think the whole js code smells and it feels like a dirty hack to me. There must be a more straight forward approach to it, isnt there? I also dislike the way I return the json answers…however I just took an example from the web and changed it a bit to make it run for me 😉

Happy for anybody trying to help me on this…

UPDATE

I finally got it working on my own. So here is what I did:


$(document).ready(function()
{
     //attach onSubmit to the form
     $(document).ready(function() 
{ 
	//attach onSubmit to the form
	$('#edit_root').submit(function()
	{
		//When submitted do an ajaxSubmit
		$(this).ajaxSubmit(
		{
			dataType: 'json',
			success: function(data, responseCode) 
			{
				if (data.category == 'conditionApplied')
				{
					confirm(data.message, 'irgendein title', 'yesAndNo', function () 
					{
						var queryString = $('#edit_root').formSerialize(); 
						queryString = queryString + "&acceptConditions"
						jQuery.post('<?=url::base(FALSE)?>editroot/save', queryString);
					});
				}
				else if (data.category == 'invalid')
				{
					confirm(data.message,'irgendein anderer title', 'ok', function () 
					{
						// do nothing because the user has to change his inputs
					});
				}
			}
		});
	//return false to prevent normal submit
	return false;
	})
}
);  

function confirm(message, title, buttons, callback) {
	$('#confirm').modal({
		close:false,
		position: ["20%",],
		overlayId:'confirmModalOverlay',
		containerId:'confirmModalContainer', 
		onShow: function (dialog) {
		
		if (buttons == 'yesAndNo')
			dialog.data.find('.ok').remove();
		else if (buttons == 'ok')
		{
			dialog.data.find('.yes').remove();
			dialog.data.find('.no').remove();
		}
			
			dialog.data.find('.message').append(message);
			dialog.data.find('.header').append('<span>' + title + '</span>');			
			dialog.data.find('.yes').click(function () {
				if ($.isFunction(callback)) {
					callback.apply();
				}
				$.modal.close();
			});
			
			dialog.data.find('.ok').click(function () {
				if ($.isFunction(callback)) {
					callback.apply();
				}
				$.modal.close();
			});
		}
	});
}

The Controller

		public function save()
	{
		if(request::is_ajax())
		{
			$post = new Validation($_POST);
			$post->add_rules('firstname', 'required');
			if(!$post->validate())
			{
				$errorMessage = '';
				$errors = $post->errors();
				foreach ($errors as $key => $val)
				{
				   $errorMessage .= $key.' failed rule '.$val.'<br />';
				}				   
				
				echo json_encode(array('category'=>'invalid','message'=>$errorMessage));
			}
			else
			{
				if (isset($_POST['acceptConditions']))
					$this->store();
				else if (1 == 1) //special condition is true
					echo json_encode(array('category'=>'conditionApplied','message'=>'Wollen Sie Kondition XYZ in Kauf nehmen?'));
				else
					$this->store();	
			}
			$this->auto_render=false; 
			return;
		}
		else
		$this->template->content = 'Ohne Javascript nix los :-(';
	}
	
	private function store()
	{
		//its valid, the user had been asked to accept special conditions etc.
	}

Well, basically I wasn’t really aware that Im using jQuerys form plugin here. Once I figured it out, I just checked the docs and found out I can serialize the form and just append any variable I want. The rest is more or less some sugar…I modified the confirm dialog to be flexible with its button etc. Maybe this will ease the pain of some other ajax newbie out there…

[1] http://www.ericmmartin.com/projects/simplemodal/

Writing a GetFirstDayOfWeek(int week, int year) function

It took me some time to write a DateTime GetFirstDayOfWeek(int week, int year) function yesterday. I’m not going to say HOW long it took me but just…I HATE date calculations. This should be a built in .NET feature!

Hopefully this will ease the pain of someone out there!

public static class DateHelper
	{		

		public static DateTime GetFirstDayOfWeek(int week, int year)
		{
			ThrowExceptionOnInvalidWeek(week);
			return GetFirstDayOfFirstWeek(year).AddDays((week - 1) * 7);
		}

		private static void ThrowExceptionOnInvalidWeek(int week)
		{
			if (week < 1 || week > 54)
			{
				throw new ArgumentException("the week must be within 1 and 54");
			}
		}

		private static DateTime GetFirstDayOfFirstWeek(int year)
		{
			DateTime firstDayOfYear = new DateTime(year, 1, 1);
			DateTime firstDayOfFirstWeek = new DateTime(year, 1, 1);			

			if (firstDayOfYear.DayOfWeek == DayOfWeek.Monday)
			{
				firstDayOfFirstWeek = firstDayOfYear;
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Tuesday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-1);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Wednesday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-2);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Thursday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-3);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Friday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-4);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Saturday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-5);
			}
			else if (firstDayOfYear.DayOfWeek == DayOfWeek.Sunday)
			{
				firstDayOfFirstWeek = firstDayOfYear.AddDays(-6);
			}
			return firstDayOfFirstWeek;
		}

	}