כמה דברים שכדאי לדעת כשמתחילים פרוייקט חדש בReact Native

וודאי שמעתם על הפרימוורק היחסית חדש של פייסבוק: ReactJS שיודע להתקמפל גם לאפלקיציות נייטיב באנדרואיד וiOS. כנהוג במוצרים חדשים, הם לא ממש עובדים Out of the box. הנה מה שהייתי צריך לעשות כדי שזה יעבוד בקונפיגורציה של: מכונת פיתוח לינוקס (אובונטו), מכשיר אנדרואיד מחובר, וכרום שמשמש כדיבאגר (זה הכלי בברירת המחדל).

לאחר שהרצת את ההתקנה כך:

https://facebook.github.io/react-native/docs/getting-started.html

תתקלו במספר שגיאות. הדבר הראשון שצריך לעשות הוא ליצור קובץ בשם local.properties במיקום של הפרוייקט בmy_project/android. לקובץ הזה צריך להוסיף את השורה: sdk.dir=/path_to/Android/Sdk

לאחר שהרצתם בהצלחה sudo react-native run-android האפליקציה תופיע במכשיר. ניעור של המכשיר יקפיץ לכם תפריט מפתחים על המכשיר אך הפעלה של start remote debugging תכשל.

על מכונת הפיתוח יש לפתוח console חדש ולהריץ: sudo react-native start

כמו כן, בחלון נוסף יש להפעיל reverse proxy של הADB על מנת שהבקשות ינותבו למחשב ולכרום דיבאגר: adb reverse tcp:8081 tcp:8081

כעת פותחים דפדפן כרום. יש להכנס לכתובת: http://localhost:8081/debugger-ui

ולהכנס לתפריט המפתחים ולסמן את pause on exceptions:

עכשיו אפשר להתחיל לדבאג ולעבוד.http://localhost:8081/debugger-u

בהצלחה!

הצלת Amazon Cloud AWS EC2 Instance אם במקרה דפקת את ההרשאות

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

יש פתרון פשוט:

  1. עוצרים את המכונה ומנתקים את הVolume
  2. מקימים Instance חדש
  3. מחברים את הvolume של המכונה הבעייתית (שאותו ניתקנו) למכונה החדשה כvolume נוסף
  4. נכנסים בssh למכונה החדשה ועושים mount לvolume
  5. עכשיו אפשר להריץ עליו פקודות כמו למשל chmod ולהחזיר את המצב לקדמותו
  6. כשסיימתם, מנתקים את הvolume, מחברים אותו למכונה המקורית ואפשר למחוק את המוכנה החדשה ששימשה לתיקון

הוראות מדוייקות אפשר למצוא כאן:

http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html#TroubleshootingInstancesConnectingMindTerm

Build Version אוטומטי באמצעות Maven

רוצים שכל קומפילציה/Deploy תקדם את מספר הבילד? שתמיד יהיה מספר גרסה עדכני בכל בנייה של הקוד? הנה הדרך עם Maven.

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

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <version>1.4</version>
    <configuration>
        <revisionOnScmFailure>no.scm.config.in.pom</revisionOnScmFailure>
    </configuration>
    <executions>
        <execution>xml
            <id>create-timestamp-id</id>
            <phase>validate</phase>
            <goals>
                <goal>create-timestamp</goal>
            </goals>
            <configuration>
                <timestampFormat>yyyy.MM.dd.HH.mm</timestampFormat>
                <timestampPropertyName>buildNumber</timestampPropertyName>
            </configuration>
        </execution>
    </executions>
</plugin>

כעת ניצור את הקובץ שבו נרצה לשתול את המספר הבילד שאותו נציג באפליקציה. ניצור את /static/js/version.js בספריה הראשית של הweb של הפרוייקט.

בקובץ נשים את השורה הבאה:

var version = ‘1’;

