26 במאי 2009

so long and thanks for the phish להתראות


שנתיים של כתיבה בבלוג זה, 99 פוסטים (איזה מספר עגול ויפה) והגיע הזמן לבלוג חדש.
את הבלוג החדש החלטתי לכתוב באנגלית, מה שיאפשר לי בנוסף להקלדה מהירה יותר גם לפנות לקהל רחב יותר. זה בלוג על פיתוח תכנה, כמו בלוג זה ואולי אכניס שם פרספקטיבה שונה מהסטארט-אפ החדש שהתחלתי לעבוד בו.
אז ללא שהיות מיותרות, קבלו בבקשה את PrettyPrint.me
מקווה שתהנו מהבלוג החדש כפי שנהנתם מבלוג זה.


After two years writing this blog and 99 posts I'm starting a new blog at PrettyPrint.me.
This time my blog will be purely English in favor of the international audience. Topics discussed in the blog will naturally be software development and maybe an insight to the new startup I've recently joined. In hope you will enjoy my new blog as you did this one.

14 במאי 2009

Count - an improved WC bookmarklet


The Hebrew announcement will be followed by an english one ;-)

To install the bookmarklet right-click this: Count and add it to your Bookmarks/Links (or just drag and drop if you use a mac). Make sure the Links tookbar is visible if you use IE.



החלטתי לכתוב בעברית ובאנגלית ביחד, להיות ידידותי לכל הקהלים.
אז אחרי שמימשתי את המועדפון (מילה שהרגע המצאתי עבור bookmarklet) לספירת אותיות נשארתי בהרגשה שזה עדיין לא זה והחלטתי לשפר אותו עוד. רציתי משהו יותר גמיש שסופר כל הזמן ונשאר צף על הדף ובעיקר משהו שישמש כעוגן להמשך פיתוח עתידי, כלומר שהמועדפון יקרא לקוד על השרת ואת הקוד הזה אוכל לשפר עם הזמן ללא צורך להטריד את המשתמש בהסרה והתקנה מחדש.
בנוסף, רציתי גם להשתפשף על jQuery וזו נראתה הזדמנות מתאימה.
התוצאה של כל העניין הזה היא מועדפון חינני שאני מאוד גאה בו. הוא שימושי לספירת תווים (או גם מילים ומשפטים) ולא פחות חשוב, הוא גם נראה טוב. אז כדי שלא ישעמם לי את הפרטים הטכניים אני אכתוב רק באנגלית, מקווה שתהנו מהספרן.



After implementing the first version of WC I was left with the feeling that it wasn't good enough, that something was missing. What I wanted was first, something more flexible in it's look and feel, second will not make you click it again and again, but will simply count chars whenever you select some text and third, is easy to upgrade.
I finally rewrote the bookmarklet and came up with this: Count
To host it I created a google apps application.
The idea is simple - there are cases you want to count characters. For example when using Topify to write a DM. All you need to do is click the bookmarklet and select some text (in any order; you may first select text and only then click the bookmarklet) and you get the char count right there as a floating window in your browser. You don't have to close it to continue your work, it'll just stay floating and you can drag it somewhere else if it gets in your way. What's nice is that next time you select some text it will listen and count the chars again.

Now the tech details.

What is a bookmarklet?
Bookmarklet are small pieces of javascript code wrapped in a bookmark. They are usually small applications or utilities you apply to the current browser page. In some sense they are like browser toolbars of addons or extensions but they usually are more lightweight, their installation process is VERY easy (drag and drop) and they are by definition cross-browser, so the same bookmarklet (when implemented correctly) should work on FF, IE, Opera, Safari etc. Example bookmarklets are bookmarklets that save links to delicious, bookmarklets that alert the page cookie etc.

How can javascript run inside a bookmark?
Bookmarks contain hyperlinks such as http://google.com. A hyperlink consists of several parts, the first being the protocol. In this example the protocol is http. After the protocol comes the colon delimiter and then the rest of the hyperlink. Browsers know many protocol types, to name a few: http, https, ftp and javascript. Yes. javascript is just another protocol the browser knows about which tells the browser to treat the rest of the text as actual javascript code and run it. So the following code will popup an alert box.

<a href="javascript:alert('hi')">Say hi</a>

Try it here: Say hi

Now, the same code can get saved as a bookmark, so if you drag that "Say hi" link to your link toolbar (or right click and add to bookmarks/link), every time you click it you get "hi".
So, this is the trick behind all bookmarklet. They are all hyperlinks using the javascript protocol, so they just run javascript on the current page without a page reload, which is important because they usually want to communicate with the page.

Why do you need the (function(){...})() construct in a bookmarklet?
If you look at real life bookmarklet, they all look like that:

(function(){...bookmarklet code here...})()

If you're wondering why does the bookmarklet code needs to get wrapped inside this weird function definition, wonder no more?
There are two compelling reasons to do this, but first let's see what is actually going on here with all the curly and other braces. What we have here is a function definition (an anonymous function)
function(){...}

This function is wrapped inside braces
(function(){...})

And after the braces we see another couple of braces:
(function(){...})()


What this construct accomplishes is an anonymous function definition and an immediate invocation of this function using the last (). So when the parser gets to the () it simply runs the code inside the function.
OK, so why do we need this? What's wrong with just having the actual code of the bookmarklet? Why do we need to wrap it in a function?
There are two reasons for this
1. the javascript: protocol allows for only one statement. So you can have a link javascript:alert(1) but you may not have javascript:alert(1);alert(2). A non trivial bookmarklet has more than one statement to using the above function construct lets you bundle several statements into one valid javascript statement javascript:(function(){alert(1);alert(2)})()
2. Namespace safety. The bookmarklet code may define local variables, for example var d = document; Now, keep in mind that a bookmarklet runs in the context of another page which you have no control over, so what if the page already has a variable d? Not good... The solution is simple, in javascript (as well as in other languages) variables are scoped, so if a bookmarklet defines a local variable d inside a function block it will not affect nor be affected by another page variable with the same name.

As a matter of fact, the function wrap trick is extensively used not only by bookmarklets, but by many other javascript applications that care about not polluting the default namespace. jQuery uses it as well.

How does one dynamically load server code to the current page?
Let's recall our setting: We write a bookmarklet, say the Count bookmarklet, which runs in the context of some arbitrary page so that when the user operates the bookmarklet by clicking it, the bookmarklet must not reload the page, but it needs to run scripts from a remote host. How do you do that? If the script was a simple alert() then you may simply include the code inline the bookmarklet. But if the code is considerably more complex, and maybe you want to use 3rd party code such as jQuery, what do you do?
As it appears, browsers allow dynamic loading of remote scripts by means of script injection to the head section (or to the body section, all the same). To acheive that you need to create a script dom element and attach it to the document head. The moment you do that, the browser notices that, loads the script and executes it. That's the same trick as jsonp uses, BTW, which I've blogged about in the past.
This is how you load a script dynamically:

var s = document.createElement('script');
s.setAttribute('src', 'http://charcount.appspot.com/s/jquery.js');
s.setAttribute('type', 'text/javascript');
document.body.appendChild(s);


What else is interesting about this bookmarklet?
I've had fun and challenges creating it. I enjoyed learning about jQuery, a kickass javascript library, I fought a lot of browser CSS quirks, learned a lot about how does one find the current selected text on a document (believe me, that's not half as easy as it may sound) and exercised my Fireworks Ninja. I did enough writing for one day, so I won't write about all these but if you have questions ping me at @rantav or just leave a comment here.

Where's your code? Can I see it?
Sure, it's all open sourced, hosted on Google Code here
And the web app that supports is is here.

29 באפר׳ 2009

WC - word count and char count


Update 2: There was a silly typo in the code which created a bug in gmail. I fixed that now, just remove the old WC and re-add the one just below.

Update: I have improved the bookmarklet to work with all types of frames and iframes (and not only gmail ones). Bookmarklet and code are updated.

