<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>&#8235;try, catch, write - Ron Klein &#187; תכנות&#8236;</title>	<atom:link href="http://heblog.ronklein.co.il/category/%d7%aa%d7%9b%d7%a0%d7%95%d7%aa/feed/" rel="self" type="application/rss+xml" />
	<link>http://heblog.ronklein.co.il</link>
	<description>&#8235;הבלוג של רון קליין: תכנות, OOP, טכנולוגיה, Design Patterns, log4net ועוד עניינים&#8236;</description>	<lastBuildDate>Fri, 27 Jan 2012 06:22:14 +0000</lastBuildDate>
	<language>he</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>&#8235;Tapuz Meetup at Sela&#8236;</title>		<link>http://heblog.ronklein.co.il/2012/01/tapuz-meetup-at-sela/</link>
		<comments>http://heblog.ronklein.co.il/2012/01/tapuz-meetup-at-sela/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 06:22:14 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Meetup]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=928</guid>
		<description><![CDATA[&#8235;מדי פעם אנחנו יוזמים מפגש פורום. הפורום הוא כמובן פורום תכנות דוט נט בתפוז, המקום הכי פעיל למתכנתי דוט נט בעברית כיום. ו&#34;אנחנו&#34; זה משתתפי הפורום, או לפחות ה&#34;גרעין הקשה&#34; ביום שלישי, ה 24.1.2012, נערך מפגש פורום שכזה. מכללת סלע נתנה את החסות, שזה אומר מקום, נשנושים ופיצות (תכלס, אני שם בשביל הפיצות). נתחיל בתודה [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>מדי פעם אנחנו יוזמים מפגש פורום.</p>
<p>הפורום הוא כמובן <a href="http://www.tapuz.co.il/forums2008/forumPage.aspx?forumId=831">פורום תכנות דוט נט בתפוז</a>, המקום הכי פעיל למתכנתי דוט נט בעברית כיום.</p>
<p>ו&quot;אנחנו&quot; זה משתתפי הפורום, או לפחות ה&quot;גרעין הקשה&quot; <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>ביום שלישי, ה 24.1.2012, נערך מפגש פורום שכזה. מכללת סלע נתנה את החסות, שזה אומר מקום, נשנושים ופיצות (תכלס, אני שם בשביל הפיצות).</p>
<p>נתחיל בתודה גדולה ל<a href="http://blogs.microsoft.co.il/blogs/shlomo/">שלמה גולדברג</a>, הידוע גם בכינויו הרב דוט נט, או shlomo500 בפורום, שהיטיב לארגן את כל הסיפור.</p>
<p>נמשיך בתודה למכללת סלע, שכאמור, נתנה את החסות.</p>
<p>וכמובן, תודה למרצים: <a href="http://blogs.microsoft.co.il/blogs/idof/">עידו פלטו</a>, שהרצה על Fiddler, ו<a href="http://blogs.microsoft.co.il/blogs/gadim/">גדי מאיר</a>, שהרצה על Production Debugging. שתי ההרצאות היו מעולות.</p>
<p>הסשן שלי היה האחרון, ולכן היה יחסית קצר. יותר בכיוון של חומר למחשבה מאשר הרצאה טכנית.</p>
<p>הנושא שדברתי עליו היה מעבר מקוד פרוצדורלי ל Object Oriented.<br />לשמחתי האנשים שרדו יפה ולא נרדמו <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>ההרצאות הוקלטו והן זמינות ברשת (שוב תודה למכללת סלע!), <a href="http://scc.sela.co.il/SCC/Pages/ShowLecture/ShowLecture.aspx?lectureId=644">ההרצאה שלי</a> לקחה 28 דקות.</p>
<p>תוכלו להוריד את <a href="http://heblog.ronklein.co.il/wp-content/uploads/2012/01/proc-to-oop.zip">דוגמאות הקוד</a> ואת <a title="המצגת בפורמט pptx" href="http://heblog.ronklein.co.il/wp-content/uploads/2012/01/Code-from-Procedural-to-Object-Oriented.pptx.zip">המצגת עצמה</a>, שהמרתי גם ל slide-share:</p>
<div style="width:425px" id="__ss_11287106"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/kleinron/code-from-procedural-to-object-oriented" title="Code: from Procedural to Object Oriented">Code: from Procedural to Object Oriented</a></strong><object id="__sse11287106" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=code-fromproceduraltoobjectoriented-120126232458-phpapp02&#038;stripped_title=code-from-procedural-to-object-oriented&#038;userName=kleinron" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><param name="wmode" value="transparent"/><embed name="__sse11287106" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=code-fromproceduraltoobjectoriented-120126232458-phpapp02&#038;stripped_title=code-from-procedural-to-object-oriented&#038;userName=kleinron" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/kleinron">kleinron</a>.</div>
</div>
<p>האווירה במפגש היתה ממש טובה. היה נחמד לראות את האנשים שמאחורי הכינויים. חלק כבר הכרתי ממפגשים קודמים, וחלק רק מהמפגש האחרון.</p>
<p>בקיצור, Good Vibes, ואפילו בלי אלכוהול! נקווה שיהיו עוד מפגשים כאלה.</p>
<p>צ'ירס!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2012/01/tapuz-meetup-at-sela/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Web Developer position at WinBuyer&#8236;</title>		<link>http://heblog.ronklein.co.il/2012/01/web-developer-position-at-winbuyer/</link>
		<comments>http://heblog.ronklein.co.il/2012/01/web-developer-position-at-winbuyer/#comments</comments>
		<pubDate>Wed, 18 Jan 2012 10:02:14 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[job]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=922</guid>
		<description><![CDATA[&#8235;לחברת WinBuyer דרוש/ה מתכנת/ת Web חברת WinBuyer היא סטארט אפ בשלב מתקדם, והמוצרים שלה פונים לשוק ה Retailers. החברה ממוקמת בתל אביב. הערה: המודעה כתובה בלשון נקבה, אבל פונה לגברים ולנשים כאחד. דרישות מקצועיות לפחות שנתיים נסיון ב ASP.NET, עדיפות ל MVC לפחות שנתיים נסיון וידע ב HTML, CSS, JavaScript לפחות שנה נסיון בעבודה מול [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>לחברת WinBuyer דרוש/ה מתכנת/ת Web</p>
<p>חברת WinBuyer היא סטארט אפ בשלב מתקדם, והמוצרים שלה פונים לשוק ה Retailers. החברה ממוקמת בתל אביב.</p>
<p>הערה: המודעה כתובה בלשון נקבה, אבל פונה לגברים ולנשים כאחד.</p>
<p><strong>דרישות מקצועיות</strong><br />
לפחות שנתיים נסיון ב ASP.NET, עדיפות ל MVC<br />
לפחות שנתיים נסיון וידע ב HTML, CSS, JavaScript<br />
לפחות שנה נסיון בעבודה מול MS SQL Server<br />
חובה נסיון בתכנון (design) לפני כתיבת קוד<br />
יתרון משמעותי: נסיון ב Multi Threading<br />
יתרונות אחרים: נסיון ב jQuery, הבנה אמיתית של OOP, רקע ב WCF ו/או HTTP, נסיון ב Big Data, נסיון ב SilverLight, השכלה אקדמית.</p>
<p><strong>הגדרת התפקיד</strong><br />
מתכנתת בסביבת <span class="ron_english">ASP.NET + C#</span>, עם הבנה טובה ב Web, לעבודה בשני הצדדים: Client+Server.</p>
<p><strong>ברמה האישית</strong><br />
מישהי שרוצה להתפתח מקצועית, שרוצה להיות חלק מצוות, ועם תקשורת טובה. יוזמה אישית מתקבלת בברכה.</p>
<p><span style="font-size: medium;"><strong><span style="color: #333399;">מתאים לך? שלחי קורות חיים למייל jobs_rd2012a@winbuyer.com</span></strong></span><br />
נא <strong>לא</strong> לציין בקורות החיים: תאריך לידה, מצב משפחתי, שירות צבאי וכד'. אנו מעוניינים לקבל קורות חיים מקצועיים בלבד.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2012/01/web-developer-position-at-winbuyer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Patriq &#8211; MSMQ Routing Service&#8236;</title>		<link>http://heblog.ronklein.co.il/2012/01/patriq-msmq-routing-service/</link>
		<comments>http://heblog.ronklein.co.il/2012/01/patriq-msmq-routing-service/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 19:45:52 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[MSMQ]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[Patriq]]></category>
		<category><![CDATA[Routing]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=915</guid>
		<description><![CDATA[&#8235;ניר (מתי תפתח כבר בלוג) ואני מפתחים Pet Project בשם Patriq ב CodePlex. פטריק הוא סוג של Router אפליקטיבי במסגרת MSMQ. הקטע המאגניב הוא שיש שימוש ב IronPython כדי ליצור את חוקי ה Routing. כרגע הפרויקט בשלב ממש התחלתי, אבל בסך הכל &#8211; עובד! http://patriq.codeplex.com&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>ניר (מתי תפתח כבר בלוג) ואני מפתחים <a href="http://patriq.codeplex.com">Pet Project בשם Patriq</a> ב CodePlex.</p>
<p>פטריק הוא סוג של Router אפליקטיבי במסגרת MSMQ.</p>
<p>הקטע המאגניב הוא שיש שימוש ב IronPython כדי ליצור את חוקי ה Routing.</p>
<p>כרגע הפרויקט בשלב ממש התחלתי, אבל בסך הכל &#8211; עובד!</p>
<p><a href="http://patriq.codeplex.com">http://patriq.codeplex.com</a></p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2012/01/patriq-msmq-routing-service/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8235;About MSDN Forums &#8211; The Hebrew Version&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/12/about-msdn-forums-the-hebrew-version/</link>
		<comments>http://heblog.ronklein.co.il/2011/12/about-msdn-forums-the-hebrew-version/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 22:06:27 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Community]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=907</guid>
		<description><![CDATA[&#8235;אני בודק מדי פעם מה קורה בפורום דוט נט ב MSDN, בגירסתו העברית. אחרי הכל, נחמד לפעמים לראות שיש קהילה פעילה גם בשפה העברית. ויצא לי אפילו לענות על שאלה או שתיים שם. אתם מרגישים שעוד רגע מגיע ה&#34;אבל..&#34;? אז רגע לפני ה&#34;אבל&#34;, ממש לפני שהוא נדחף בדלת, אני אעצור ואכתוב עוד כמה מילים. אני [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>אני בודק מדי פעם מה קורה בפורום דוט נט ב MSDN, <a href="http://social.msdn.microsoft.com/Forums/he-IL/nethe/threads">בגירסתו העברית</a>.</p>
<p>אחרי הכל, נחמד לפעמים לראות שיש קהילה פעילה גם בשפה העברית. ויצא <a title="הפרופיל שלי במסדן" href="http://social.msdn.microsoft.com/Forums/he-IL/user/threads?user=%D7%A8%D7%95%D7%9F%20%D7%A7%D7%9C%D7%99%D7%99%D7%9F">לי</a> אפילו לענות על <a href="http://social.msdn.microsoft.com/Forums/he-IL/nethe/thread/f8d5d77e-b825-453c-9504-1b88604a08a1">שאלה</a> או <a href="http://social.msdn.microsoft.com/Forums/he-IL/nethe/thread/08fd2e56-6111-4a1d-a961-1c4443c2ec5f">שתיים</a> שם.</p>
<p>אתם מרגישים שעוד רגע מגיע ה&quot;אבל..&quot;?</p>
<p>אז רגע לפני ה&quot;אבל&quot;, ממש לפני שהוא נדחף בדלת, אני אעצור ואכתוב עוד כמה מילים.</p>
<p>אני לוקח חלק פעיל בקהילה של מתכנתים בכלל ומתכנתי דוט נט בפרט, ואני שמח לראות כל &quot;קורת גג&quot; וירטואלית (או פיזית, כפי שקורה במפגשי משתמשים) שמארחת את הקהילה.</p>
<p>&quot;קורות גג&quot; שכאלו הן רבות, וראוי לציין את אלו שהן בעברית, שם האתגר הוא כפול ומכופל: גם לשלב עברית ואנגלית, לתרגם מונחים טכניים, להוסיף קוד וליישר לשמאל (כולל מעברי BiDi), וגם מספר המשתתפים יחסית נמוך לעומת האלטרנטיבות.</p>
<p>לפיכך אין לי אלא להוריד את הכובע בפני כל מי שמשתתף, תורם, משקיע (זמן ו/או כסף) כדי שתהיינה &quot;קורות גג&quot; שכאלו.</p>
<p>ועכשיו, אחרי שהקדמתי וכתבתי את ההלל והשבח לאלו שלוקחים חלק במשימה של יצירת קהילת משתמשים בעברית, הנה זה בא:</p>
<h2>אבל&#8230;</h2>
<p>נבדוק לרגע את <a href="http://social.msdn.microsoft.com/Forums/he-IL/nethe/threads">הפורום של דוט נט בגירסה העברית של MSDN</a>.</p>
<p>נכנסתם? יפה.</p>
<p>הכל בסדר. באמת. ממשק משתמש סביר, יש שאלות, יש תשובות.</p>
<p>התנועה קצת דלילה לפעמים. יש תקופות של יובש קל, שיכולות לקחת גם שבוע.</p>
<p>טוב, לא נורא, קורה.</p>
<p>עד שצדה את עיני התנהגות קצת מוזרה. תסלחו לי על הקונספירציה, אבל נראה לי שמרוב שהתנועה דלילה, יש איזה משתמש dummy, שמייצר שאלות יחסית שטחיות, ויש מי שעונה. והכל כדי להשאיר את הפורומים האלה יחסית בחיים.</p>
<p>מה זה שאלות יחסית שטחיות? נניח, משהו כמו: מה זה connection string? מתי משתמשים בזה? &#8211; זו שאלה שטחית.</p>
<h2>מה מפריע לי בזה?</h2>
<p>קודם כל, זו רק תיאוריה, אין לי שום הוכחה, אז מי אני שאגיד משהו?</p>
<p>אבל בכל זאת, אם זה נכון, אז זה מרגיש שכאילו &quot;מריצים את המניות&quot;. מייצרים תחושת &quot;כאילו&quot;. וכשזה מספיק שקוף &#8211; זה מעצבן.</p>
<p>האלטרנטיבה היא או להציג את האמת הקשה במלוא תפארתה (פורום דליל), או לייצר תנועה ע&quot;י שאלות יזומות, אבל עם קצת יותר תחכום, רק כדי שאלה מאיתנו שרוצים לענות &#8211; ירגישו שהם באמת עוזרים למישהו עם בעיה אמיתית, ולא עם שאלה מומצאת.</p>
<h2>ולסיום &#8211; חידה</h2>
<p>נסו בעצמכם לבדוק מיהו ה dummy שאני מתייחס אליו (הנה <a href="http://social.msdn.microsoft.com/Forums/he-IL/nethe/threads">הלינק</a> שוב, לעצלנים). אתם מוזמנים לכתוב בהערות לפוסט את הניחוש שלכם.</p>
<p>וגם אם לא מצאתם, בטח למדתם משהו חדש מהסקירה הזו <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/12/about-msdn-forums-the-hebrew-version/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8235;תרמתי לויקיפדיה&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/11/%d7%aa%d7%a8%d7%9e%d7%aa%d7%99-%d7%9c%d7%95%d7%99%d7%a7%d7%99%d7%a4%d7%93%d7%99%d7%94/</link>
		<comments>http://heblog.ronklein.co.il/2011/11/%d7%aa%d7%a8%d7%9e%d7%aa%d7%99-%d7%9c%d7%95%d7%99%d7%a7%d7%99%d7%a4%d7%93%d7%99%d7%94/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 21:45:02 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Donation]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[stackoverflow.com]]></category>
		<category><![CDATA[Wikipedia]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=865</guid>
		<description><![CDATA[&#8235;כשהתחלתי להשתתף ב stackoverflow נתקלתי בשאלה הבאה (בתרגום שלי): פרויקטים של קוד פתוח חוסכים לנו הרבה זמן וכסף. למי הייתם תורמים 100 דולר מבין הפרויקטים של הקוד הפתוח? התשובה שלי היתה: אני משתמש בויקיפדיה על בסיס יומיומי במסגרת העבודה שלי. למרות שזה לא קוד פתוח, אני חושב שזה מועמד ראוי. אגב, חוץ מלקרוא ערכים, לעיתים [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>כשהתחלתי להשתתף ב <a title="A Few Words on StackOverflow.com" href="http://heblog.ronklein.co.il/2010/04/a-few-words-on-stackoverflow-com/">stackoverflow</a> נתקלתי <a title="Stackoverflow.com - Donations for open source tools" href="http://stackoverflow.com/q/129537/17772">בשאלה הבאה</a> (בתרגום שלי):</p>
<p><span style="background-color: #ffffff;"><strong>פרויקטים של קוד פתוח חוסכים לנו הרבה זמן וכסף. למי הייתם תורמים 100 דולר מבין הפרויקטים של הקוד הפתוח?</strong></span></p>
<p><a href="http://stackoverflow.com/questions/129537/donations-for-open-source-tools/277400#277400">התשובה שלי</a> היתה:</p>
<p><span style="background-color: #ffffff;"><strong>אני משתמש בויקיפדיה על בסיס יומיומי במסגרת העבודה שלי. למרות שזה לא קוד פתוח, אני חושב שזה מועמד ראוי.</strong></span></p>
<p>אגב, חוץ מלקרוא ערכים, לעיתים רחוקות אני גם מעדכן ומתקן ערכים שם. אז אפשר לומר שאני תורם מהידע שלי, <a title="ויקימילון - פילנתרופ" href="http://he.wiktionary.org/wiki/%D7%A4%D7%99%D7%9C%D7%A0%D7%AA%D7%A8%D7%95%D7%A4">פילנתרופ</a> שכמותי!</p>
<p>אבל היום&#8230; היום תרמתי כסף של ממש לויקיפדיה. אני מאמין שהם (כלומר, אנחנו) צריכים את הכסף הזה כדי להשאיר את ויקיפדיה נטולת פרסומות ונגישה לכל.<br />
למעשה ויקיפדיה בעיני זה אחד הפרויקטים המרגשים שקיימים כיום באינטרנט (גם אם הוא חורק קצת בפוליטיקה&#8230;).</p>
<p>צ'ירס!</p>
<p><a href="https://wikimediafoundation.org/wiki/Support_Wikipedia/en"><img src="//upload.wikimedia.org/wikipedia/commons/4/40/Fundraising_2009-micro-thanks-en.png" alt="Support Wikipedia" border="0" /></a></p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/11/%d7%aa%d7%a8%d7%9e%d7%aa%d7%99-%d7%9c%d7%95%d7%99%d7%a7%d7%99%d7%a4%d7%93%d7%99%d7%94/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8235;Don&#039;t enum Data&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/10/dont-enum-data/</link>
		<comments>http://heblog.ronklein.co.il/2011/10/dont-enum-data/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 21:37:46 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[enum]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[OCP]]></category>
		<category><![CDATA[Solid]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=769</guid>
		<description><![CDATA[&#8235;בפוסט הזה:
אני אראה איך קוד יכול להיות מעוצב ובנוי אחרת, כאשר רואים חלקים ממנו כ plugins.
אני אסביר את השינויים, את היתרונות והחסרונות, ואתחמק באלגנטיות משאלת מיליון הדולר: מה עדיף?&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>מכירים את enum?</p>
<p>-מכירים.</p>
<p>אז מתי כדאי להשתמש בו וליצור enum בקוד שלנו?</p>
<p>-הממממם&#8230; כשיש כמה קבועים מאותה &quot;קבוצה&quot;.</p>
<p>ופיסת הקוד הזו:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
public class Util
{
  public static void SaveAs(Image image, ImageFormat format, string path)
  {
    switch (format)
    {
      case ImageFormat.Bitmap:
        SaveAsBitmap(image, path);
        break;
      case ImageFormat.Jpeg:
        SaveAsJpeg(image, path);
        break;
      case ImageFormat.Png:
        SaveAsPng(image, path);
        break;
      default:
        throw new ApplicationException(
          string.Format(&quot;enum '{0}' changed&quot;, typeof (ImageFormat).FullName)
          );
    }
  }

  // implementations here...
}
</pre>
<p>נראית הגיונית?</p>
<p>-כן. נראה בסדר גמור.</p>
<p>טעות. הקוד הזה מפר את עקרון OCP, קיצור של <a href="http://en.wikipedia.org/wiki/Open/closed_principle" title="Open/closed principle - Wikipedia">Open/closed principle</a>.</p>
<p style="background-color: #e6e6fa; border-style: solid; border-width: thin; border-color: #000099; padding: 15px;"><strong>בפוסט הזה</strong>:<br />
אני אראה איך קוד יכול להיות מעוצב ובנוי אחרת, כאשר רואים חלקים ממנו כ plugins.<br />
אני אסביר את השינויים, את היתרונות והחסרונות, ואתחמק באלגנטיות משאלת מיליון הדולר: מה עדיף?<br />
קבצים: <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/10/silicate.zip">גירסה ראשונה</a>, <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/10/silicate-plugins.zip">גירסה שניה</a>.</p>
<p>לפני שנמשיך עם הדוגמה הקודמת, בואו נראה דוגמה אחרת, שבה ה enum הוא הגיוני, מוצדק, טבעי וכו':</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
using System;
namespace System.Data
{
  public enum ConnectionState
  {
    Closed = 0,
    Open = 1,
    Connecting = 2,
    Executing = 4,
    Fetching = 8,
    Broken = 16
  }
}
</pre>
<p>בא מי שתכנן את האובייקטים של <a href="http://msdn.microsoft.com/en-us/library/system.data.aspx" title="System.Data Namespace - MSDN">ADO.NET</a> ואמר: אלה המצבים היחידים האפשריים ל Connection. זה מה שיש, וזה מה שיהיה.<br />
למעשה, זאת הנחת עבודה מהותית. החלטה עקרונית שנמצאת ביסודות של הארכיטקטורה של ADO.NET. שינוי בהנחת העבודה הזו משמעותו, ככל הנראה, הנחת יסודות למערכת <strong>אחרת</strong>.</p>
<p>ועכשיו נחזור לדוגמה הראשונה. אם בעוד כמה חודשים נצטרך לתמוך בשמירת האובייקט Image לפורמט אחר, נניח לפורמט <a title="WebP - ויקיפדיה" href="http://en.wikipedia.org/wiki/WebP">WebP</a>, אז נצטרך להוסיף עוד ערך לקבוצת הערכים של ה enum שלנו. ולקמפל מחדש. ולבדוק בכל מיני מקומות מה ההשפעה של זה. וכו' וכו'. כמה שינויים בקוד בשביל להוסיף תמיכה בפורמט נוסף!</p>
<h2>למה זה קורה?</h2>
<p>בשורה התחתונה, זה קורה בגלל שעטפנו קבוצת ערכים ב enum, בזמן שהם למעשה נתונים &#8211; data. <strong>הם לא קבוצה סגורה וסופית</strong>. אולי עכשיו היא נראית סופית, אבל זה ממש לא בטוח. יתרה מזאת, הוספת ערך לקבוצה הזו <strong>לא</strong> תגרום להנחת יסודות למערכת אחרת.</p>
<p>בקיצור, יצרנו enum סביב data, וזו הטעות.</p>
<p>זאת טעות נפוצה מאוד. גם אני הייתי שם, בעיקר בגלל שזה נתן לי תחושה של type safety &#8211; יש לי השלמה אוטומטית של הויז'ואל סטודיו, יש Resharper שיכול לצעוק עלי שאני לא בודק את כל הערכים האפשריים &#8211; משמע אני לא יכול לטעות. זה אולי נכון במיקרו, אבל מרוב תחושה של &quot;הנה אני כותב קוד עם מינימום אפשרות לטעות&quot; &#8211; לא ראיתי את הטעות במאקרו.</p>
<h2>איך בכל זאת כדאי לעצב ולכתוב קוד עם רעיון דומה?</h2>
<p>הרעיון המרכזי הוא לראות שהקוד הזה יכול להיות מורכב משילוב של plugins, כאשר לכולם אותו <a title="מנשקים לפנים - בבלוג הזה" href="http://heblog.ronklein.co.il/2011/02/interface-in-your-face/">ממשק</a> (חוזה) אבל כל אחד מהם מממש אותו בצורה שונה.</p>
<p>בדוגמה שלנו, הממשק הוא כזה ששומר תמונה לדיסק:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
using System.Drawing;

namespace Silicate.Lib
{
  public interface IImagePersister
  {
    void SaveAs(Image image, string path);
  }
}
</pre>
<p>וכל מימוש יוכל לכתוב את הקובץ בפורמט אחר. ניקח לדוגמה מימוש של png:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
using System.Drawing;

namespace Silicate.Lib
{
  public class PngPersister : IImagePersister
  {
    public void SaveAs(Image image, string path)
    {
      image.Save(path, System.Drawing.Imaging.ImageFormat.Png);
    }
  }
}
</pre>
<p>ובאותו אופן נוכל לממש עבור כל פורמט שנרצה, כולל WebP, שלא נתמך בפריימוורק.</p>
<h2>אוקיי, אבל איך הכל מתחבר ביחד?</h2>
<p>הרעיון המרכזי הוא לוותר על ה switch, כי אז הוספה (או גריעה) של פורמט לשמירת תמונה תגרום לקימפול מחדש. במקום ערכים של enum נעבוד עם <strong>string</strong>, שיכול להחזיק ערכים בצורה גמישה יותר. האלטרנטיבה ל switch היא לטעון באופן <strong>דינמי</strong> את ה plugin הרלוונטי ולהשתמש בו. טעינה דינמית שכזו יכולה להתבצע ע&quot;י Reflection, או ע&quot;י <a title="IoC Container Explained - בבלוג הזה" href="http://heblog.ronklein.co.il/2011/07/ioc-container-explained/">IoC Container</a> (ובקיצור IoCC). אני אראה בפוסט הזה את הדרך של IoCC. אם מישהו יבקש (נניח בהערות לפוסט) &#8211; אז אני אוסיף גם קוד שמדגים ע&quot;י Reflection.</p>
<p>נסכם את המהלך בטבלה קטנה ואז נמשיך:</p>
<table class="ron_heb_table" style="border-color: #000000; border-width: 1pt; background-color: #e6e6fa; width: 500px; border-style: solid;">
<tbody>
<tr>
<td></td>
<td>לפני</td>
<td>אחרי</td>
</tr>
<tr>
<td>סוג המזהה</td>
<td>ערך מתוך enum</td>
<td>string</td>
</tr>
<tr>
<td>סוג הטעינה</td>
<td>סטטית ע&quot;י switch + new</td>
<td>דינמית ע&quot;י Reflection או IoCC</td>
</tr>
<tr>
<td>הרחבה גורמת ל&#8230;</td>
<td>שינויים בקוד + rebuild <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </td>
<td>שינויים בקונפיגורציה בלבד <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </td>
</tr>
</tbody>
</table>
<h2>נחבר את הכל עם Unity</h2>
<p>ה IoCC שאדגים באמצעותו את השינויים בקוד הוא <a title="patterns &amp; practices - Unity" href="http://unity.codeplex.com">Unity</a>. קודם כל &#8211; הקונפיגורציה:</p>
<pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;unity&gt;
  &lt;namespace name=&quot;Silicate.Lib&quot; /&gt;
  &lt;assembly name=&quot;Silicate.Lib&quot; /&gt;
  &lt;container&gt;
    &lt;register type=&quot;IImagePersister&quot; mapTo=&quot;BitmapPersister&quot; name=&quot;bitmap&quot; /&gt;
    &lt;register type=&quot;IImagePersister&quot; mapTo=&quot;JpegPersister&quot; name=&quot;jpeg&quot; /&gt;
    &lt;register type=&quot;IImagePersister&quot; mapTo=&quot;PngPersister&quot; name=&quot;png&quot; /&gt;
  &lt;/container&gt;
&lt;/unity&gt;
</pre>
<p>שימו לב שיש יותר ממימוש אחד לממשק IImagePersister, ולכן יש גם התייחסות לשם (או מזהה) של המימוש.</p>
<p>מרגע שהכל מקונפג כמו שצריך, נוכל לוותר על ה switch ולכתוב את הקוד באופן הבא:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
public class Util
{
  private static readonly UnityContainer Container = BuildContainer();

  private static UnityContainer BuildContainer()
  {
    var container = new UnityContainer();
    var section = (UnityConfigurationSection)
      ConfigurationManager.GetSection(&quot;unity&quot;);
    section.Configure(container);

    return container;
  }

  public static void SaveAs(Image image, string format, string path)
  {
    var persister = Container.Resolve&lt;IImagePersister&gt;(format.ToLowerInvariant());
    persister.SaveAs(image, path);
  }
}
</pre>
<p>בואו נעבור קצת על הקוד:</p>
<p>קודם כל, במקום פרמטר מסוג enum, אנחנו מקבלים פרמטר מסוג string. זה שינוי מהותי, כי string הוא ערך גמיש &#8211; אפשר להכניס בו כל טקסט שהוא.</p>
<p>שנית, ה string שקיבלנו מייצג את הפורמט הרצוי. כלומר, מי שקורא לפונקציה הזו &#8211; אמור לדעת בדיוק איך לרשום את הטקסט שמייצג את הפורמט הרצוי. למשל &quot;bitmap&quot; ולא &quot;bmp&quot;. זה מקשה קצת על מי שאמור להשתמש בקוד. זה אומר שהוא יצטרך לקרוא את התיעוד איפשהו.</p>
<p>עניין נוסף &#8211; מי שמבצע את הטעינה (בפועל) של המחלקה הרלוונטית הוא ה Unity. העברנו אליו את <strong>האחריות</strong> לבצע את זה. [אנחנו, ראש קטן אנחנו, כמה שפחות אחריות - יותר טוב <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ]</p>
<p>ועוד משהו: שימו לב כמה הקוד קצר וברור. זה אלגנטי, זה קריא, וקל לתחזק את זה.</p>
<p>יש מספר יתרונות וחסרונות בצורה שבה הקוד מעוצב כרגע. נתחיל מהחסרונות:</p>
<ul>
<li>מי שקורא לפונקציה הזו &#8211; אמור לדעת את הערכים האפשריים ל string הרלוונטי. זה פחות נוח מההשלמה האוטומטית של הערכים מתוך ה enum הקיים.</li>
<li>הכנסנו פנימה IoCC, וזה אומר שעכשיו יש לנו תלות ב DLLים נוספים, וכן בקונפיגורציה שלו.</li>
<li>נוספו קבצים לפרויקט: קובץ הממשק, וקבצי המימושים.</li>
</ul>
<p>ונעבור ליתרונות:</p>
<ul>
<li>המערכת שיש לנו ביד &#8211; פתוחה להרחבות, וללא צורך בשינוי כלשהו בקוד עצמו (וב rebuild שלו). כלומר, אנחנו עומדים בעקרון שנקרא OCP. אם יש לנו קבוצה של 10 פורמטים, ונרצה להוסיף את הפורמט ה 11 שנרצה לתמוך בו &#8211; אין שום בעיה.</li>
<li>הקוד שיש לנו קריא יותר, ולכן התחזוקה שלו קלה יותר.</li>
<li>במקרים אחרים (ואולי פחות בדוגמה הזו) &#8211; הקוד יותר טסטבילי, כלומר יותר מוכן לבדיקות.</li>
</ul>
<p>המסקנה היא שהמערכת, אחרי השינויים, היא יותר <strong>פתוחה להרחבות</strong>, אבל <strong>במחיר מסויים של נוחות</strong>. במילים אחרות: עכשיו קצת פחות נוח, אבל הרבה יותר גמיש וניתן להרחבה.</p>
<h2>ולשאלה המתבקשת&#8230;</h2>
<p><img class="alignright size-full wp-image-837" style="magin-left: 10px;" title="מיליון דולר?" src="http://heblog.ronklein.co.il/wp-content/uploads/2011/10/question-mark-flickr.jpg" alt="" width="75" height="75" />השאלה המתבקשת שעולה עכשיו, והיא שאלת מיליון הדולר: מתי כדאי להעדיף את הצורה הראשונה (enum+switch) ומתי נעדיף את הצורה השניה?</p>
<p>התשובה המתבקשת, וזו בד&quot;כ התשובה הטבעית לשאלות של מיליון דולר ומעלה:<br />
תלוי.</p>
<p>תלוי כמה הפרויקט גדול.</p>
<p>תלוי כמה מפתחים בוחשים בקדרה הזו.</p>
<p>ובעיקר: תלוי כמה OCP הוא עקרון שחשוב שיבוא לידי ביטוי בפרויקט.</p>
<p>בשורה התחתונה: לא חייבים. אבל, אם בעתיד הנראה לעין יש סיכוי סביר שמערכת תורחב, אז יכול להיות ששווה כבר מהרגעים הראשונים לעצב את המערכת ל plugins. צורת עבודה שכזו מובילה אותנו לקוד איכותי יותר גם ככה, וגם זו סיבה לא רעה.</p>
<p>עדכון לאלה ששרדו עד עכשיו: ממליץ לכם לקרוא את <a href="http://heblog.ronklein.co.il/2011/10/dont-enum-data/#comments">התגובות לפוסט</a>, שכנראה יכולות לחדד את העניין.</p>
<p>תכנות נעים!</p>
<p>קבצי הקוד: גירסה <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/10/silicate.zip">ראשונה</a> &#8211; עם enum וגירסה <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/10/silicate-plugins.zip">שניה</a> &#8211; בצורה של plugins.</p>
<p><span style="font-size: xx-small;">[התמונה מתוך אתר flickr, שם משתמש tj scenes, <a href="http://www.flickr.com/photos/uncut/16926192/">לינק ישיר לתמונה</a>, תחת רשיון CC BY 2.0]</span></p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/10/dont-enum-data/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>&#8235;WinBuyer is Hiring&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/08/winbuyer-is-hiring/</link>
		<comments>http://heblog.ronklein.co.il/2011/08/winbuyer-is-hiring/#comments</comments>
		<pubDate>Tue, 16 Aug 2011 10:22:22 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[job]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=816</guid>
		<description><![CDATA[&#8235;אני עובד בחברה שנקראת WinBuyer, ואנחנו מחפשים ראש צוות web. ההודעה מנוסחת בלשון נקבה, בשביל הכיף. התפקיד הוא של ניהול של שני מתכנתים, hands-on, כלומר צריך לכתוב קוד בחלק מהזמן. ברמת הטכנולוגיה מדובר על פיתוח web, שכולל את כל ההיבטים: client side &#8211; לדעת ולהבין JS ברמה טובה וכן jQuery (או כל פריימוורק אחר ב [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>אני עובד בחברה שנקראת WinBuyer, ואנחנו מחפשים ראש צוות web.<br />
ההודעה מנוסחת בלשון נקבה, בשביל הכיף.<br />
התפקיד הוא של ניהול של שני מתכנתים, hands-on, כלומר צריך לכתוב קוד בחלק מהזמן.<br />
ברמת הטכנולוגיה מדובר על פיתוח web, שכולל את כל ההיבטים:<br />
client side &#8211; לדעת ולהבין JS ברמה טובה וכן jQuery (או כל פריימוורק אחר ב JS), כולל Ajax<br />
לדעת ולהבין HTML+CSS<br />
server side &#8211; לדעת ולהבין ASP.NET עם <span class="ron_english">C#</span><br />
לדעת ולהבין אחסון נתונים ב MSSQL (עם או בלי שכבת ORM, לא עקרוני)</p>
<p>נדרש נסיון של שנתיים לפחות בניהול צוות בתחום.</p>
<p><strong>ברמה האישית</strong>:<br />
אנחנו מצפים למועמדת בעלת יכולת תקשורת טובה מאוד, שלצד הנסיון שלה תוכל ללמוד ולהתפתח גם בהיבט הניהולי וגם בהיבט הטכני.<br />
מישהי שתוכל גם לקחת אחריות וגם להיות קשובה לביקורת וללמוד מטעויות.<br />
מישהי שאוהבת את התחום ואת הצד הטכנולוגי באותה מידה (פחות או יותר..) כמו שהיא מעוניינת באתגרי ניהול.</p>
<p><strong>אז נסכם</strong>:<br />
ראש צוות web, שיודעת את העבודה, אוהבת את העבודה שלה, עם נסיון של שנתיים, ומשם כבר נתקדם.</p>
<p>מי שרוצה פרטים נוספים &#8211; שתשלח לי מייל לכתובת jobs.winbuyer@yahoo.com ואני אשלח לה דרישות תפקיד מלאות במסמך Word. אבל תכלס התמצית של הכל כבר כאן.<br />
אשמח לקבל קורות חיים במייל.</p>
<p>בהצלחה!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/08/winbuyer-is-hiring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;מפגש מתכנתי דוט נט&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/08/dot-net-developers-meetup/</link>
		<comments>http://heblog.ronklein.co.il/2011/08/dot-net-developers-meetup/#comments</comments>
		<pubDate>Sat, 06 Aug 2011 15:45:05 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Meetup]]></category>
		<category><![CDATA[Presentation]]></category>
		<category><![CDATA[Unit-Testing]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=808</guid>
		<description><![CDATA[&#8235;ב 2 באוגוסט, שזה לפני כמה ימים, היה מפגש מתכנתי דוט נט במכללת סלע. היה ממש כיף. נתחיל בתודה מתבקשת למכללת סלע, שארחה אותנו בצל קורתה וביד נדיבה: היו פיצות!! המפגש הזה נולד ביוזמה של משתתפי פורום תכנות דוט נט בתפוז. באופן אירוני משהו, היוזם העיקרי (שמזוהה בניק IamStalker ושמו האמיתי הוא גנַדי) נעדר מהמפגש [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>ב 2 באוגוסט, שזה לפני כמה ימים, היה מפגש מתכנתי דוט נט במכללת סלע. היה ממש כיף.</p>
<p>נתחיל בתודה מתבקשת למכללת סלע, שארחה אותנו בצל קורתה וביד נדיבה: היו פיצות!!</p>
<p>המפגש הזה נולד ביוזמה של משתתפי <a title="פורום תכנות דוט נט" href="http://www.tapuz.co.il/Forums2008/ForumMaavaron.aspx?ForumId=831">פורום תכנות דוט נט בתפוז</a>. באופן אירוני משהו, היוזם העיקרי (שמזוהה בניק IamStalker ושמו האמיתי הוא גנַדי) נעדר מהמפגש עצמו כי היה חולה <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> .</p>
<p>בכל מקרה, התחלנו את <a href="http://www.tapuz.co.il/Forums2008/ViewMsg.aspx?ForumId=831&amp;MessageId=154536422">המפגש</a> בסקרנות הרגילה של &quot;מי את/ה ומה הכינוי שלך בפורום?&quot; היו כאלה שהזדהו, היו כאלה שבחרו להישאר אנונימיים, והיו כאלה שבכלל לא הגיעו ישירות מהפורום אלא מ<a title="מתוך הקבוצה .NET Developers in Israel" href="http://www.linkedin.com/groupItem?view=&amp;gid=2513131&amp;type=member&amp;item=63994772&amp;qid=26926a80-8cdd-4acc-8ac9-973b898e837f&amp;trk=group_most_popular-0-b-ttl&amp;goback=.gmp_2513131">הודעה שפירסמתי</a> בלינקדין (&quot;הפרסום בלינקדין &#8211; עובד!&quot;)</p>
<p>סוף סוף ראיתי מי זה זיו, מנהל הפורום הנוכחי (כבר דברתי איתו בטלפון, אבל לא יצא לנו להיפגש ממש), שגם <a title="שרשור התמונות" href="http://www.tapuz.co.il/Forums2008/ViewMsg.aspx?ForumId=831&amp;MessageId=154580488">צילם אותנו</a> אוכלים פיצה בהפסקה.</p>
<p>בהתחלה <a href="http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/08/04/future-client-technologies-slides-and-demo-code.aspx">אלעד</a> העביר סשן מעניין על הטכנולוגיות של ה client בעיקר בקונטקסט של web: איפה אנחנו עומדים כיום ולאן מועדות פנינו בהקשר של SilverLight, JavaScript, <span class="ron_english">HTML(5)</span> ועוד. מעבר לחנופה צפויה ושגרתית, באמת היה מעניין. תודה, אלעד!</p>
<p>אחרי שאלעד סיים אני העברתי סשן בנושא Introduction to Unit Testing with NUnit. מעבר למבוא ולדוגמאות שהן סוג של Jump Start למי שרוצה להיכנס לתחום של Unit Testing, ניסיתי להעביר את המסרים הבאים:</p>
<ol>
<li>קוד שמכוסה ב Unit Testing הוא קוד שיחסית קל לשנות לו את המימוש. הבדיקות מוודאות שהפונקציונליות נשמרת למרות השינויים במימוש.</li>
<li>קוד שהוא לא טסטבילי, כלומר שלא ניתן לכתוב לו Unit Testing &#8211; הוא ברוב המקרים קוד שצריך לשפר אותו. כלומר, טסטביליות מובילה אותנו לקוד טוב יותר ו/או ל design טוב יותר.</li>
</ol>
<p>הנה המצגת שליוותה את הסשן שלי:</p>
<div style="width:425px" id="__ss_8785144"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/kleinron/unit-testing-with-nunit" title="Unit testing with NUnit" target="_blank">Unit testing with NUnit</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/8785144" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/kleinron" target="_blank">kleinron</a> </div>
</p></div>
<p>אפשר גם להוריד את <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/08/unit-testing-presentation.zip">הקובץ של המצגת</a> ואת <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/08/unit-testing-code.zip">הקוד</a> לדוגמאות (שימו לב שצריך רפרנסים ל NUnit, וזה לא חלק מההורדה).</p>
<p>תודה לכל מי שלקח חלק במפגש הזה, אני מקווה שיהיו עוד.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/08/dot-net-developers-meetup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;IoC Container Explained&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/07/ioc-container-explained/</link>
		<comments>http://heblog.ronklein.co.il/2011/07/ioc-container-explained/#comments</comments>
		<pubDate>Thu, 14 Jul 2011 02:44:30 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[Loose-Coupling]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=741</guid>
		<description><![CDATA[&#8235;בפוסט הזה אני רוצה להסביר את עיקרי הדברים סביב IoC, שזה ראשי תיבות של Inversion of Control. למעשה אני רוצה לספר מעט על התיאוריה ולהרחיב על הפרקטיקה. בקיצור, אני רוצה להסביר ולהדגים מה זה IoC Container. הנושא כולו די רחב, ואפשר להתעמק בו עוד ועוד, ועדיין ללמוד דברים חדשים. אני חושב שלמען ההגינות, כדאי מאוד [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>בפוסט הזה אני רוצה להסביר את עיקרי הדברים סביב IoC, שזה ראשי תיבות של Inversion of Control. למעשה אני רוצה לספר מעט על התיאוריה ולהרחיב על הפרקטיקה.</p>
<p>בקיצור, <strong>אני רוצה להסביר ולהדגים מה זה IoC Container</strong>.</p>
<p>הנושא כולו די רחב, ואפשר להתעמק בו עוד ועוד, ועדיין ללמוד דברים חדשים. אני חושב שלמען ההגינות, כדאי מאוד לקרוא מאמרים שמסבירים בצורה טובה את הקונספט של IoC Container ושל Dependency Inversion.</p>
<p>הנה קצת לינקים חיצוניים, שמסבירים (באנגלית, מן הסתם) את הנושא:</p>
<ul>
<li>אחד מהמאמרים המפורסמים ביותר בנושא הוא של Martin Fowler. <a href="http://bit.ly/fEPtda">המאמר</a> נקרא<br />
&quot;Inversion of Control Containers and the Dependency Injection pattern&quot;</li>
<li>בויקיפדיה אפשר למצוא את:
<ul>
<li>הערך <a href="http://en.wikipedia.org/wiki/Inversion_of_control">Inversion of control</a>,</li>
<li>שקשור גם לערך <a href="http://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency inversion principle</a></li>
</ul>
</li>
</ul>
<p>אחרי התיאוריה וההקדמות, בואו ניגש לעניין עצמו.</p>
<p>הפוסט הזה הוא המשך של פוסט קודם: <a href="http://heblog.ronklein.co.il/2011/02/interface-in-your-face/">&quot;מנשקים לפנים&quot;</a>. בפוסט ההוא, הסברתי את המשמעות של ממשקים, ואת היתרונות של תכנות מול ממשקים.</p>
<p>נרענן מעט את הזכרון. יש לנו מחלקה שנקראת CustomerReminder, והגענו בסופו של תהליך, לקוד הבא:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
namespace Canberra.InterfacesDemo.Lib
{
  public class CustomersReminder
  {
    public void Remind(ICustomersFetcher customersFetcher, IEmailSender emailSender)
    {
      foreach (var customer in customersFetcher.GetSleepingCustomers())
      {
        emailSender.SendRemindMessage(customer.FirstName,
		  customer.LastName,
		  customer.EmailAddress);
      }
    }
  }
}
</pre>
<p>השאלה שנותרה פתוחה היא: &quot;מי אמור לספק instance של מחלקות שמממשות ICustomerFetcher ו IEmailSender?&quot;</p>
<p>אפשרות אחת היא ליצור instance כחלק מהקוד עצמו, שקורא לפונקציה Remind. הקוד יראה כך:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
var customersReminder = new CustomersReminder();
customersReminder.Remind(new CustomersFetcher(), new EmailSender());
</pre>
<p>האפשרות הזו עובדת מצוין. עם זאת, יש כאן עניין שכדאי להתייחס אליו: הקומפילציה.</p>
<p>כדי שנוכל לקמפל ולבנות את הפרויקט שבו נמצאת המחלקה CustomerReminder, הפרויקט צריך להכיר את המחלקות המממשות את הממשקים המדוברים.</p>
<p>כלומר, אם כתבנו בפרויקט נפרד, שנקרא לו MyMail, את המחלקה EmailSender, שמממשת את IEmailSender, ונרצה להשתמש בה, אז אנחנו צריכים רפרנס לפרויקט MyMail. הרפרנס יכול להיות בצורה של רפרנס בין פרויקטים באותו solution, והרפרנס יכול להיות ל DLL של MyMail. זה לא משנה לצורך העניין.</p>
<p>מה שמשנה כאן הוא שיש <strong>תלות</strong> בין הפרויקט שלנו, לרפרנס של מימוש ספציפי של הממשק IEmailSender.</p>
<p>אם נרצה יום אחד להשתמש במימוש אחר לממשק IEmailSender, נצטרך לבנות מחדש את את הפרויקט שלנו.</p>
<p>בואו נבדוק לרגע מה זה אומר:</p>
<ul>
<li>לבנות מחדש פרויקט &#8211; Build</li>
<li>לבדוק שוב שהכל תקין &#8211; QA</li>
<li>להפיץ את התוצר לאן שצריך &#8211; Deploy</li>
</ul>
<p><strong>כל זה רק כי רצינו לשנות את המימוש של ממשק מסוים</strong>.<br />
זה לא מעט עבודה&#8230;</p>
<h2>אז מה האלטרנטיבה?</h2>
<p>הבעיה העיקרית שלנו היא איך להיפטר מהפעולה new בקוד שלנו.</p>
<p>נרצה להגיע לקוד שבו:</p>
<ul>
<li>אין את הפעולה new</li>
<li>אין התייסות בקוד עצמו או ברפרנסים של הפרויקט לאסמבלי שנרצה להשתמש בו</li>
</ul>
<p>ובמילים אחרות:</p>
<p><span style="color: #800080;"><strong>הבחירה באסמבלי שיממש את הממשק תהיה בקונפיגורציה</strong></span>.</p>
<p>כדי להגיע לזה בדוט נט, נוכל להשתמש במנגנון ה Reflection, שמאפשר לנו לטעון אסמבלי על סמך השם בלבד (טקסטואלי). השם הזה יכול להישמר בקונפיגורציה, ובא לציון גואל.</p>
<p>או שלא בא.</p>
<p>כי תכלס, להתחיל עם רפלקשן זה קצת מבאס, ומוציא את החשק לרוב המתכנתים (למרות שזה יכול לרגש מתכנתים אחרים).</p>
<p>אז במקום ש<strong>אנחנו</strong> נשבור את הראש כדי להשתמש ברפלקשן לעניין זה &#8211; נוכל להשתמש בפריימוורק ש<strong>אחרים</strong> כתבו, ושהם כבר שברו את הראש בשבילנו. לפריימוורק שכזה קוראים <em>IoC Container</em>.</p>
<h2>IoC Container</h2>
<p>IoC זה ראשי תיבות של Inversion of Control. לצערי IoC זה מושג שקשה עד בלתי אפשרי לתרגם אותו לעברית, ולכן אני אשאר איתו כמו שהוא. IoC Container זה איזשהו אמצעי/כלי/מיכל/קונטיינר/פריימוורק/ספריה לביצוע הפעולות של IoC. <strong>באופן כללי, זה אמצעי ליצור instance של מחלקה בלי שיהיה לה רפרנס בפרויקט</strong>.</p>
<p>בסביבת דוט נט יש מספר IoC Containers נפוצים. מתוכם אני שמח להזכיר את:</p>
<ul>
<li>Spring.NET</li>
<li>Castle Windsor</li>
<li>StructureMap</li>
<li>Autofac</li>
<li>Unity</li>
<li>Ninject</li>
</ul>
<p>וזו רשימה חלקית. מי שרוצה לראות השוואות בין הפריימוורקים מוזמן <a title="Google: ioc container .net comparison" href="http://www.google.co.il/?q=ioc+container+.net+comparison#hl=en&amp;source=hp&amp;biw=1440&amp;bih=805&amp;q=ioc+container+.net+comparison&amp;btnG=Google+Search&amp;oq=ioc+container+.net+comparison&amp;aq=f">לגגל</a> או להיכנס ל <a title="Stackoverflow: .NET IoC Container Comparisons" href="http://stackoverflow.com/questions/1140730/net-ioc-container-comparisons">stackoverflow</a> ולהמשיך משם.</p>
<p>באופן אישי יצא לי לעבוד עם Spring.NET, עם Ninject, עם StructureMap (כיום) ועם Unity (גם כיום; למעשה אנחנו בתהליך של החלפת SM ב Unity).</p>
<p>בואו נחזור לבעיה שלנו ונראה איך משתמשים ב <a title="Unity - hosted in CodePlex" href="http://unity.codeplex.com/">Unity</a> כדי לקבל instance של הממשק IEmailSender.</p>
<h2>הדגמה עם Unity</h2>
<p>קודם כל, צריך רפרנס מהפרויקט שלנו ל Unity. נוסיף. יש.</p>
<p>עכשיו, לפקודה עצמה. במקום הקוד הזה:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
var customersReminder = new CustomersReminder();
customersReminder.Remind(new CustomersFetcher(), new EmailSender());
</pre>
<p>נרשום כך:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
var container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection(&quot;unity&quot;);
section.Configure(container);

var customersReminder = new CustomersReminder();
customersReminder.Remind(new CustomersFetcher(), container.Resolve&lt;IEmailSender&gt;());
</pre>
<p>יפה. אבל לפני שאנחנו קופצים משמחה, איך תדע ה Unity להחזיר אובייקט כתוצאה מהשורה הזו?</p>
<p>-נצטרך לקנפג אותה כמובן.</p>
<p>נוכל להשתמש בקובץ ה config הסטנדרטי לצורך העניין. בואו נראה דוגמה:</p>
<pre class="brush: xml; gutter: false; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;section
		name=&quot;unity&quot;
		type=&quot;Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
			Microsoft.Practices.Unity.Configuration&quot;
	/&gt;
  &lt;/configSections&gt;
  &lt;unity&gt;
    &lt;typeAliases&gt;
      &lt;typeAlias
		alias=&quot;IEmailSender&quot;
		type=&quot;Canberra.InterfacesDemo.Lib.IEmailSender,
			Canberra.InterfacesDemo.Lib&quot;
	  /&gt;
      &lt;typeAlias
		alias=&quot;EmailSender&quot;
		type=&quot;MyMail.EmailSender, MyMail&quot;
	  /&gt;
    &lt;/typeAliases&gt;
    &lt;containers&gt;
      &lt;container&gt;
        &lt;types&gt;
          &lt;type type=&quot;IEmailSender&quot; mapTo=&quot;EmailSender&quot;/&gt;
        &lt;/types&gt;
      &lt;/container&gt;
    &lt;/containers&gt;
  &lt;/unity&gt;
&lt;/configuration&gt;
</pre>
<p>כלומר, אנחנו מגדירים ל Unity בדיוק באיזה מימוש להשתמש עבור הממשק IEmailSender.</p>
<p>בדוגמה הזו, כנגד הבקשה למימוש של IEmailSender, כלומר בקשת ה Resolve, ה Unity תחזיר לנו instance של המחלקה MyMail.EmailSender, שנמצאת באסמבלי MyMail.</p>
<p>כדי שזה באמת יקרה, קבצי ה dll של MyMail (וכל התלויות שלהם) צריכים להיות באותה תיקיה של ה exe של הפרויקט שלנו (או בתיקיית bin במקרה של web application).</p>
<p>זהו, <strong>עכשיו</strong> אפשר לקפוץ משמחה.</p>
<p>כדי להנות קצת יותר, במקרה של אפליקציית web, מומלץ לאתחל את ה Unity ב Application_Start שב global.asax, ולהגדיר משתנה סטאטי שתמיד נפנה אליו:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
using System;
using System.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace Canberra.InterfacesDemo.WebApp
{
  public class Global : System.Web.HttpApplication
  {
    public static UnityContainer Container;

    protected void Application_Start(object sender, EventArgs e)
    {
      Container = new UnityContainer();
      var section = (UnityConfigurationSection)ConfigurationManager
  		.GetSection(&quot;unity&quot;);
      section.Configure(Container);
    }
  }
}
</pre>
<p>וכך, הקוד שלנו שמשתמש ב Resolve של Unity יצטמצם באופן הבא:</p>
<pre class="brush: csharp; gutter: false; title: ; notranslate">
var customersReminder = new CustomersReminder();
customersReminder.Remind(new CustomersFetcher(),
    Global.Container.Resolve&lt;IEmailSender&gt;());
</pre>
<p>והשמחה רבה <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>אחרי ששמחנו ונהנינו, בואו נסכם את התהליך של שימוש ב IoC Container:</p>
<ul>
<li>מוסיפים רפרנס ל IoC Container עצמו</li>
<li>במקום new בקוד שלנו, משנים לתחליף שמציע ה IoC Container. בדוגמה שלנו עם Unity זה <span class="ron_english">Global.Container.Resolve&lt;IEmailSender&gt;()</span></li>
<li>מגדירים עבור ה IoC Container מה יהיה המימוש לכל interface שנרצה</li>
<li>מוודאים שכל קבצי האסמבלי והתלויות שלהם נמצאים בתיקיית ה bin של הפרויקט ה&quot;ראשי&quot;, אחרת מקבלים אקספשן&#8230;</li>
</ul>
<h3>עוד כמה מילים על IoC Container</h3>
<p>השימוש הבסיסי ביותר ל IoC Container (להלן IoCC) הוא ליצור instance של מחלקה לפי interface, או לפי כל type אחר. הרעיון המרכזי הוא להימנע מ new בקוד.</p>
<h4>קונפיגורציה &#8211; בקובץ או דרך קוד?</h4>
<p>הקונפיגורציה של ה IoCC יכולה להיות בקובץ חיצוני או בקוד עצמו. היתרונות של קובץ קונפיגורציה הם ברורים &#8211; לא צריך לבנות מחדש את האפליקציה וכו'. עם זאת, הקונפיגורציה יכולה להיות מעיקה וארוכה, ולכן יש לא מעט אנשים שמעדיפים לקנפג את ה IoC Container בקוד עצמו. למשל, מה שמציע Ninject זה קונפיגורציה רק דרך קוד. זה מאוד נקי, ואפשר להעביר לקונפיגורציה רק מה שצריך באמת.</p>
<h4>אתחול של אובייקטים מורכבים</h4>
<p>אם יש אובייקט שצריך לאתחל אותו עם פרמטרים בקונסטרקטור או דרך properties, אז אפשר לקנפג גם את זה. לא נכנסתי לזה כאן בפוסט, אבל זה בהחלט אפשרי ושכיח.</p>
<h4>IoCC as a Factory</h4>
<p>בפוסט הזה הראיתי איך בהינתן טיפוס של ממשק (IEmailSender) ה IoCC יכול לספק אובייקט. באופן כללי IoCC יכול לספק אובייקט גם על סמך טיפוס של מחלקה. בצורה הזו אמנם אנחנו מוותרים על הרעיון של הפרדה בין ממשק ומימוש שלו, אבל אנחנו עדיין נהנים מהאפשרות שה IoCC פשוט יהיה Factory נוח, מבלי שנצטרך לדעת איך מאתחלים מחלקה מסויימת.</p>
<h4>ועוד הרחבות</h4>
<p>IoCC נותן הרבה מעבר ליצירת אובייקטים פשוטה. אפשר למשל להגדיר שיצירת  אובייקט מסויים תהיה יחידה למשך כל חיי האפליקציה, ואז יש לנו סינגלטון דרך  ה IoCC. כלומר אין צורך להשתמש ב Singleton Design Pattern, ה IoCC עושה  את כל הסיפור הזה בשבילנו.</p>
<h2>לסיכום</h2>
<p>בפוסט הזה הראיתי איך אפשר להשתמש ב IoC Container (ובקיצור &#8211; IoCC).</p>
<p>הרעיון המרכזי &#8211; להעביר את הלוגיקה של איתחול של אובייקט מהקוד שלנו אל קובץ קונפיגורציה. במילים אחרות: השימוש ב IoCC מאפשר לנו להימנע מ new בקוד.</p>
<h3>למה זה טוב?</h3>
<p>-כי אז אפשר לבחור במימוש של ממשקים בלי להיות תלוי בקומפילציה מחדש. כלומר, אנחנו <strong>מקטינים את הצימוד ברמת הפרויקטים שלנו</strong>.</p>
<h3>למה זה לא טוב?</h3>
<p>-כי לפעמים זה מורכב מדי למתכנתים מתחילים;</p>
<p>-כי זה לא כל כך פשוט להרכיב את הפאזל הזה: גם לקנפג וגם לוודא שהקבצים יגיעו לתיקיית bin ונגזרותיה&#8230; קצת כאב ראש;</p>
<p>-באופן כללי, קצת קשה לעשות back-tracking לקוד ולהבין מה מתבצע בפועל</p>
<p>אבל הי, ככה זה שמקטינים צימוד, תפסיקו להתבכיין פה.</p>
<h3>ובשורה התחתונה, חייבים לעבוד ככה?</h3>
<p>לא, לא חייבים. אבל אני חושב שאחרי שמנסים קצת ורואים את היתרונות בפועל, זה הופך להיות ברור והגיוני יותר.</p>
<p>מעבר לזה, IoCC מתווה לנו את הדרך לכתיבת קוד שמחולק כראוי לחלקים שהם ניתנים להפרדה ולשינוי, והופך אותנו ממתכנתים &quot;סתם&quot; למהנדסי תוכנה.</p>
<p>&nbsp;</p>
<p>הקוד לפוסט הזה נמצא <a href="http://heblog.ronklein.co.il/wp-content/uploads/2011/07/iocc-example-unity.zip">כאן</a>.</p>
<p>הינדוס נעים!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/07/ioc-container-explained/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>&#8235;Regex מיתולוגי&#8236;</title>		<link>http://heblog.ronklein.co.il/2011/05/mythological-regex/</link>
		<comments>http://heblog.ronklein.co.il/2011/05/mythological-regex/#comments</comments>
		<pubDate>Wed, 04 May 2011 01:03:30 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Input-Validation]]></category>
		<category><![CDATA[Maintainability]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[Web-Forms]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=517</guid>
		<description><![CDATA[&#8235;מתי כדאי להשתמש ב Regex כדי לוודא קלט? מתי זה לא מומלץ? ואיפה עובר הגבול?&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>מתי כדאי להשתמש ב Regex כדי לוודא קלט?<br />
מתי זה לא מומלץ?<br />
ואיפה עובר הגבול?<br />
ואולי יש אלטרנטיבות?</p>
<h1>תור הזהב של ה Regex</h1>
<p>בשנים האחרונות יש הייפ משמעותי ל Regex (או בעברית, &quot;ביטוי רגולרי&quot;, אבל אני אשתמש ב&quot;רגקס&quot;), בעיקר סביב וידוא קלט. נראה לי שהסיבה העיקרית לזה היא שמיקרוסופט שיבצו מספר פקדים (Controls) לוידוא קלט כחלק ממערכת ה UI הבסיסית של ה WebForms כבר מויז'ואל סטודיו 2002 (או אולי 2003). הפקדים האלה הם די פשוטים ומוגבלים: הם יכולים לוודא שערך נמצא בטווח כלשהו, או שהוא קיים וכו'. רק שניים מהם נותנים אפשרויות מתקדמות: פקד CustomValidator, שמאפשר פונקציות בדיקה מוגדרות ע&quot;י המפתח עצמו (כחלק מהאפליקציה), ופקד RegularExpressionValidator, שמאפשר לבדוק מול רגקס את הקלט.</p>
<p>נוצר מצב שבו וידוא קלט שהוא יחסית פשוט &#8211; הפך להיות משימה קלה מאוד: רק לבחור את פקד וידוא הקלט המתאים מתוך אלה הקיימים, ולסגור עניין. עם זאת, וידוא של קלט מורכב יותר השאיר בידי המפתחים שתי אפשרויות: לכתוב פונקציות או לכתוב/למצוא רגקס מוכן.</p>
<p>מאוד מפתה העניין הזה של הרגקס, כי יש הרבה תבניות מוכנות ברשת, ולמצוא רגקס מוכן זה די קל. אתרים כמו <a title="RegexLib.com" href="http://www.regexlib.com">RegexLib</a> יצרו קהילה שלמה של מפתחי רגקס. מה גם שלפתח פונקציות זה קצת מבאס: מי רוצה לפתח פונקציה כשיש רגקס מוכן?!</p>
<p>בכל מקרה, פקדי וידוא הקלט הפכו להיות להיט היסטרי למפתחי WebForms, כי זה  סגר להם פינה קריטית של וידוא קלט, עם לוגיקה ברורה. עם הפופולריות של  WebForms ופקדי וידוא הקלט שם, עלתה גם הפופולריות של וידוא קלט ע&quot;י רגקס.</p>
<h1>דוגמה &#8211; כתובת מייל</h1>
<p>וידוא קלט של כתובת מייל, למשל, הפך להיות עניין יחסית פשוט, כי יש הרבה תבניות רגקס מוכנות רק בשביל זה. ויש הרבה תבניות מוכנות <strong>כי כתובת מייל היא עניין סטנדרטי</strong>, שמוגדר היטב במסמכי RFC של IETF (עוד על אימייל, מבנה הכתובת וכו' &#8211; <a title="ויקיפדיה - אימייל" href="http://en.wikipedia.org/wiki/E-mail_address">בויקיפדיה</a>). עם זאת, תבנית רגקס של וידוא כתובת מייל תקינה היא לא פשוטה להבנה. הנה דוגמה:</p>
<div class="codesnip-container" >
<div class="text codesnip">^((?&gt;[a-zA-Z\d!#$%&amp;'*+\-/=?^_`{|}~]+\x20*|&quot;((?=[\x01-\x7f])[^&quot;\\]|\\[\x01-\x7f])*&quot;\x20*)*(?&lt;angle&gt;&lt;))?((?!\.)(?&gt;\.?[a-zA-Z\d!#$%&amp;'*+\-/=?^_`{|}~]+)+|&quot;((?=[\x01-\x7f])[^&quot;\\]|\\[\x01-\x7f])*&quot;)@(((?!-)[a-zA-Z\d\-]+(?&lt;!-)\.)+[a-zA-Z]{2,}|\[(((?(?&lt;!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)&gt;)$</div>
</div>
<p>לא הכי נעים לקרוא את זה. האמת, נראה לי שצריך תואר ברגקס כדי להבין את התבנית הזו (מתוך האתר <a target="_blank" href="http://regexlib.com/REDetails.aspx?regexp_id=711">RegExLib.com</a>). אבל אם זה עובד, אז הבעיה פתורה וסגרנו עניין. (דגש על &quot;אם&quot;&#8230;)</p>
<h1>דוגמה נוספת &#8211; מספר טלפון בישראל</h1>
<p>העניינים מתחילים להסתבך כשאין סטנדרט לבדיקה. מספר טלפון בישראל, למשל, שמכיל קידומת ואת המספר עצמו. האם אנחנו מאפשרים רווח בין הקידומת למספר? האם אנחנו מאפשרים מקף בין הקידומת למספר? ואולי גם וגם? מכיוון שאין סטנדרט לזה, אנחנו יכולים לנסות את כוחנו ברגקס ולכתוב בעצמנו תבנית מתאימה. <a title="פורום תפוז - וידוא קלט" href="http://www.tapuz.co.il/Forums2008/ViewMsg.aspx?ForumId=831&amp;MessageId=142389469">בפורום תפוז</a>, למשל, הציע משתמש בשם IamStalker את התבנית הבאה לבדיקת טלפון:</p>
<div class="codesnip-container" >
<div class="text codesnip">^(([0]([2|3|4|8|9|72|73|74|76|77])))[2-9]\d{6,7}$</div>
</div>
<p>כאן הרגקס פחות מאיים, ואפילו נראה די מובן למי שיודע רגקס בסיסי. אבל התבנית הזו לא מאפשרת רווחים ומקפים: הקלט הבא (מספר הטלפון של &quot;לוח העיר&quot;, למי שתהה) לא יהיה תקין:</p>
<div class="codesnip-container" >
<div class="text codesnip">03 6382020</div>
</div>
<p>ועכשיו שאלה, בהצבעה בלבד בבקשה: מישהו <strong>יודע</strong> איך משנים את התבנית הזו כדי שהיא תתמוך גם ברווח אחד בין המספר לקידומת? או במקף? או ברצף של רווח-מקף-רווח (&quot; &#8211; &quot;)? אני לא שואל אם מישהו יודע <strong>בערך</strong>, והוא יכול לבדוק ע&quot;י ניסוי וטעיה &#8211; אני שואל על <strong>יודע-יודע</strong>.</p>
<p>אני מנחש שאין הרבה שבאמת יודעים איך לשנות את התבנית הזו כדי שתתמוך ברווח/מקף. הרוב פשוט לא מתעסק עם רגקס ביומיום.</p>
<h1>וידוא קלט בקוד</h1>
<p>בואו נבדוק את האלטרנטיבה: קוד <span class="ron_english">C#</span> שבודק תקינות טלפון בישראל, בדיוק כמו התבנית שכתובה למעלה (בלי תמיכה ברווחים, מקפים, ושאר עניינים).</p>
<div class="codesnip-container" >
<div class="csharp codesnip"><span class="kw1">namespace</span> Electron<span class="sy0">.</span><span class="me1">Validation</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">class</span> CharExt<br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">bool</span> IsDigit<span class="br0">&#40;</span><span class="kw1">this</span> <span class="kw4">char</span> c<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> c <span class="sy0">&gt;=</span> <span class="st0">'0'</span> <span class="sy0">&amp;&amp;</span> c <span class="sy0">&lt;=</span> <span class="st0">'9'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <br />
&nbsp; <span class="kw1">public</span> <span class="kw4">class</span> PhoneNumber<br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">bool</span> IsValid<span class="br0">&#40;</span><span class="kw4">string</span> s<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> <span class="sy0">==</span> s<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; var validPrefixes <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;02&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;03&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;04&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;08&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;09&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;072&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;073&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;074&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;076&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;077&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;050&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;052&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;054&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw4">int</span> prefixLength <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; var foundMatchingPrefix <span class="sy0">=</span> <span class="kw1">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span>var validPrefix <span class="kw1">in</span> validPrefixes<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s<span class="sy0">.</span><span class="me1">StartsWith</span><span class="br0">&#40;</span>validPrefix<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prefixLength <span class="sy0">=</span> validPrefix<span class="sy0">.</span><span class="me1">Length</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foundMatchingPrefix <span class="sy0">=</span> <span class="kw1">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>foundMatchingPrefix<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="co1">// remaining length should be between 6 and 7</span><br />
&nbsp; &nbsp; &nbsp; var remainingLength <span class="sy0">=</span> s<span class="sy0">.</span><span class="me1">Length</span> <span class="sy0">-</span> prefixLength<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="nu0">6</span> <span class="sy0">==</span> remainingLength<span class="br0">&#41;</span> <span class="sy0">||</span> <span class="br0">&#40;</span><span class="nu0">7</span> <span class="sy0">==</span> remainingLength<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="co1">// check the rest of the string to be digits</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i <span class="sy0">=</span> prefixLength<span class="sy0">;</span> i <span class="sy0">&lt;</span> s<span class="sy0">.</span><span class="me1">Length</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>s<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">.</span><span class="me1">IsDigit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>עכשיו נחזור לשאלה ששאלתי: מי <strong>יודע</strong> איך משנים את הקוד כדי שהוא יתמוך גם ברווח אחד בין המספר לקידומת? אני מנחש שכמעט כולם יכולים לשנות את הקוד שכתבתי כאן ו<strong>לדעת</strong> מראש, אפילו בלי להריץ, שזה יצליח. כי קוד <span class="ron_english">C#</span> הוא הרבה יותר יומיומי, וגם כי הוא הרבה יותר קריא. הנה הגירסה שלי לשינוי:</p>
<div class="codesnip-container" >
<div class="csharp codesnip"><span class="kw1">public</span> <span class="kw4">class</span> PhoneNumber<br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">bool</span> IsValid<span class="br0">&#40;</span><span class="kw4">string</span> s<span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> <span class="sy0">==</span> s<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; var validPrefixes <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;02&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;03&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;04&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;08&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;09&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;072&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;073&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;074&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;076&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;077&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;050&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;052&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;054&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> prefixLength <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; var foundMatchingPrefix <span class="sy0">=</span> <span class="kw1">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span>var validPrefix <span class="kw1">in</span> validPrefixes<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s<span class="sy0">.</span><span class="me1">StartsWith</span><span class="br0">&#40;</span>validPrefix<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; prefixLength <span class="sy0">=</span> validPrefix<span class="sy0">.</span><span class="me1">Length</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; foundMatchingPrefix <span class="sy0">=</span> <span class="kw1">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>foundMatchingPrefix<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s<span class="sy0">.</span><span class="me1">Length</span> <span class="sy0">==</span> prefixLength<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw4">int</span> nextDigitIndex<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s<span class="br0">&#91;</span>prefixLength<span class="br0">&#93;</span> <span class="sy0">==</span> <span class="st0">' '</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; nextDigitIndex <span class="sy0">=</span> prefixLength <span class="sy0">+</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; nextDigitIndex <span class="sy0">=</span> prefixLength<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="co1">// remaining length should be between 6 and 7</span><br />
&nbsp; &nbsp; var remainingLength <span class="sy0">=</span> s<span class="sy0">.</span><span class="me1">Length</span> <span class="sy0">-</span> nextDigitIndex<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="nu0">6</span> <span class="sy0">==</span> remainingLength<span class="br0">&#41;</span> <span class="sy0">||</span> <span class="br0">&#40;</span><span class="nu0">7</span> <span class="sy0">==</span> remainingLength<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="co1">// check the rest of the string to be digits</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i <span class="sy0">=</span> nextDigitIndex<span class="sy0">;</span> i <span class="sy0">&lt;</span> s<span class="sy0">.</span><span class="me1">Length</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>s<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">.</span><span class="me1">IsDigit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">true</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>מי שיעשה Diff על הקטע הרלוונטי יראה שהוספתי 7 שורות קוד, ושיניתי שתיים. זה שינוי קל, קריא, וברור. <strong>רואים את השינוי</strong>. מבינים את השינוי. וכל זה עוד בלי לפקטר החוצה את רשימת הקידומות ולהפוך אותן לפרמטר.</p>
<h2>קוד כפול</h2>
<p>האמת היא שאם אנחנו חוזרים להקשר של WebForms, אז צריך לכתוב קוד שיבצע את הוידוא הזה גם ב JavaScript. כך שמבחינת תחזוקת קוד, נצטרך לתחזק שתי פונקציות: אחת ב <span class="ron_english">C#</span> ואחת ב JavaScript, וזה חסרון עצום, כי אם הלוגיקה משתנה, צריך לשנות את הקוד בשני חלקים שונים לחלוטין של אותה המערכת, וקיימת האפשרות ששני צוותים שונים לגמרי ינהלו את החלקים האלה. לכן הפתרון של פקד רגקס הוא יותר נוח לתחזוקה, כי רגקס זו פעולה שהיא חלק מדוט נט (<span class="ron_english">C#</span> או vb.net או whatever.net) וגם חלק מ JavaScript.</p>
<h2>פתרון אפשרי: המרה אוטומטית</h2>
<p>בהקשר של WebForms, יש עוד אפשרות מעניינת: לכתוב קוד ב <span class="ron_english">C#</span> שיכול להיות מתורגם ל JavaScript. לדוגמה, לכתוב פונקציית וידוא קלט של מספר טלפון ב <span class="ron_english">C#</span>, ולקבל את הפונקציה השקולה לה ב JavaScript. יש כלי פיתוח שמיועדים לזה, אני מצאתי שניים:</p>
<p>1. <a title="SharpKit.net - home page" href="http://sharpkit.net" target="_blank">SharpKit</a>, שלמדתי להכיר אותו במפגש של ALT.NET. זה כלי מסחרי, עם תמחור משתנה (חינם לשימוש אישי). לדבריהם:</p>
<div class="codesnip-container" >
<div class="text codesnip">When you work with SharpKit, you write C# instead of JavaScript</div>
</div>
<p>מעניין.</p>
<p>2. <a target="_blank" href="http://projects.nikhilk.net/ScriptSharp"><span class="ron_english">Script#</span></a>, כלי שכבר קיים מספר שנים. העקרון די דומה. המימוש קצת שונה. </p>
<h1>אז מתי להשתמש ב Regex?</h1>
<p>באופן כללי, ההמלצה שלי היא להימנע מרגקס אם אפשר. אני אשתמש ברגקס כדי לודא קלט רק כאשר <strong>כל</strong> התנאים הבאים מתקיימים:</p>
<ol>
<li>הקלט סטנדרטי (כמו כתובת מייל או URL), או שאינו צפוי להשתנות גם בעתיד הרחוק</li>
<li>קל למצוא (או לכתוב) תבנית רגקס לקלט</li>
<li>הרגקס נותן מענה ביותר מסביבה אחת. למשל, אם הוא משותף גם ל client וגם ל server (כפי שמתקיים בפיתוח אפליקציות web)</li>
<li>ברור לי (ולצוות הפיתוח) שאם התבנית לא תקינה &#8211; מחליפים אותה באחרת ולא מנסים לדבג אותה</li>
</ol>
<p>סעיף 4 הוא סעיף מהותי: מכיוון שאני לא מתעסק עם רגקס ביומיום, אין טעם שאני אתחיל לדבג תבנית קיימת. זה לא הספציאליטה שלי, ואין לי יומרה כזו. אז אם מצאנו דוגמה לקלט תקין, שלפי תבנית הרגקס הוא נחשב ל&quot;לא תקין&quot;, <strong>אני זורק את התבנית הנוכחית ומתחיל לכתוב מחדש או מחפש תבנית אחרת</strong>. אם לא קיימת תבנית אחרת שכזו, או שקשה לפתח אותה מחדש, הרי שסעיף 2 לא מתקיים, ולכן הפתרון של רגקס לא מתאים.</p>
<h1>אלטרנטיבות &#8211; תוכנות עזר</h1>
<p>קיים מגוון של תוכנות שבונות תבניות רגקס, עם ממשק משתמש סביר וידידותי (האמת, הכל יותר ידידותי מהסינטקס של רגקס). המפורסמת מכולן היא <a title="RegexBuddy - homepage" href="http://www.regexbuddy.com" target="_blank">RegexBuddy</a>, ממנה אפשר רק להתרשם בתמונות מסך, ולא להתנסות (כנראה שיש יותר מדי כאלה ש&quot;מתנסים&quot; בתוכנה כבר כמה שנים טובות). מבין <a title="מתוך stackoverflow" href="http://stackoverflow.com/questions/132405/free-alternative-to-regxbuddy" target="_blank">האלטרנטיבות</a> <a href="http://alternativeto.net/desktop/regexbuddy/" target="_blank">ל RegexBuddy</a> מצאתי את <a title="Expresso - homepage" href="http://www.ultrapico.com/Expresso.htm" target="_blank">Expresso</a> (ויש עוד, כמובן). בדקתי, וזה נראה שאחרי &quot;תקופת למידה&quot; די קצרה &#8211; אפשר להגיע לתוצאה הרצויה.</p>
<p>העניין הוא שתוכנת עזר לבניית רגקס <strong>רק ממחישה את הבעייתיות של רגקס</strong>. היה מי שאמר/כתב את הדברים הבאים:</p>
<div class="codesnip-container" >
<div class="text codesnip">Some people, when confronted with a problem, think &quot;I know, I'll use regular expressions.&quot;<br />
Now they have two problems.</div>
</div>
<p>לא מספיק ברור <a href="http://regex.info/blog/2006-09-15/247" target="_blank">מי המקור לזה</a>, אבל זה יפה. אם היתה לי בעיה ואני מנסה לפתור אותה באמצעות רגקס, אז עכשיו יש לי שתי בעיות: זו המקורית ובעיה חדשה, של למצוא/לכתוב/לעדכן רגקס. תוכנת עזר רק ממירה את הבעיה החדשה למרחב אחר: עכשיו כדי לכתוב/לעדכן רגקס אני צריך להתקין תוכנה מיוחדת (אולי בתשלום), וללמוד לתפעל אותה.</p>
<h1>אלטרנטיבות &#8211; DSL</h1>
<p>למעשה הסינטקס של רגקס הוא די מכוער. אין לי שום עניין לתחזק גיבוב של  תווים שכוללים בקסלשים (\) ופייפים (|), עם דולר ($) וכובע (^)  בהתחלה/בסוף, ויש גם הרבה סוגריים מכל הסוגים. ואחרי כל זה, אני צריך להתפלל  שזה יעבוד. לו רק היה איזה כלי שיתן לי סינטקס נעים יותר לעבוד איתו, איזה <a title="Domain-specific language" href="http://en.wikipedia.org/wiki/Domain-specific_language">DSL</a> שיתן לי אבסטרקציה לכל הסיפור הזה, חיי היו הרבה יותר קלים.</p>
<p>עם תקווה בעיניים ובאצבעות רועדות, גיגלתי קצת <a title="Google Search: regex dsl" href="http://www.google.com/search?q=regex+dsl">regex dsl</a>, ועל פניו  נראה ש<a title="readable regular expressions" href="http://flimflan.com/blog/ReadableRegularExpressions.aspx" target="_blank">יש משהו שפיתח אחד בשם Joshua Flanagan</a>: הוא מציע DSL  די בסיסי שמחליף את הסינטקס של הרגקס. בדקתי ושיחקתי קצת, והצלחתי להגיע  למשהו לא רע. הנה קוד לבניית התבנית שבודקת תקינות של מספר טלפון בישראל,  לפני התוספת של רווחים ומקף:</p>
<div class="codesnip-container" >
<div class="csharp codesnip">Pattern phoneNumber <span class="sy0">=</span> Pattern<span class="sy0">.</span><span class="me1">With</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">AtBeginning</span><span class="sy0">.</span><span class="me1">Choice</span><span class="sy0">.</span><span class="me1">Either</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;02&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;03&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;04&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;08&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;09&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;072&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;073&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;074&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;076&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;077&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;050&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;052&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;054&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">Digit</span><span class="sy0">.</span><span class="me1">Repeat</span><span class="sy0">.</span><span class="me1">InRange</span><span class="br0">&#40;</span><span class="nu0">6</span>,<span class="nu0">7</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="me1">AtEnd</span><span class="sy0">;</span></div>
</div>
<p>והנה הקוד שמוודא טלפון בישראל עם אפשרות  לרווחים ולמקף בין הקידומת למספר עצמו:</p>
<div class="codesnip-container" >
<div class="csharp codesnip">Pattern phoneNumber <span class="sy0">=</span> Pattern<span class="sy0">.</span><span class="me1">With</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">AtBeginning</span><span class="sy0">.</span><span class="me1">Choice</span><span class="sy0">.</span><span class="me1">Either</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;02&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;03&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;04&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;08&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;09&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;072&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;073&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;074&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;076&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;077&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;050&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;052&quot;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; Pattern<span class="sy0">.</span><span class="me1">With</span><span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;054&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">WhiteSpace</span><span class="sy0">.</span><span class="me1">Repeat</span><span class="sy0">.</span><span class="me1">Optional</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">Literal</span><span class="br0">&#40;</span><span class="st0">&quot;-&quot;</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="me1">Repeat</span><span class="sy0">.</span><span class="me1">Optional</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">WhiteSpace</span><span class="sy0">.</span><span class="me1">Repeat</span><span class="sy0">.</span><span class="me1">Optional</span><br />
&nbsp; <span class="sy0">.</span><span class="me1">Digit</span><span class="sy0">.</span><span class="me1">Repeat</span><span class="sy0">.</span><span class="me1">InRange</span><span class="br0">&#40;</span><span class="nu0">6</span>,<span class="nu0">7</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="me1">AtEnd</span><span class="sy0">;</span></div>
</div>
<p>הקוד  הרבה יותר מובן, ולכן קל לתחזוקה ולשינוי. עם זאת, הסינטקס של ה DSL הזה  מורכב מדי לטעמי (או שפשוט צריך להתרגל אליו?). אגב, כדי להגיע לתוצאה הזו הוספתי מתודה <a title="מתודה  נוספת" href="http://pastebin.com/HiG0DA08" target="_blank">ושמתי ב pastebin</a>.<br />
בכל מקרה, אם אני מבין נכון, הפרויקט הזה של Flanagan, כפי הוא עצמו <a href="http://www.lostechies.com/blogs/joshuaflanagan/archive/2009/12/19/readable-regular-expressions-revisited.aspx" target="_blank">מסביר</a>,  הוא בגדר DSL נסיוני בלבד, והוא לא הפך את הנסיון הזה לפרויקט שיתופי,  ומעולם לא ניסה את הקוד בפרודקשן. חבל, דווקא יש לזה פוטנציאל.<br />
מי שדווקא כן המשיך עם הרעיון של Flanagan ולקח אותו לכיוון של <a href="http://weblogs.asp.net/rosherove/archive/2008/05/06/introducing-linq-to-regex.aspx" target="_blank">Linq  to Regex</a> הוא רועי אושרוב, מדטנט ידוע.</p>
<h1>אז מה נסגר?</h1>
<p>וידוא קלט זה עניין חשוב ומשמעותי, אבל חשוב גם להבין את ההשלכות של עבודה עם רגקס, ומעל הכל &#8211; להבין שזה לא קסם.</p>
<p>אני עדיין משתדל להתרחק מרגקס בהקשר של וידוא קלט, בעיקר כי קשה לי לקרוא ולתחזק רגקסים. (אגב, כדי למנוע אי-הבנות, לרגקס יש עוד תכונות כמו matches, והפוסט הזה בכלל לא מתייחס אל התכונות האלו.)</p>
<p>מתי אני ארצה לבצע וידוא קלט ברגקס? רק אם זה ממש פשוט. אני אישית מעדיף ללכת על האופציה של וידוא קלט בקוד, גם אם יש כאן סכנה לכפילות.</p>
<p>שימוש ב DSL כדי לוודא קלט (או כדי לבנות רגקס למטרה הזו) יכול להיות פתרון מעניין לכל הסוגיה, ובאמת מאפשר לבנות תבנית בצורה קריאה יותר. אבל כל עוד הוא לא עבר בדיקות מקיפות, לא הייתי לוקח אותו איתי לפרודקשן. עם זאת, אם אין ברירה וחייבים רגקס, יכול להיות שהקריאות של הקוד שווה את הסיכון (ומקסימום, נדבג תוך כדי תנועה).</p>
<p>ועד אז, עזבו אותי מוידוא קלט עם רג-אקס, מבחינתי זה די דרעק-אקס <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2011/05/mythological-regex/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