כעת נשתמש בתוסף נוסף בשם replacer שיודע להחליף טקסט בקובץ לפי RegEx:

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.3</version>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <file>${project.build.resources[0].directory}/static/js/version.js</file>
        <replacements>
            <replacement>
                <token>(["'])(?:(?=(\\?))\2.)*?\1</token>
                <value>'${buildNumber}'</value>
            </replacement>
        </replacements>
    </configuration>
</plugin>

שימו לב שאנו משתמשים במשתנה buildNumber ובביטוי רגולרי שמשמעותו להחליף את הערך שבין הגרשיים הבודדים (‘’).

מדריך בזק לתכנות א-סינכרוני בnode.js

אחד היתרונות המובהקים של Node הוא השימוש הרב בפונקציות אסינכרוניות. זה אחד המאפיינים המאפשרים את המהירות והסקלאביליות של שפה זו. אסינכרוניות פותר את צוואר הבקבוק של מערכות רבות ובפרט מערכות web ושרתים: ההמתנה של Thread לפעולת I/O. למשל אם הרצתי שאילתה לDB ואני ממתין לתשובה זה יכול לקחת שניה, או 30 שניות. בזמן הזה הthread תפוס ומבזבז משאבי מערכת למרות שהוא לא עושה כלום (לא מבצע שום פעולה מלבד המתנה).
אמנם בתכנות "רגיל" אפשר ברוב השפות לכתוב קוד אסינכרוני אבל רבים לא טורחים לעשות זאת וספריות וAPI רבים לא תומכים בכך. Node מאלץ את המתכנת לכתוב אסינכרוני כיוון שהקוד רץ בthread אחד ואם תהליך כלשהו ימתין אז כל הפרוסס יהיה תקוע.

כתיבת קוד בסגנון אסינכרוני יכול להיות מבלבל ולא אינטואיטיבי. הבעיה העקרית היא שכמתכנתים אנו רגילים להסתכל על ביצוע שורות קוד לפי סדר כתיבתן. כלומר, שורה 3 תתבצע אחרי שורה 2 וכו’. בתכנות אסינכרוני בדומה לתסנות Multi Threaded המצב שונה.

האתגר הגדול הוא לוודא שהקוד שלנו רץ במקום הנכון ובזמן הנכון. בnod יש לנו 3 אפשרויות לטיפול בפונקציות אסינכרוניות ובפוסט זה ובפוסט הבא נעסוק בהן:
שימוש בפונקציית Callback
שימוש בpromise
שימוש בyield (כשיש תמיכה בES6)

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

db.insert(‘hello’, function(err,res){
	console.log(‘Completed inserting to DB’);
});

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

db.insert({str:‘hello’}, function(err,res){
	console.log(‘Completed inserting to DB’);
	var id = res._id;
	db.update({id:id, data:’aaa’}, function(err, res){
		http.send(‘http://server.com/’ + res, function(err,res){
			db.insert({id:id, response:res},function(err, res){
				console.log(‘Done!’);
			});
		});
	});
});

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

db.insert({str:‘hello’}, function(err,res){
	console.log(‘Completed inserting to DB’);
	var id = res._id;
	return db.update({id:id, data:’aaa’}).then(function(err, res){
		return http.send(‘http://server.com/’ + res).then(function(err,res){
			return db.insert({id:id, response:res}.then(function(err, res){

			});
		});
	});
}).then(function(res){	
	console.log(‘completed’);
});

בפוסט הבא נדבר עם yield עם EcmaScript 6 וכיצד ניתן לסנכרן קוד באמצעותו.

רקורסיה + תכנות אסינכרוני בNode.js

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

הנה דוגמה לסדרת פיבונאצ'י הידועה. מימוש רקורסיבי רגיל ולאחריו מימוש עם Promises.

אנחנו נשתמש בrouter של Express לצורך הדוגמה אבל כל אובייקט אחר יתאים גם:

var router = express.Router();

עכשיו לצורה הרקורסיבית הסטנדרטית:

router.fib = function(n) {
	if(n <= 2) {
		return 1;
	} else {
		return this.fib(n - 1) + this.fib(n - 2);
	}
};

והנה המימוש הרקורסיבי-אסינכרוני:

router.fibAsync = function(n) {
	return new Promise(function (resolve, reject) {
		if(n <= 2){
			resolve(1);
		}else{
			var sum = 0;
			router.fibAsync(n-1).then(function(res1){
				sum += res1;
				router.fibAsync(n-2).then(function(res2){
					sum += res2;
					resolve(sum);
				});
			});
		}
	});
};

כפי שניתן לראות המימוש משתמש בPromises והערכים המוחזרים הם הסכום שחוזר בthen של הpromise הרקורסיבי. הדבר היחיד שצריך לזכור בעבודה עם Promises הוא שהערך לא חוזר מהפונקציה כמו בכתיבה רגילה אלא בתוך הthen שהוא למעשה החלופה לCallback המסורבל. הפונקציה fibAsync בעצמה מחזירה Promise כך שיש לקרוא לה בצורה אסינכרונית עם then.

בפוסט הבא נלמד להריץ רקורסיה על עץ כשיש להפעיל לולאה על הבנים והכל כמובן… אסינכרוני!

הStack שלנו בשנתיים האחרונות MEAN – Node.js, Express, Angular.js, MongoDB

עבר זמן מאז כתבתי פה ודברים קצת התעדכנו. אז בשנתיים האחרונות החבילה המומלצת שלנו מתבססת על Node.js. מהיר, פשוט, קל להתקנה לתחזוקה ולדיבוג, הרבה פחות מסורבל לעומת ג'אווה ומאפשר תאימות וחלקי קוד משותפים בין השרת לקליינט. כמובן שJava עדיין מככבת בפרוייקטים שלנו, במיוחד בפרוייקטים הוותיקים וגם סתם אצל לקוחות שבוחרים לפתח בשפה זו אבל כשאנחנו נדרשים להקים מערכת מאפס ולבחור ארכיטקטורה node הוא בהחלט הבחירה שלנו. בפוסטים הבאים נעלה טיפים, רעיונות, פתרונות וPatterns לבעיות נפוצות.

פרידה מWindows ביי ביי Microsoft

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

התשובה פשוטה:

הwindows מגיע עם המחשב וקשה היום לקנות לפטופ נורמלי בלי ערכת הפעלה מותקנת מראש. זה נראה לי מטופש לזרוק 100 דולר לפח אז נשארתי עם מה שיש.

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

אז למה בכל זאת עברתי?

קודם כל, כי windows 8 כל כך מזעזעת, לא ידידותית ולא אינטואיטיבית שלא יכולתי לסבול את המחשבה לעבור אליה

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

לסיום: כמתכנת, העלות עלתה על התועלה. רוצה להתקין רובי? בהצלחה עם windows. פיתון? חצי מהספריות לא מתאימות במיוחד כל מה שקשור לסיסטם. להריץ דברים שכתבתי לרסברי פיי על חלונות? נו באמת .Hadoop? צריך מליון מעקפים שאפילו לא ניסיתי. לקמפל דברים עם GCC או להריץ דברים בCygwin ממש לא בא לי על windows.

גם להריץ VM ולהקריב את ביצועי המכונה אני לא רוצה מה גם שעם דיסק SSD אני מוגבל במקום הפנוי וכל MB הוא יקר.

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

למה אני עובר מג'אווה לRuby On Rails?

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

כי נמאס מהסירבול של Java

אני עובד בג'אווה, בונה אפליקציה יפה עם כמה מסכים. כמות הJars שאני צריך להביא, תהליך בניית האפליקציה (הWAR) והDeploy הארוך גוזלים זמן יקר בכל פעם שרוצים לשנות אפילו שדה אחד מסכן. זה מתחיל בבנייה ארוכה בMaven שתוצאתו קובץ ענק של עשרות MB, ואז צריך להעלות את הקובץ לשרת מה שיכול לקחת דקות ארוכות כשמדובר בCloud, מה שגורם לאתחול האפליקציה (עוד כמה דקות) ולבסוף לבדוק ולגלות ששוב צריך לשנות משהו. התהליך הזה בלתי נסבל. אמנם יש דרכים לעקוף את זה כמו העתקת קובץ JSP ישירות לשרת אבל זה עובד רק בתנאים מסויימים ובוודאי שזו לא דרך מומלצת.

כי האובייקטים בג'אווה הם Strong typed

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

כי ריבוי הפרימוורקים והשכבות מסבך את העבודה

נסו לחבר את Spring וHibernate. לא מסובך מאוד למי שיודע מה הוא עושה. נסו לחבר את זה לGWT, זה כבר כן מסובך כי אין דרך סטנדרטית. עכשיו בואו נגדיר שדה בHibernate, נשתמש בו בDAO (מוזרק דרך ספרינג, אלא מה?), שמתמפה לשדה בטופס GWT. זה כבר מצריך לא מעט עבודה. הטכנולוגיות כל כך רבות, השכבות השונות והחיבורים בינהם מויאים את החשק לפתח. כולם כותבים MVC אבל מה עם Model שמתחבר באופן טבעי לView שמדבר בצורה נורמלית עם הController?

בשביל פיתוח סטנדרטי, יותר מדי טכנולוגיות רק מזיקות

ג'אווה נהדרת. יש אינספור טכנולוגיות, פרימוורקים וספריות. אני יכול לאנדקס מסמכים בLucene, להריץ חישובים מבוזרים בHadoop, לשמור מידע בMySQL או בnoSQL או בGoogle App Engine או במליון דרכים אחרות. אבל בואו נודה בזה, חלק גדול מהאפליקציות דורשות פחות או יותר אותו דבר: קצת לוגיקה בשרת, UI משובח מבוסס JS וAJAX, ושמירת מידע בRDBMS. לא מדובר על מדע טילים ולא צריך אלף פרימוורוקים מתוחכמים בשביל זה. לכן אני מוותר על הגמישות והתשתיות של ג'אווה לטובת סטנדרט אחיד ופשוט, אינגרטיבי באופן מלא, קריא, קליל, מהיר ונוח.

אז מה עם ג'אווה בכל זאת?

Java בהחלט לא הולכת לפח. היא תשאר שפה חשובה וחזקה והטכנולוגיות הרבות שפותחו סביבה ימשיכו לשרת אחרים ואותי עוד שנים ארוכות. בהחלט אשקול פיתוח פרוייקטים בג'אווה במקרה הצורך אבל כשמדובר בפיתוח WEB פשוט, אני אבחר במשהו קליל ומהיר יותר וכרגע Ruby On Rails עונה בדיוק על הדרישות.

איך עובד oAuth 2.0? דוגמא מFacebook API

אתרים שונים מספקים API חיצוני על מנת לאפשר למפתחים לכתוב אפליקציות ותוכנות המתממשקות לאתר. הידועים שבהם: פייסבוק, גוגל, טוויטר וכו' מאפשרות למפתחים חיצוניים לגשת לפרופיל של המשתמש הרשום, לבצע פעולות בשמו, לקבל מידע, לבצע עדכונים וכו'. על מנת לנהל את ההתממשקות וההרשאות של משתמשי הAPI נעשה שימוש במנגנון אישור בשם oAuth. במאמר זה נסקור את הטכניקה הזו ואת היישום שלה בפועל בAPI של Facebook. נושא זה הכרחי כמעט לכל Facebook Application Developer ולמעשה לכל מי שרוצה לפתח אפליקצייה לפייסבוק או אתרים דומים (גוגל, טוויטר ועוד).

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

הדרך לפתרון שמציע oAuth עובד בצורה הבאה:

מפתחי האתר כותבים אפליקציית פייסבוק ריקה (ללא תוכן). באפליקציה זו מגדירים את הדברים הבאים:

  • אילו הרשאות האפליקציה מבקשת מהמשתמש? (צפייה, עדכון, וכו')
  • הדומיין של האתר mydomain.com

כשהמשתמש רוצה לאפשר לאתר שימוש בAPI, האתר מפעיל לינק בדפדפן במבנה הבא:

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream

הפעלת הלינק הזה על ידי הדפדפן (redirect פשוט) תעלה למשתמש את המסך כניסה לפייסבוק:

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

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

כעת פייסבוק יודע שהמשתמש אישר לאתר לבצע פעולות מסויימות.

במידה והמשתמש אישר את האפליקציה, פייסבוק יעשו redirect לכתובת שצויינה בבקשה המקורית (הועבר כפרמטר בURL). הURL שפייסבוק שולח יכלול פרמטר בשם code. עם הפרמטר הזה נפנה לפייסבוק על מנת לקבל את הaccess_token, שהוא הקוד הסופי שמאפשר קריאות API לפייסבוק.

https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE

פייסבוק יאשר את הקוד וישלח לכתובת שמצויינת בredirect_uri את התשובה: access_token שייראה בערך כך:

הקוד הזה ישמש אותנו לקריאות API. כל קריאת API (מבוססת REST) מאפשרת שירשור של הaccess_token כפרמטר. כך אנו יכולים לבצע קריאות לפייסבוק ופעולות על משתמש מסויים, לאחר שאישר אותנו מבלי לבקש פרטי משתמש. פייסבוק יאפשרו פעולות רק מתוך הדומיין שהוגדר באפליקציה כדי למנוע מצבים בסגנון cross site scripting. הaccess_token תקף למשך הזמן שהוגדר לו. אפשר גם ליצור token שאינו פג לעולם, תלוי בהגדרות.