Have you ever needed to count words in a document that you're authoring, in an email or a web page? Or even better, count characters and make sure you conform to the 140 twitter de-facto standard?
You have to try this bookmarklet then: WC

Again I'm blogging in English on this blog which is usually kept Hebrew, but since the last post on the subject was Heb I think that's fine.

A few days ago I was asked to give a twintterview, a short interview in email for which every question has to be answered with only 140 characters. Sounds like fun, right? But now, what if you had to actually count the characters for each and every answer? Not so much fun now... and twitter can't help you b/c you're in gmail...
So I did the interview and then took the time to write a simple bookmarklet that does that - counts words and chars of the selected text on a web page.

Many other applications already have this simple functionality built-in (e.g. Word or Unix) but unfortunately I couldn't find the same functionality as a bookmarklet or something else available to my gmail web client. Why does it have to be a bookmarklet? Well, it doesn't have to be one but I prefer it to be a bookmarklet b/c I want it to be available for my gmail and I want it to be browser agnostic. So, no Firefox add-ons, no Explorer toolbar, just a simple and straight forward bookmarklet.

First I thought, hey this is such a simple and useful functionality, there must be dozens of bookmarklet of add-ons out there doing just that. I googled it and found a few, but none of them were good enough for me, so I took the liberty to write my own (and use them as reference). For example the first one I found only counted words, while what I really need is chars. None of the bookmarklets of greasmonkey scripts. extension etc actually worked with gmail which is really where I needed it.

The code is right here (a bit compacted) for your enjoyment

javascript:(function(){
// Function: finds selected text on document d.
// @return the selected text or null
function f(d){
var t;
if (d.getSelection) t = d.getSelection();
else if(d.selection) t = d.selection.createRange();
if (t.text != undefined) t = t.text;
if (!t || t=='') {
var a = d.getElementsByTagName('textarea');
for (var i = 0; i < a.length; ++i) {
if (a[i].selectionStart != undefined && a[i].selectionStart != a[i].selectionEnd) {
t = a[i].value.substring(a[i].selectionStart, a[i].selectionEnd);
break;
}
}
}
return t;
};
// Function: finds selected text in document d and frames and subframes of d
// @return the selected text or null
function g(d){
var t;
try{t = f(d);}catch(e){};
if (!t || t == '') {
var fs = d.getElementsByTagName('frame');
for (var i = 0; i < fs.length; ++i){
t = g(fs[i].contentDocument);
if(t && t.toString() != '') break;
}
if (!t || t.toString() == '') {
fs = d.getElementsByTagName('iframe');
for (var i = 0; i < fs.length; ++i){
t = g(fs[i].contentDocument);
if(t && t.toString() != '') break;
}
}
}
return t;
};
var t= g(document);
if (!t || t == '') alert('please select some text');
else alert('Chars: '+t.toString().length+'\nWords: '+t.toString().match(/(\S+)/g).length);
})()


Disclaimer:
- Tested on FF and Safari. Didn't test on IE, so could be buggy

ספירת מילית ותווים WC


נתבקשתי לעשות ראיון-טוויטר, שזה אומר שכל תשובה לשאלה בראיון צריכה להיות באורך של לא יותר מ 140 תווים
את הראיון כבר השלמתי אבל סיימתי אותו בתחושת חוסר סיפוק. ולמה? מכיוון שלא הייתי בטוח שלכל התשובות אכן עמדתי במבחן ה 140. לחלק ספרתי אבל זה מתיש וברור שצריך כאן כלי אוטומטי.
חיפשתי משהו שסופר ומצאתי בערך, כלומר לא בדיוק מה שחיפשתי. אז קצת העתקתי והרבה שיפרתי וכתבתי את ה bookmarklet הבא ועכשיו אני הרבה יותר רגוע. אפשר לספור מילים ותווים ע"י סימון טקסט ולחיצה על ה bookmarklet

WC

מעניין שהאתגר הגדול יותר היה לגרום לו לעבוד ב gmail עם המערכת המופרעת של ה iframes שהולכת שם.
בדקתי בספארי ופיירפוקס. אין ברשותי אקספלורר, אז נותר רק להחזיק אצבעות, אבל אם יש באג נא לדווח.

הקוד במלואו, קצת מקומפקט להלן:


javascript:(function(){
var t,d=document;
if(location.href.indexOf('mail.google.com')>0){
d=d.getElementById('canvas_frame').contentDocument;
if(d.getElementsByTagName('iframe').length)d=d.getElementsByTagName('iframe')[0].contentDocument;
}
if(d.getSelection)t=d.getSelection();
else if(d.selection)t=d.selection.createRange();
if(t.text!=undefined)t=t.text;
if(!t||t==''){
a=document.getElementsByTagName('textarea');
for(i=0;i=a.length;i++){
if(a[i].selectionStart!=undefined&&a[i].selectionStart!=a[i].selectionEnd){
t=a[i].value.substring(a[i].selectionStart,a[i].selectionEnd);
break;
}
}
}
if(!t||t=='')alert('please select some text');
else{
alert('Chars: '+t.toString().length+'\nWords: '+t.toString().match(/(\S+)/g).length);
}
})()


10 באפר׳ 2009

לוח המשרות של רברס עם פלטפורמה


מזה מספר חודשים אורי ואני מקליטים פודקאסט לאנשי תכנה, רברס עם פלטפורמה. אנחנו נהנים מעצם העשייה ומהמפגש המעשיר עם האורחים שלנו, המאזינים והתגובות.
לאחרונה, עם התדרדרות מצב שוק העבודה החלטנו לעשות את שביכולתנו לסייע לאנשי תכנה מובטלים והקמנו את לוח המשרות של רוורס עם פלטפורמה.
לוח זה הוא שרות חינמי לחלוטין וללא כל התחייבות ומטרתו אחת: לשדך דורשי עבודה עם נותני עבודה. מה שמיוחד בלוח זה הוא שאני ואורי חושבים שיש הרבה שאלות שמעניינות דורשי עבודה בענף התכנה שאינן מקבלות מענה בלוחות המשרות הקיימים היום וזה מקשה על חיפוש העבודה ולכן כל מעסיק שמפרסם משרה מתבקש לענות על השאלון. מעבר לכך כיוון שהקהל שלנו מאוד ממוקד אנחנו מאמינים שביכולתנו לעשות שידוכים טובים. אז ללא שהיות מיותרות, מי שמחפש עבודה או מי שיש לו משרה להציע מוזמן לבקר את http://jobs.reversim.com נכון להיום יש כבר שלוש משרות פתוחות. תודה רבה לאדם מתן שלקח על עצמו את הפרוייקט הזה ועוזר לנו בבניית האתר.

אם מצאתם עבודה דרך הלוח אנא השאירו לנו הודעה או מייל - בטח נרצה לפרסם סיפורי הצלחה וגם להסיר את המשרה מהלוח.

מי שמחפש מהנדסי תוכנה מוצלחים- ניגש לאתר, ממלא את השאלון (בעברית או באנגלית) ושולח לאדם (שהתנדב לסייע במשימה החשובה הזו). משם אנחנו דואגים לפרסם אותה, לקדם אותה בבלוגים, בטוויטר וכמובן בפודקאסט.

בהצלחה לכולם ו... קדימה לעבודה.

19 במרץ 2009

TwitGraph-en


By popular demand I'm reposting this one in English. I usually keep this blog Hebrew only as I wanted it to approach Israeli developers but as I said, I was asked to post that one in en as well and who could resist such a request? ;)

For a while I've been trying to solve the following problem: how to effectively get feedback from users? Specifically online users. How does one measure success of a product launch or a campaign?
It's quite obvious I'm not the one first to think of this problem and I'm sure there's already an established industry out there working just on that but still... I had one specific problem that I just couldn't get solved any other way. So I built that solution my own hands. It was fun doing so, so I'm sharing the experience here.

Problem definition: I work on a product that has massive web attention. Once we release a new feature of the product I'd like to see how the community reacts. To do so I've set up several blog searches and fed them to Google Reader. I've also subscribed to a twitter search and fed that rss feed to GReader as well, but that wasn't enough. Some days I get dozens or hundreds of tweets and it gets too hard to measure both buzz and user's happiness. What I wanted to know was: 1) how many tweets are tweeted about my product and 2) were they positive or negative attitude?
So I've put the rest of the blogsphere and the rest of the world aside and simply concentrated on twitter.

I created this. A web application that graphs how many tweets a day there are on your subject of interest, plus, how many of them were positive, negative or neutral attitude.



And now... to the gory tech details. You can stop reading now if you don't care about fun software

I used google's appengine as my server, so a lot of the code is written in python. Naturally I also used a bit of javascript and family for the client side implementation. Arguably, I could have used more CSS to make it prettier, but I didn't (any volunteers that want to help with that?)

There were several interesting challenges, so I'll speak about them here and explain how I solved them.

1. Getting the data
What I want to do is query a date range, say past 7 days, and for each day graph how many tweets are there for that specific query term. So, challenge #1 is how to get that data.
Twitter has a pretty cool and slick search API which lets you search API-ish for all kinds of stuff. Here are just a few examples of it:
http://search.twitter.com/search.atom?q=twitter
http://search.twitter.com/search.atom?q=from%3Aalexiskold (from a user)
http://search.twitter.com/search.atom?q=twitter until:2009-03-01 (Until a date. You may also use from: date)

So, this API is quite nice. It not only allows you to query for an atom (xml) result but also a json and even jsonp, which is json with a callback and is useful for crossdomain requests. I'll talk a little bit about that later.
But the API has some very painful restrictions, the most important of them all is the limit on the number of results. They limit them to at most 100 for each call. Now, coming from a search engine company I can clearly see why they do that, they can't possibly allow not to limit the number of results, but as a developer that uses that API... that was a challenge.
It's important to me to get all the results and get the raw results, e,g, not aggregate b/c I'd like to run some text categorization algorithm on them later. Not that there's a way of getting aggregate results on twitter, but even if there were I wouldn't have used it.
So here's what I did: I called the API to get the first 100 results. Then I called it to get the next 100 results, and then the next 100 results... etc. That's mean, I know... API servers don't necessarily like that and they might block me sooner or later, but what other choice did I have?
This method works actually quite well for micro-trends. E.g. don't try to feed twitgraph with popular search terms such as "google" or "youtube" b/c it'll simple drown the server. That's one of the most annoying shortcomings of my service. But, for micro-trends, e.g. less popular trends it actually works pretty well, so that was really nice.
The first version was implemented almost entirely on the client side, which means that all logic was implemented in javascript and the google appengine server was hardly involved. But the second version changed that and nowadays all logic is actually implemented on the server, including recursively fetching the results.

Problem 1 solved (but only for micro-trends) by fetching results recursively.

2. How to analyze the data for positive and negative attitude?
The twitter search API has a neat feature. If you append to a search term a ":)" or a ":(" you get back happy/sad results. That's the first API that I've seen which actually uses emoticons, cool. Only problem is that it sucks :( and :( again. The results are absolute rubbish and had very poor quality, so I could not use them at all. Indeed, they would sometimes get the happy/sad sentiment right, but in most cases they would just say "don't know" and in some cases they would return the wrong answer. Bottom line: nice try, but can't use it.
So I had to do it myself. I didn't know what do to, so I posted a question on stackoverflow.
I got plenty of answers there, so now I knew what to do :)
Here's what I did: I fetched all the results from the server and then used a Naive Bayesian Classifier to tag them to :-), :-( and :-|.
Basically a naive bayesian classifier works like this:
First you train it by feeding it examples of :) tweets, of :( tweets and of :-| tweets which you prepared beforehand, and then you ask it to guess what's the sentiment of the next tweet. That works surprisingly well!
I used a bayesian classifier from here which was pretty simple to use. To bootstrap the system I fed it with a list of known good words and a list of known bad words that I found somewhere, which is BTW not ideal for a bayesian classifier, but it worked reasonably well, and then I added a dynamic learning feature, namely, as you get the search results back, as a user, you can teach twitgraph what's the correct sentiment of each and every tweet. Next time we use this data as a signal, and this turns out to be a very good signal. I've now tagged several dozens of tweets and already classification is getting really really good.

So - problem 2 solved - fetch all results and use an open-source bayesian classifier. Happy happy :)

3. How to graph the data?
That was actually the easiest part of then all!
I used the Google Visualization API javascript library which is pretty easy to use. Really, with only a few lines of code I created those nice graphs. To prove that I'll paste the two functions that draw the graphs here.


twitgraph.Grapher.prototype.drawLineChart = function() {
var aggregate = this.result.aggregate;
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Date');
data.addColumn('number', ':-(');
data.addColumn('number', ':-)');
data.addColumn('number', ':-|');
data.addRows(aggregate.length);
for (var i = 0; i < aggregate.length; ++i) {
data.setCell(i, 0, aggregate[i].date);
data.setCell(i, 1, aggregate[i].neg);
data.setCell(i, 2, aggregate[i].pos);
data.setCell(i, 3, aggregate[i].neu);
}

// Create and draw the visualization.
twitgraph.Utils.$('twg-graph').innerHTML = '';
var chart = new google.visualization.AreaChart(twitgraph.Utils.$('twg-graph'));
chart.draw(data, {legend: 'bottom',
isStacked: true,
width: 600,
height: 300,
colors: ["#FF4848", "#4AE371", "#2F74D0"]});
}

twitgraph.Grapher.prototype.drawPieChart = function() {
var stats = this.result.stats;
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Sentiment');
data.addColumn('number', 'Tweet count');
data.addRows(3);
data.setValue(0, 0, ':-(');
data.setValue(0, 1, stats.neg);
data.setValue(1, 0, ':-)');
data.setValue(1, 1, stats.pos);
data.setValue(2, 0, ':-|');
data.setValue(2, 1, stats.neu);

// Create and draw the visualization.
twitgraph.Utils.$('twg-graph-pie').innerHTML = '';
var chart = new google.visualization.PieChart(twitgraph.Utils.$('twg-graph-pie'));
chart.draw(data, {legend: 'none',
is3D: true,
width: 300,
height: 300,
colors: ["#FF4848", "#4AE371", "#2F74D0"]});
}

Problem 3 solved.
Well, almost... I also wanted to have the option of static images, e.g. gif. A common use case for static images is to be able to include the graph in an email which doesn't allow running any js. I solved that too, but this time using the Google Charts Service. So now static graph images (with for dynamic data which get updated every day) are also available.

Now 3 is really solved :)

4. how to embed in a 3rd party site?
I think twitgraph is useful if it can be embedded in 3rd party sites. But to do that you'd need to run an XmlHttp call across domains, which most browsers just wouldn't let you. The solution to that problem is already well known and is called jsonp, json with padding. That's actually a very well known technique which is widely used across other web services so I won't get into details and just lay out the short concepts and code here.
The idea is that you can't make an XmlHttp request across domains, but you can include JS across domains. And you can also load javascript dynamically to any web page if you'd just add a <script> element to its head at any given time, even if the page is already loaded. That javascript that you added to the page will call a callback function that you tell it to, once its loaded, and there - you have your data.
More about json and jsonp.
The code from my app is here:

function jsonp(url, callbackName) {
url += '&callback=' + callbackName;
addScript(url);
}
function addScript(url) {
var script = document.createElement("script");
script.setAttribute("src", url);
script.setAttribute("type", "text/javascript");
document.body.appendChild(script);
}

5 design
Well, what can I say... I didn't solve that one yet.. I'm bad at design so the application is still ugly. I'd be very happy to get professional help with this...

Hope the post was useful to all ya developers out there.

Would you like to contribute? The source code is here and you're welcome to drop me a line at the post comments.

18 במרץ 2009

דרוש מתנדב 2.0


הפופולריות של הפודקאסט שאני מריץ עם אורי, רוורס עם פלטפורמה, עולה יפה, ולאורי היה רעיון שאולי נוכל לנצל אותה לטובת הכלל.
הרעיון הוא לעזור לאנשי תעשיית התוכנה שמחפשים עבודה בתקופה קשה זו למצוא עבודה. אבל כדי לממש את זה אנו זקוקים לעזרה, אז אם יש למישהו כמה דקות פנויות ביום ורוח התנדבות קלה הוא מוזמן לפנות אלינו בדואל או להשאיר תגובה לפוסט ונוכל לדבר על הפרטים.
רן [את] רוורסים [דוט] קום או אורי [את] רוורסים [דוט] קום

11 במרץ 2009

פודקאסט מספר 10 - SundaySky


פודקאסט מספר 10 - יומהולדת שמח לנו.
הפעם שוב אורח - יניב אקסן יזם ו-CTO של סטארטאפ בשם SundaySky.

* יניב סיפר לנו על המוצר המ-ג-נ-י-ב! של החברה.
* מהי השפה שהחברה פיתחה? VSML !
* מי היה בשוק לפני?איזה תקנים קיימים?
* מי הם הלקוחות ולמה זה טוב להם - וידאו שמחולל בו-בזמן.
* האתגר לעשות את העבודה מהר ו... הרבה.
* איך עושים את ההמרה לוידאו. מה אפשר ללמוד מעולם המשחקים.
* להוציא מים מן הסלע - הסלע של אמזון AWS.
* איזה יתרונות יש לשימוש AWS ומה באמת מקבלים.
* למה Windows? למה צריך לשנות את התכנה כשעוברים ל-AWS?
* CloudFront ה-CDN של אמזון.
* SQS - רעיון מעניין לתזמון משימות.
* אם בחרת בשירות... עד כמה אתה קשור אליו?
* AWS - בחורה יפה - אבל משוגעת!
* מאיפה השם... SundaySky !

תודה ליניב ותודה לכל מי שתומך ומגיב על הפוסטים.
הקובץ כאן

3 במרץ 2009

פודקאסט מספר 9 - TDD - תיכנות מונחה בדיקות


פודקאסט מספר 9 של רוורסים הוקלט היום והיום outbrain מארחת את הפודקאסט ואיתנו היום אורח, איתי הוכמן.
דיברנו על תכנות מונחה בדיקות והשלכותיו על חיינו.

  • אז מה זה בכלל TDD?

  • מה זה בכלל נותן לנו? מה נשאר מהמאמץ?

  • דרישות -> כתיבת בדיקות -> פיתוח. פעם אחת או מעגל מחזורי.

  • בדיקות לפי שורות קוד או מודולים או לפי פונקציונאלית.

  • מתי לכתוב את הבדיקות. לפני? אחרי? תוך כדי?!?

  • אם יש באג בקוד הבדיקה.

  • מי כותב את הבדיקות? המפתח? הבודק?

  • שימוש ב - continues integration server והרצת הבדיקות.

  • בדיקות אינטגרציה מול בדיקות יחידה.

  • הנסיון של רן, מיקרוסופט מול גוגל וגישתם ל- TDD.

  • ממילא אנחנו מריצים את הקוד בפיתוח - למה לא להריץ תחת בדיקות היחידה.

  • איך בודקים UI? איזה כלים יש? האם אפשר לבדוק אוטומטית?

  • כלים: Team-City - JUnit - JMeter

  • טירונות בגוגל ואח"כ המסלול לבגרות באיכות קוד.

  • TOTT - הגרסה הגוגלית ל"עד מתי נובמבר..." על הקיר בשירותים.

  • כמה מהר לתקן בדיקה שנכשלה? מתי יוצרים פתח לשכונת עוני.


היה שוב מאוד מעניין.
תודה לאיתי.
כאן הקובץ - ביי

28 בפבר׳ 2009

TwitGraph



הרבה זמן מטרידה אותי השאלה איך מקבלים פידבק ממשתמשים באופן יעיל? איך מודדים הצלחה של מוצר או הצלחה של קמפיין? ברור שלא אני הראשון ששואל את השאלות הללו אבל אני שמח לבשר שהתחלתי לפתור את הבעייה הקטנה והנקודתית שלי ואני חולק כאן את הפתרון.

אז נתחיל עם הגדרת הבעיה: אני עובד על מוצר שיש לו הרבה מאוד משתמשים וכל חיפוש בגוגל, טוויטר ובבלוגים מניב מאות תוצאות וזה מאוד מעניין לקרוא אותן ולהבין יותר טוב מה המשתמשים שלנו חושבים עלינו. מצאתי שהפידבק בטוויטר הוא מאוד יעיל ואני משתמש בו המון כדי לשמוע תלונות, שבחים, להכיר סרטים חדשים שמשתמשים בפיצ'ר וכו'. לעתים יש כמה מאות טוויטים בכל יום, אז חיפשתי דרך לכמת את הפידבק בטוויטר, כלומר לראות באופן ויזואלי כמה טוויטים יש עלינו בכל יום ואף לראות כמה חיוביים וכמה שליליים מביניהם.

תחילה חיפשתי אפליקציה שתספק לי את התשובה הזו, אך משלא מצאתי, החלטטי לכתוב אחת משלי. קראתי לה טוויט-גרפ והנה היא כאן.





לקח לי פלוס מינוס שני לילות לכתוב אותה והיא ממש רק בחיתולים (יש רשימה ארוכה של TODO כאן) אבל אני כבר יכול לעשות בה שימוש אפקטיבי. רציתי לספר קצת על אופן הפיתוח שלה.

כמו שכבר הזכרתי, הצורך נבע מצורך אישי שלי לכמת ולראות בצורה גרפית מה העולם חושב, או יותר ספציפית, מה משתמשי טוויטר חושבים עלינו ומשלא מצאתי כלי מתאים שמחתי שיש לי הזדמנות לעשות משהו מועיל ולא רק לצורך התרגול, אלא ממש משהו שימושי (שדרך אגב, בחוג חברים מצומצם כבר עושים בו שימוש נוסף).

התחלתי לחפור ב Search API של טוויטר עד אשר מצאתי את מבוקשי. החלטטי שאני אשתמש ב App Engine, פלטפורמת אפליקציות הווב של גוגל גם בגלל שזה חינם ופשוט וגם בגלל שרציתי להעמיק את נסיוני בפלטפורמה ובפייטון והתחלתי בעבודה.



אז איך זה עובד? (טכני. וארוך...)

היה מעניין לעבוד על האפליקציה ולמדתי מספר דברים אז החלטתי לחלוק את נסיוני כאן. כל הקוד פתוח, ניתן למצוא אותו כאן ואני אשמח לקבל עזרה (ראו את רשימת ה TODO שלי)



ה API של טוויטר מאפשר לעשות חיפוש של search term כלשהו, למשל youtube annotations, כמו גם חיפושים מורכבים יותר כגון "כל הטוויטים שנשלחו אלי" - to:rantav או "כל הטוויטים שאני שלחתי ויש בהם יוטיוב" from:rantav youtube

בנוסף ה API תומך באופרטורים :) ו :( כלומר פילטור התוצאות לפי תוצאות שמחות או תוצאות עצובות. זה נעשה ע"י ניתוח "גוון הטקסט" של הטוויט והבנה האם הוא חיובי או שלילי, אבל לטעמי לא נעשה בצורה טובה ולכן אני אנסה לממש אותו בעצמי לכשיהיו לי כמה לילות פנויים.

ה API גם תומך לא רק בפורמט הקומפקטי של json כי אם גם ב jsonp, מה שמאפשר לי לפנות מהדפדפן ישירות אל טוויטר ללא צורך לעבור דרך השרת. זה גם נחמד יותר לביצועים וזה גם עדיף משיקולי scalability. הנה כמה שאילתות לדוגמא. אני משתמש ב curl כדי להריץ את השאילתה מה- command line אבל מי שאין לו curl מותקן יכול להשתמש ב wget או דומיו.




$ curl http://search.twitter.com/search.json?q=video+annotations



{"results":[{"text":"Anyone noticed how I've used annotations in my yesterday's http:\/\/sendme.to\/genov0003 video? I think it really helps ppl keep up with speech", ...},..more results here...],

"since_id":0, "max_id":1262171803, "refresh_url":"?since_id=1262171803&q=video+annotations", "results_per_page":15, "next_page":"?page=2&max_id=1262171803q=video+annotations", "completed_in":0.026702,"page":1, "query":"video+annotations"}




ניתן לראות שיש כאן מערך של תוצאות:



{"results":[{...},..more results here...],...}


ועוד metadata על השאילתא עצמה, כגון איזה עמוד זה, כמה תוצאות, והחשוב מכל, איך מקבלים את העמוד הבא:



"next_page":"?page=2&max_id=1262171803&q=video+annotations"


באמצעות ה next_page אני מביא את העמוד הבא והבא עד שאין יותר תוצאות.

אבל כמובן שמספר התוצאות יכול להיות אינסופי, אז צריך להחיל מגבלה של תאריך התחלה ותאריך סוף, ולשם כך גם כן יש תמיכה ב API. הנה שאילתה לדוגמא:



curl "http://search.twitter.com/search.json?&q=youtube%20annotations%20
since:2009-01-31%20until:2009-02-01"





כעת, אחרי שכל התוצאות הגיעו (ע"י קריאות מרובות) אני עושה להן אגרגציה לפי תאריך ואז מציג אותן בגרף.

החלק של ציור הגרף הוא למעשה הקל ביותר כיוון שאני משתמש ב Google Visualization API שהוא די פשוט לשימוש. יוצרים DataTable, שהיא כמו מערך דו-מימדי, ממלאים אותה ואומרים לגרף לצייר. הנה הקוד של הציור:



SearchMaster.prototype.drawGraph = function(dates) {
        // Create and populate the data table.
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Date');
        data.addColumn('number', 'All');
        data.addColumn('number', 'Happy');
        data.addColumn('number', 'Sad');
        data.addRows(dates.length);
        for (var i = 0; i < dates.length; ++i) {
                data.setCell(i, 0, dates[i].date);
                data.setCell(i, 1, dates[i].getAll());
                data.setCell(i, 2, dates[i].getHappy());
                data.setCell(i, 3, dates[i].getSad());
        }
      
        // Create and draw the visualization.
        $('graph').innerHTML = '';
        new google.visualization.LineChart($('graph')).
            draw(data, null);  
}




אז יש עוד כמה חלקים שלא פירטטי לגביהם, אחד זה איך יודעים כמה טוויטים חיוביים יש וכמה שליליים ושתיים, מה זה jsonp ואיך השתמשתי בו.



לגבי החיוביים והשליליים, בעצם על כל שאילתה של המשתמש אני שולח לטוויטר שלוש שאילתות: אחת נייטרלית, אחת חיובית ואחת שלילית. אם למשל השאילתה היא from:rantav אז למעשה נשלחות במקביל השאילתות הבאות:



from:rantav

from:rantav :)

from:rantav :(



וכאשר שלושתן חוזרות במלואן (כלומר כולל בקשות חוזרות עד שיש את כל הטוויטים בטווח התאריכים), רק אז אני מציג את הגרף.

זה לא מעט בזבזני כיוון שאני תמיד שולח לפחות שלוש שאילתות על כל אחת של המשתמש, ואף גרוע מזה, סיווג התוצאות הוא לא משהו בכלל. אבל בתור התחלה זה סביר הייתי אומר. אני רוצה לשפר את זה בהזדמנות הראשונה שתהיה לי.



בקשר ל jsonp, זו טכניקה לשליחת בקשות json בין דומיינים שונים ולשמחתי טוויטר תומך בה. למעשה כל הקוד שמממש את מה שמתואר למעלה כתוב ב javascript ורץ על הדפדפן, לא על השרת. מה שמרוויחים מזה זה שיפור ביצועים (ברוב המקרים) אבל חשוב יותר, אי-חסימה. מה זה אי-חסימה? טוויטר מגביל את מספר הבקשות שכל אחד יכול לבצע בדקה אז ככה שאם כל הבקשות של כל המשתמשים היו עוברות השרת אז מהר מאות הייתי מגיע למגבלה שלי. ככה, כאשר כל אחד שולח את הבקשות שלו ישירות לטוויטר אם הוא יגיע לחסימה, רק הוא ייחסם וגם יקח לו הרבה זמן עד שהוא ייחסם.

אז מה רע ב json? למה צריך להוסיף לו גם p? הסיבה היא שכאשר שולחים בקשה בין שני דומיינים שונים (דומיין המקור הוא twitgraph.appspot.com ודומיין היעד הוא search.twitter.com) אז יש מגבלת אבטחה שהדפדפן אוכף ובאופן כללי לא ניתן לשלוח בקשות XmlHttp בין שני דומיינים. גם שימוש ב iframe לא עוזר. אבל מה כן - ניתן להוסיף סקריפטים מכל מקום ומכל דומיין וברגע שמוסיפים סקריפט לחלק של ה head אז הדפדפן יריץ אותו, אפילו אם התוספת היא כבר זמן רב אחרי הטעינהֿ. התרגיל הוא כזה: במקום לשלוח בקשת XmlHttp מוסיפים סקריפט לדף והפרמטרים של הסקריפט הם השאילתה. הסקריפט הוא בעצם דינמי ונוצר על השרת בזמן הבקשה. מה שהסקריפט מכיל הוא קוד של javascript שבו פשוט קריאה לפונקציה בדף עם התוצאות של השאילתה. אז ברגע שהסקריפט חוזר הפונקציה לקראת ומקבלת את התשובה לשאילתה.

ויפה דוגמא אחת קודם:


$ curl "http://search.twitter.com/search.json?q=video+annotations&callback=myCallback"


myCallback({"results":[...}],...});


myCallback זו פונקציה על הדף שמקבלת את תוצאות השאילתא ברגע שהן מגיעות.

להלן הקוד שקורא ל jsonp ובעצם מוסיף קטע סקריפט באופן דינמי:


function jsonp(url, callbackName) {                
        url += '&callback=' + callbackName;
        var script = document.createElement("script");        
        script.setAttribute("src", url);
        script.setAttribute("type", "text/javascript");                
        document.body.appendChild(script);
}




אז בגדול אלו הדברים המעניינים. יש עוד הרבה קוד וכמו שציינתי הוא נמצא כאן ואם יש מעוניינים להצטרף למקצי השיפורים נא להשמיט כאן שורה (drop a line) או בטוויטר שלי rantav כי יש לי כבר הרבה מאוד רעיונות לשיפור.



פודקאסט מספר 8 - Debugger - ידידו הטוב של המפתח... או שלא?

בפודקאסט מספר 8 של רוורס עם פלטפורמה אירחנו בפעם השניה את יוסי גיל והפעם... הפתעה - איסור מוחלט על שימוש ב-DEBUGGER.
  • האם אפשר לחיות בלי Debuggers?
  • שיטת ה"דלות" - או -DALUT (תיעוד, התראות, לוגים, ובדיקות יחידה).
  • "קודם כל לחשוב" - טוב זה תמיד נכון.
  • String- בירושלמית זה "סדרית".
  • "לדבג" זה יותר מהיר או איטי?
  • Debugger- העיניים שמראות לנו את מקרי הקצה.
  • אספקטים של חיזוי זמן פיתוח.
  • חוויותיו של יוסי בשוחות הקוד.
  • לוגים - פסטיבל מספרי סיפורים של מה שקורה לקוד שלך בזמן אמת, אצל הלקוח.
  • MULTI-THREADING - דיבאגגינד בסביבה מרובת פתילים, או חוטים.
  • קריאת קוד מעמיקה של כמה אנשים יכולה למצוא באגים ממש קשים.
  • האם יש מקרים לגיטימיים להשתמש ב-Debugger?
  • חיפוש באגים כמו שמחפשים אריה במדבר.
  • Code Review - כלי נוסף לשפר איכות קוד ולעלות על באגים.
גלשנו בזמן כי היה לנו מאוד מעניין - אז קבלו את התנצלותנו על כך.
תודה על התגובות ואנחנו נשמח לקבל עוד תגובות. תודה גם לאריק על הפוסט.
הקובץ של הפרק הזה כאן
להשתמע.

19 בפבר׳ 2009

פודקאסט מספר 7 של רוורס עם פלטפורמה ראה אור זה עתה.
הפעם אספנו קצת גבב דברים על חידושי קוד.
  • ניצלנו את ההזדמנות לספר קצת על הפודקאסט שלנו (למי שלא מכיר)
  • הכל התחיל בהערה של דוד על הפודקאסט הקודם
  • התייחסנו בעיקר למאמר תרגום לפוסט של יואל ספולסקי.
  • דוגמאות לשכתוב קוד בעברנו או איך מעבירים אפליקציה - מווינייט - דרך פרל - ל ג'אווה.
  • מתי אפליקציה מתקרבת ל"קיר" ודורשת שכתוב.
  • תכנה מזדקנת? עוד נדבר על זה בהמשך.
  • "לזרוק ולכתוב מחדש" - למה??? זה עוד עובד!
  • תוכנות הביטוח כתובות ב- קובול - שנאמר... "קוד זה לא חברת ביטוח"
  • פרל וטוויטר - קוריוז.
  • פיתוח מונחה בדיקות - יכול (או לא) לעזור בשכתוב קוד.
נתנו את הסיומת הרגילה.
את הקובץ ניתן למצוא גם כאן
שבוע טוב והאזנה נעימה.... צ'או.

16 בפבר׳ 2009

דרושים לפודקאסט: מומחי ווב

אני ואורי רוצים לשדר פרק של הפודקאסט-תכנה שלנו, רוורסים, על פלטפורמות ווב. כל השמות הגדולים וההיסטוריים יהיו שם, החל מ פרל ו סי-גי-איי, דרך סטרטס וכלה ברובי הקטר המאושר ודג'נגו.
אבל אנחנו לא רוצים לעשות את זה לבד, אנחנו רוצים לשתף אתכם בשידור.
אז אם אתם מומחים לאחת מהפלטפורמות שבשימוש היום או שהיו פעם, או כל טכנולוגיית ווב אחרת שקשורה אז אתם מוזמנים לקחת חלק בשידור.
  • RoR
  • Django
  • Struts
  • ASP
  • ASP.NET
  • JSF
  • Hibernate
  • webwork
  • and more...

אנחנו רוצים לערוך מעין פאנל של מומחים שבו כל אחד יכול להציג את אחת מהפלטפורמות או אחת מהטכנולוגיות אותה הוא מכיר היטב ולהשוות ביניהן ולהבין מה היתרונות של כל אחת. אז אם אתם מומחים, או סתם מכירים די טוב, אתם ממש מוזמנים להשתתף.
את ההקלטה נעשה דרך שיחת ועידה של סקייפ, ככה שלא צריך לסוע הרבה. המועד טרם נקבע, אז מי שיהיה ראשון תהיה לו הכי הרבה השפעה. בגדול מדובר על מהלך השבועות הקרובים.

מי שמעוניין מוזמן לפנות אלי: רן [את] רוורסים.קום או אל אורי [את] רוורסים.קום
נשתמע

10 בפבר׳ 2009

פודקאסט מספר 6 של רוורס עם פלטפורמה

בפודקאסט מספר 6 דיברנו על עקרונות תכנה ויצירתיות של מתכנתים.
אירחנו את יוסי גיל - מרצה בטכניון וגוגלר אשר רוב הסטודנטים לתכנה בטכניון בוודאי מכירים בתור מרצה מחונן ובעל עניין רב.
יוסי חלק איתנו את עקרונות פיתוח התכנה שליקט והתמקדנו בעיקר בעקרון היצירתיות ומה שמסביבה.
  • מתכנתים הם בד"כ יצירתיים?!? - האמנם? מה טוב ומה רע בכך?
  • גוגלרים מעדיפים צפרדעים.
  • יצירתיות - כדי לבנות את מה שאתה צריך לא מה שאתה רוצה.
  • איך לובשים חולצות - עם או בלי כפתורים.
  • מתכנתים שעושים פיצ'רים במוצר רק כי אפשר.
  • מינימליזם - "פחות זה יותר". (פחות או יותר)
  • תרוצים שמתכנתים משתמשים בהם: כי זה יותר יפה, כי זה יותר קריא, כי זה "יותר מונחה עצמים..."
  • לגו או חימר? מה יותר אומנותי?
  • מתכנתים והערכות זמנים - "כי ככה".
  • עקרון השטויות - טאוטולוגיה או טעות-או-לוגיה.
  • יוסי סקר את שאר העקרונות כהכנה לשידורים העתידיים.
הקובץ נמצא כאן.
ואם אמרתי בשידור שהפיצ'ר הנסיוני של אאוטבריין לא עובד לי אז אני מתנצל - טעות שלי, הוא עובד פגז.

זהו - אנחנו מזמינים אתכם - אם יש לכם רעיונות לנושאים - תכתבו לנו.



8 בפבר׳ 2009

מילים אחרונות של מתכנתים


לא מזמן נתקלתי בשאלה "מה היו מילותיו האחרונות של מתכנת בשפה X" באתר stackoverflow וכיוון שכל כך נהנתי לקרוא את התשובות החלטתי למחזר כאן. ובכן:

מה יהיו מילותיו האחרונות של מתכנת C

main() { printf("goodbye, world"); }
מה יהיו מילותיו האחרונות של מתכנת Java

try{ ... }catch(Exception ignore){ //This won't happen }


מה יהיו מילותיו האחרונות של מתכנת perl
אני לא צריך לכתוב תעוד. הקוד כל כך יפה ומפורמט למופת שפשוט אפשר לקרוא אותו אחר כך

מה יהיו מילותיו האחרונות של מתכנת lisp
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((

מה יהיו מילותיו האחרונות של מתכנת PHP
*/

מה יהיו מילותיו האחרונות של מתכנת python שמשתמש ב vi
:%retab!


מה יהיו מילותיו האחרונות של מתכנת bash
rm -rf /

מה יהיו מילותיו האחרונות של מתכנת כלשהו
אצלי על המחשב זה עבד!


5 בפבר׳ 2009

פודקאסט מספר 5 של רוורס עם פלטפורמה

ככה בין המילואים הצלחנו להשחיל הקלטת פודקאסט אחת של רוורס עם פלטפורמה. קצת הארכנו והסליחה עם כל מי שממתין בחניה לסוף הפרק :)
השבוע נושא שקרוב לליבנו - ווידג'טים וגאדג'טים.
  • דיברנו על דפי בית אישיים כביתם הראשון של הגאדג'טים.
  • מיהם שרותי השרת של ה"חפיצים".
  • אורי סיפר על הווידג'ט של אאוטבריין.
  • מה לווידג'טים ולתפוצה ברשת?
  • SaaS, SOA הארכיטקטורה שמאחור.
  • ווידג'טים ואבטחה.
  • סקרנו את הטכנולוגיות סקריפטים פלאש AJAX וכו'.
  • עבודה בין אתרים - מה הבעיה ואיך פותרים.
  • JSON ואיך הוא עוזר לנו לפתור את הבעיה.
  • "האנשים בבסיסם הם טובים" - לא לפחד מווידג'טים.
  • "ווידג'טים מנומסים" - איך אאוטבריין שומרים על זה בקנאות.
  • ברגע האחרון נכנס סיפור קצר על prototype.js .
כתבו לנו הערות והצעות לסדר והכי חשוב לתכנים שאתם רוצים שנדבר עליהם.
קובץ השמע נמצא כאן.
להתראות.

30 בינו׳ 2009

דא פיירפוקס

ברוח הבחירות הממשמשות ובאות מצאתי את הבאנר המשעשע הזה. תודה לתומר.
האמת היא שאני משתמש יותר בספארי, אבל אתם מבינים את העיקרון - דפדפן מרדני כלשהו ורצוי שעובד גם על מק

22 בינו׳ 2009

פודקאסט מספר 4 של רוורס עם פלטפורמה

בפודקאסט מספר 4 של רוורס עם פלטפורמה יש לנו אורח - פרנק סמדג'ה.
ביחד עם פרנק דיברנו על אנשי תכנה.
סיפרנו, כל אחד, על איך הוא התחיל את כל סיפור התכנה שלו.
סיפורי האימה של פרנק וה- EMACS .
אורי והמפתח של המסופים בקיבוץ.
רן והסינקלר. או... מזיפ ועד... ZIP .
פרנק סיפר על שיטת סמדג'ה לסיווג אנשי תכנה. מרוב עצים לא רואים את היער.
אנשי תכנה וניהול - מי מתאים למה.
איך אנחנו בתור מנהלים בעולם התכנה.
דיברנו על אנשי תכנה בעיתות משבר - כמו המשבר הנכחי.
הזכרנו את האנשים ש"נושמים תכנה".

לצערנו יש לנו בעיות עם שירות שמירת קבצי השמע ולכן העלינו אותו למקום זמני אחר. אם אתם מכירים שירות טוב לאיכסון הקבצים - תזרקו איזה טיפ.

דבר נוסף. את הפודקאסט אנחנו מקליטים לטובתם של כלל "אנשי התכנה העבריים" - אם אתם בלוגרים, נשמח אם תפיצו את השמועה שיש פודקאסט כזה ואם אתם נהנים ממנו אז גם המלצה תתקבל בברכה :)

תודה לפרנק - היה כיף ולהתראות בפעם הבאה.

15 בינו׳ 2009

פודקאסט מספר 3 של רוורס עם פלטפורמה

פודקאסט 3 של רוורס עם פלטפורמה יצא לאור. קובץ השמע כאן.
הנושא להפעם היה "הלקוח הרזה" (Thin Client) והקאמבק שלו לחיינו. חילקנו תפקידים: אני דיברתי בשבחו של הלקוח הרזה ואורי היה קצת סנגורו של השטן.
דיברנו קצת על חייו הראשונים של ה- (Thin Client) ולמה נעלם מנוף חיינו.
דיברנו על שובו בתור ישומים אינטרנטיים שונים.
מה המגבלות ולמה הוא כנראה לו זוכה לאותה עדנה כמו בימיו הקודמים.
צד נוסף שעליו דיברנו היה "הלקוח הרזה והירוק" (מן סוג של סלט חסה) או השפעות ארכיטקטורה כזו על צריכת משאבים ופחות זיהומים סביבתיים.

בסופו של דבר קינחנו באתנחתא קומית בנוסח: לו שפות תכנות היו דתות.

מקווים שתהנו - אנחנו נהנינו

10 בינו׳ 2009

איך כותבים קוד כשאין debugger

אני זוכר איך זרחו עיני בפעם הראשונה שפתחתי את הדיבגר (יש לזה מלה בעברית?) של בורלנד turbo-c וחוויתי את מה שהיה נדמה לי בזמנו כחוויה מיסטית. לראשונה בחיי יכלתי לראות למשתנים המקומיים שלי ישר בלבן של העיניים, יכלתי לבדוק את הערכים שלהם, לשנות את הערכים שלהם, והייתי בעננים! ולא רק משתנים מקומיים, כי אם גם משתנים גלובליים, רחמנא ליצלן. ולא רק משתנים - יכלתי גם לעשות single-step ואפילו break-point. מדהים!!! לא עוד טבלאות עם משתנים והרצות של התכנית על יבש עם עדכון ערכים סזיפי, לא עוד מחקים ממוללים על שולחני, דור חדש של כלי פיתוח עמד על מפתני - דור הדיבגר!

מאז אותו רגע ועד היום מים רבים זרמו בקישון, turbo-c התחלף ב Borland C++ 3.0 אשר התחלף בבוא העת ב Visual Studio לגרסאותיו השונות, ומאוחר יותר לכלי יוניקס/לינוקס כדוגמת GDB.

ואז גם הגיעו ימי ה Java העליזים עם Net-beans, Idea, Eclipse ועוד ועוד וכל סביבה חדשה כזו באה עם עושר נוסף של יכולות להסתכל לקוד ישר בעיניים ולא לפחד.
אפשר לחזור אחורה בריצה, אפשר להסתכל על כל חוט (thread) בנפרד, אפשר לעקוב אחרי ערכים של משתנה אחד ספציפי, ליצור break-point עם תנאים שונים, לדבג תהליך מרוחק שנמצא אולי ביבשת אחרת, ועוד ועוד ועוד - ממש לונה-פארק למתכנתים.

וכמו בכל הסרטים עם מוסר ההשכל, מתישהו האידיליה היתה צריכה להגמר, כמאמר הפרסומאים "מה עשינו שמגיע לנו כל הטוב הזה?". היתה תחושה שבכלל לא צריך לכתוב קוד טוב, בכלל לא צריך לחשוב על הקוד, מספיק היה לשרבט איזה משהו שנראה שהוא נכון, שעובר קומפילציה, לפתוח דיבגר ואז ללמוד מה שהקוד שלי באמת הולך לעשות. ברצינות, זה נהיה כל כך קל לדבג, לתקן את הקוד תוך כדי הרצה, שפשוט כבר לא היה עוד טעם בלוודא שהקוד נכון לפני שמריצים אותו, לוודא שהאלגוריתם נכון לפני שמממשים אותו (שוב המילה הזו עם 3 הממים בתוכה). לא היו כרטיסיות נייר שהיה צריך לנקב, לא היו תורים לקומפיילר כמו בימי אבותינו, הכל היה כל כך קל, כל כך פשוט ליירט את הבאגים עד שנהייתי מפונק, נהייתי מושחת, לקחתי את כל הטוב הזה וסובבתי אותו נגדי. כי מה היה יוצא בסוף מתוכנית שלא חושבים עליה מספיק? אז נכון שאחרי כמה סשנים קצרים עם ידידי, משחיתי, הדיבגר, היא היתה מתחילה לעבוד, אבל תכנית כזו, השם ירחם, לא הייתי רוצה שתשלוט על הטייס האוטומטי במטוס שבו אני טס.

ואז באה הישועה ממקום בלתי צפוי. התחלתי לעבוד בשפה שאין לה דיבגר! התחלתי לכתוב ב actionscript2, שפה בעייתית מעוד הרבה סיבות אחרות, ובין השאר גם דיבגר אין לה. (ליתר דיוק יש, אבל א' הוא די פאתטי ו ב' אין מצב להשתמש בו בקונפיגורציה שבה אני עובד).
חצי שנה ראשונה קיללתי וקיטרתי - מי המציא את השפה המזעזעת הזו, למה הקומפיילר שלה כל כך מאעפן, ולמה לעזזל אין דיבגר?!
אחרי שלב הכעס בא שלב ההשלמה. הבנתי שאין דיבגר (וגם הקומפיילר לא משהו) אבל עם זה צריך להתמודד - ומאז יצאתי מחוזק.
אז איך כותבים קוד אם יודעים שאין דיבגר? איך חושבים עליו? איך משתכנעים שהוא רץ נכון אם לא רואים אותו צעד אחר צעד מתקדם בכיוון שייעדנו לו? שאלות אלה העסיקו אותי ולאט לאט גיליתי שאני משנה את הרגלי הקידוד שלי.
התחלתי לכתוב קוד כמו שצריך (טוב, אני מקווה...) להשקיע הרבה מאמץ במחשבה תחילה, לארגן את הקוד יפה יפה, לעשות תכנות דפנסיבי, כלומר אף פעם לא להניח כלום ותמיד לבדוק הכל ואולי החשוב מכל - לבדוק את האם-אמא של הקוד ע"י מימוש של עשרות או אולי מאות unit-tests. יצא שזמן כתיבת הבדיקות משתווה לזמן כתיבת הקוד האמיתי, ובמקרים מסויימים אני גם כותב את הבדיקות לפני המימוש (test driven development).

טוויסט נוסף בסיפור הגיע אחרי שלפני כחודשיים יצא לי לדבר עם אחד מעמיתי למשרד והסתבר לי שלמרבה הפתעתי שהוא מתנגד לשימוש בדיבגרים באופן עקרוני, ולמרות שהוא כותב בשפות שקיים להן דיבגר עוד משחר ההסטוריה הוא מתנגד באופן עקרוני לשימוש בהם. אני, שסבלתי כל כך מהמחסור בדיבגר ב as2 לא הצלחתי להבין איך הוא מוכן לוותר על כלי כל כך יעיל, ולא סתם מוכן - ממש מתנגד אליו באופן עקרוני וחושב שאף אחד לא צריך להשתמש בו. היתה לי תחושה שיש משהו בגישה הזו, אבל לא הצלחתי להבהיר לעצמי האם היא נכונה, או יותר נכון, להסביר לעמצי למה היא נכונה. אז קראתי לו לבירור ושאלתי אותו - מה זאת אומרת שאתה מתנגד לשימוש בדיבגר? והוא הסביר לי את כל התאוריה על רגל אחת. (תוספות ספרותיות - עלי - להגברת הדרמה)

הוא אמר לי - תראה - באגים יש לכולם, אין אחד שכותב בלי באגים, אבל איך ממשיכים משם זה כבר עניין של בחירה. כל דקה שאתה משקיע בלדבג את התכנית שלך היא דקה מבוזבזת, היא לא דקה מושקעת, או אולי במילים אחרות, היא השקעה בהווה, השקעה לטווח קצר, אבל לא השקעה לעתיד.
ופירש - יש באג? יופי! זה הזמן להפשיל שרוולים ולהתחיל לעבוד.

שלב א - קרא את הקוד שלך והבן אותו. רוב הבאגים נפתרים כך. אתה לא מבין את הקוד שלך? הקוד מסובך מידי? לא קריא? אבל אתה כתבת אותו (טוב, לא תמיד אתה, אבל לא חשוב, עכשיו אתה הבעלים שלו). אם ככה יש לך בעיות גדולות הרבה יותר מהבאג הבודד שנמצא זה עתה - יש לך קוד שאתה לא מבין. עבור לשלב ב.

שלב ב - חזור על הפעולת הבאות: עשה לקוד refactor לפונקציות קטנות יותר, למחלקות סגורות יותר ותעד את האם-אמא של מה שקורה. כעת חזור אל שלב א והבן את הקוד. עדיין לא מובן? חזור לשלב ב. זכור! אתה לא רק מתקן את הבאג הזה הנוכחי, אתה גם משקיע בעתיד טוב יותר, אתה משקיע בקוד יותר פשוט, קריא יותר, שבו יהיה קל ומהיר יותר לפתור באגים עתידיים. זו השקעה לטווח רחוק ואתה עוד תברך על הרגע הזה.

שלב ג - אם עוד לא עשית זאת קודם, זה הזמן לכתוב unit-tests. אין דבר טוב מזה. באמצעות unit-test אתה לא רק תמצא את הבאג הזה באופן אוטומטי, אתה גם תמצא באגים עתידיים באופן אוטומטי. זכור שעוד לא נולדה פיסת הקוד שנכתבה רק ע"י בן אדם אחד. גם אם היום אתה הוא היחידי שמתעסק בקוד שלך, אתה יכול להיות בטוח שבעתיד להקות של מתכנתים יעשו כמיטב יכולתם לשבור אותו על ימין ועל שמאל ואתה רוצה להגן עליו, להשאירו בחיים ולהגן על שמך הטוב. אתה לא רוצה להיות זה שאומרים עליו מאחורי הגב "הנה - הוא כתב את הקוד המצ'וקמק הזה שנשבר לנו על ימין ועל שמאל". בדיקות יחידה הן הדרך הטובה ביותר להשיג עמידות לאורך זמן.




אז זו התאוריה על רגל אחת - לקרוא, להבין, לפקטר ולבדוק. הגישה היא אולי סזיפית, אולי מעט מינימליסטית, אבל כמו הוראות הבטיחות הצהליות, היא נכתבה בהרבה דם ואין טעם לשפוך דם נוסף כדי להגיע אל אותן מסקנות (/יזע/דם/s). אם תסתמכו על דיבגר תמצאו את עצמכם מכבים שריפות כל היום. אם אתם רוצים לבנות תכנה יציבה ולאורך זמן כדאי להפסיק ולהתפנק, קצת משמעת עצמית ולשכוך מהשטן בלבוש המלאך.

ואמרו אמן.

7 בינו׳ 2009

פודקאסט מספר 2 של רוורס עם פלטפורמה

אורי ואני הקלטנו אתמול את פודקאסט מספר 2 של רוורס עם פלטפורמה (www.reversim.com)
היה מאוד כיף והזמן רץ לו. תכננו לדבר על מספר נושאים ובסופו של דבר המשכנו רק את הנושא מהפודקאסט הקודם, קוד פתוח, ואת שאר הנושאים דחינו לשבוע הבא. יש הרבה על מה לדבר והחלטנו להגביל את עצמנו לחצי שעה בדיוק.
אז מה היה לנו? פיל אחד חמוד (HDOOP), שלושת אבות האומה: MapReduce, BigTable, GFS ועוד.
רסס ל איי-טונס (נשמע טוב במבטא פולני) נמצא כאן. (ב iTunes הולכים ל Advanced -> Subscribe to Podcast)

האזנה נעימה ומוזמנים להשאיר הערות.

1 בינו׳ 2009

נמצא - הפודקאסט העברי הראשון

לפני שבועות מספר פירסמתי את הפוסט דרוש: הפודקאסט העברי הראשון שבו שאלתי איפוא אפשר למצוא פודקאסט ישראלי, בעברית על עולם התכנה והאינטרנט, משהו בסגנון stackoverflow או TalkCrunch רק בעברית ועל התעשייה בישראל.
כתגובה לפוסט קיבלתי כמה תגובות על פודקאסטים מעניינים וביניהם רציתי לציין לחיוב את הפודקאסט עושים הסטוריה עם רן לוי, אבל לצערי לא מצאתי את מבוקשי. לא מצאתי פודקסט ישראלי על עולם התכנה הישראלי.
בעקבות פוסט זה קיבלתי פניה מאורי להב - למה שלא נעשה פודקאסט משלנו?!!! אז ללא שהות (כמה שבועות...) הרמנו שנינו את הכפפה והתחלנו במרץ בבניית הפודקאסט הראשון שלנו: רוורס עם פלטפורמה!!!
בהזדמנות חגיגית זו אנו משיקים את השידור הראשון של הפודקאסט רוורס עם פלטפורמה (http://www.reversim.com) שבו אנו הולכים לדבר על עסקי התכנה - כלים, סביבות פיתוח, קוד פתוח, מסדי נתונים, שרותי אינטרנט וכו'. זה פודקאסט טכני שקהל היעד שלו הוא בעיקר מפתחי תכנה. רוב הזמן נהיה רק שנינו לבדנו מדברים על רשימת נושאים שהוכנה מראש, פעם בשבוע, חצי שעה, אבל אנו גם נשמח לארח דוברים ומרואיינים חיצוניים. אם יש לכם משהו מעניין להגיד, אם אתם מומחים באיזשהו תחום ורוצים לתרום נשמח לשתף. אם יש לכם שאלות אתם מוזמנים לשלוח אלי (ran את reversim נקודה קום) או אל אורי (ori את reversim נקודה קום) או להשאיר הערות בבלוג זה או ברוורסים. ואם אתם רוצים לדעת מה מקור השם רוורס עם פלטפורמה כדאי שתשיגו לעצמכם איזה iPod ותתחילו להאזין - שם כל הסודות נחשפים ;-)
אורי ואני מקווים שתהייה האזנה נעימה ונשמח לקבל תגובות.