<?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&#8236;</title>	<atom:link href="http://heblog.ronklein.co.il/feed/" rel="self" type="application/rss+xml" />
	<link>http://heblog.ronklein.co.il</link>
	<description>&#8235;הבלוג של רון קליין, תכנות, OOP ועוד עניינים&#8236;</description>	<lastBuildDate>Sat, 13 Mar 2010 23:18:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>he</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>&#8235;SMS Integration: Israel is wayyy behind US&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/03/sms-integration-israel-is-wayyy-behind-us/</link>
		<comments>http://heblog.ronklein.co.il/2010/03/sms-integration-israel-is-wayyy-behind-us/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 23:18:26 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[אינטגרציה]]></category>
		<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Integration]]></category>
		<category><![CDATA[SMS]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=323</guid>
		<description><![CDATA[&#8235;ספקי אינטגרציה לשליחת SMS מקומיים לעומת ספק אמריקאי - מי יותר טוב? ניחשתם נכון, בואו תבינו למה...&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>והפעם פוסט סביב אינטגרציה.</p>
<p>החלטנו להוסיף למוצר שלנו מערכת התראות ב SMS. הנמענים אמורים להיות בישראל, בלי מגבלה על הרשתות והמפעילים.<br />
האינסטינקט הראשוני הוא ליצור קשר עם ספקי SMS בישראל, שמאפשרים התממשקות באמצעות Web Service כזה או אחר, להתרשם ולקנות חבילה.<br />
גיגלתי ומצאתי שני ספקים ישראליים:</p>
<ul>
<li>SimpleSMS</li>
<li>שירות של גולדמן תקשורת שנקרא SMS API</li>
</ul>
<p><span style="font-weight: bolder;">התרשמתי מ SimpleSMS לטובה</span>. <a target="_blank" href="http://www.simplesms.co.il/">האתר שלהם</a> נראה נחמד, יש תיעוד טוב ודוגמאות קוד לשפות תכנות רבות, גם לדוט נט. ואז רציתי לשלם. אחרי מילוי מושקע של הפרטים, קבלתי הודעת שגיאה לא ברורה עם מסך של טרנזילה. ועכשיו אני בבעיה: היה חיוב או לא היה חיוב?<br />
בצר לי, התקשרתי. מכירים את המוקדים הטלפוניים האלה, שעונים לכם אנשים חינניים שבכלל לא קשורים לעסק עצמו, אלא רק שם כדי לקבל שיחות ולהעביר את הקריאה הלאה? כן כן, זה מה שהיה שם, ואמרו שיתקשרו אלי תוך 45 דקות. אחרי חצי שעה ניסיתי שוב, והדגשתי שזו הודעה שניה. כל זה היה לפני שבוע בערך, ואני עדיין מחכה.<br />
אז אם אין שירות סביר ל SimpleSMS, אין טעם שאני אשאר איתם. מזל שיש מתחרים.</p>
<p><span style="font-weight: bolder;">אז כאמור, גולדמן תקשורת</span>. שם זה סיפור אחר: באתר שלהם מדברים על API בצורת Web Service, ואפילו יש screenshot שממחיש את זה, אבל תיעוד אמיתי אין. ודוגמאות קוד, זה בכלל &quot;מוקצה&quot;. האמת, חייבים <a target="_blank" href="http://www.goldman.co.il/SMSAPI/smsapibiz/">להיכנס ולראות</a> כדי להאמין.<br />
אבל אני, אופטימיסט אני. אמרתי, ניתן צ'אנס, נרים טלפון. התקשרתי ובקשתי לנסות את המוצר, או לפחות לקבל את ה API הנכסף (ולא ב screenshot). מהעבר השני של הקו הסביר לי, בתקיפות לא ברורה, שהם היחידים שעובדים דרך סלקום, כבר שנים, ושהמתחרים לא אמינים כמותם. הסיטואציה לא היתה מספיק ברורה (לשנינו, כנראה), וסיכמנו שכדאי לי לדבר עם אסף, הבן שלו, בעניין ה API.<br />
מסתבר שתחום ה pre sales בגולדמן תקשורת קצת בעייתי, כי אסף סרב לספק את התיעוד ל API, והסביר שאני צריך לקנות את השירות כדי לקבל את ה API והתיעוד. עכשיו, נכון שהחבילה המינימלית עולה בסה&quot;כ 20 ש&quot;ח, וזה סכום פעוט לחברות תוכנה, אבל למה להחביא את ה API? מה כל כך סודי בו? אסף הסביר לי שמנסיון העבר שיש להם, זו מדיניות החברה.<br />
יש משהו קצת פישי בהסתרת API, ולא בעיה להרים שירות Dummy שיהווה &quot;מתקן אימונים&quot; אם רוצים להסתיר את הכתובת של השירות האמיתי. במילים אחרות, אני לא רואה בעיה שהיא לא פתירה, ובגלל זה אני מסיק שיש כאן בעיה של מקצועיות.<br />
אז גם גולדמן תקשורת נפסל.</p>
<p><span style="font-weight: bolder;">באותו זמן, ומהעבר השני של החדר</span>, כלומר במרחק של מטר וחצי ממני, <a target="_blank" href="http://reshefmann.com/blog/">רשף</a> כבר נרשם לשירות אמריקאי שנקרא <a target="_blank" href="http://www.twilio.com/">Twilio</a>. הם שולחים הודעות SMS להרבה מקומות בעולם, גם לישראל. תוך חצי שעה כבר נרשמנו, שילמנו (עם סליקה מוצלחת!), והיה לנו קוד מלא ועובד.</p>
<p>נחזור רגע לאינסטינקט הראשוני (מתחילת הפוסט), שאומר שבשביל שירות אינטגרציה מקומי כדאי לפנות לספקים מקומיים, כי הם בטח מתמצאים יותר ויהיו דרכם פחות בעיות טכניות. מסתבר שהפעם, פניה לספק חיצוני העלתה תוצאה טובה יותר: האמריקאים כנראה יודעים לעשות את זה טוב יותר ומקצועי יותר מהישראלים (ובכמות גדולה של הודעות, גם זול יותר). אולי כי הסליקה שלהם עובדת בלי בעיה, ואולי כי הכל פשוט מתקתק כמו שצריך, עם שירות מבוסס ReST, ועם תיעוד מלא ומקיף (ולא מוסתר&#8230;).<br />
זה אולי לא מדגם מייצג, אבל בכל זאת, בשנת 2010, הייתי מצפה מחברות טכנולוגיה/אינטגרציה מקומיות להרים שירות בסטנדרט גבוה יותר.</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/2010/03/sms-integration-israel-is-wayyy-behind-us/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Startable &#8211; State Machine part 1&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/03/startable-state-machine-part1/</link>
		<comments>http://heblog.ronklein.co.il/2010/03/startable-state-machine-part1/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 20:15:02 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Mini-Pattern]]></category>
		<category><![CDATA[State Machine]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=203</guid>
		<description><![CDATA[&#8235;מכונת מצבים פשוטה מאוד (מופעל/מופסק), שיכולה להיות שימושית כשמפתחים "יישומי רקע" (חלק 1)&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>בפוסט הזה:</p>
<ul>
<li>קצת על State Machine</li>
<li>Startable State Machine</li>
<li>מתי משתמשים</li>
<li>מימוש רגיל</li>
<li>הפרדת interface מהמימוש</li>
<li>מימוש עם נעילות</li>
<li>הדגמה פשוטה</li>
</ul>
<p>בפוסט הבא אני אראה איך אפשר להשתמש ב state machine הזה (בירושה, למשל)</p>
<h2>קצת על State Machine</h2>
<p>חלק משמעותי מעולם התכנות כולל מעבר ממצב x למצב y, כאשר כל המצבים ידועים מראש. אפשר לומר שכל התוכניות שכתבתי עד היום הן כאלו. אמנם,לא תמיד ידעתי לצפות מראש את כל המצבים, ופה ושם היו באגים שבדרכם גרמו לי להבין שיש עוד מצב או שניים שצריך לקחת בחשבון, אבל בסופו של דבר, זו היתה קבוצה סגורה ומוגדרת היטב של מצבים.</p>
<p>קבוצת המצבים הזו יכולה להיות מתוארת כמכונת מצבים (סופית), או באנגלית Finite State Machine, ובקיצור FSM. המעבר ממצב למצב נקרא transition ובד&quot;כ הצורך לעבור ממצב אחד לאחר נובע מקלט כזה או אחר, או הודעה פנימית. אפשר לקרוא עוד בויקיפדיה (<a href="http://he.wikipedia.org/wiki/%D7%90%D7%95%D7%98%D7%95%D7%9E%D7%98_%D7%A1%D7%95%D7%A4%D7%99" target="_blank">עברית</a> ו<a href="http://en.wikipedia.org/wiki/State_machine" target="_blank">אנגלית</a>) כדי להעמיק.</p>
<h2>Startable State Machine</h2>
<p>תרשו לי להציג מכונת מצבים פשוטה ונחמדה. אולי פשוטה מדי, אבל אני מקווה שאצליח לשכנע שהיא נחוצה ומעודדת שימוש חוזר בקוד (שזו מטרה נאה לכל הדעות). אני קורא למצבים פשוטים כאלה &quot;mini patterns&quot;. לא ממש design pattern, אבל בהחלט מעודד שימוש חוזר בקוד.</p>
<p>מדובר בסה&quot;כ בשני מצבים אפשריים: Started ו Stopped. או בעברית: מופעל/מופסק.</p>
<p>נדמיין שני לחצנים: לחצן Start ולחצן Stop (כמו Play ו Stop במכשיר DVD, למשל)</p>
<p>אם המצב הנוכחי הוא Stopped, ולחצנו על Start &#8211; עוברים למצב Started. כל לחיצה נוספת על Start לא משנה את המצב.</p>
<p>וכנ&quot;ל להיפך: אם המצב הנוכחי הוא Started, ולחצנו על Stop &#8211; עוברים למצב Stopped. כל לחיצה נוספת על Stop לא משנה את המצב.</p>
<p>לצורך העניין, מצב הפתיחה הוא Stopped.</p>
<p>התרשים הבא יכול לתאר את זה:</p>
<p><img src="http://heblog.ronklein.co.il/wp-content/uploads/2010/02/startable_sm.png" alt="Startable State Machine - chart" /></p>
<h2>מתי משתמשים?</h2>
<p>השימוש העיקרי שלי ב Startable הוא כשבתוך אפליקציה קיימת, אני צריך איזשהו שירות שיהיה פעיל ברקע כל הזמן, או פעיל לפעמים. למשל: שרת UDP שמאזין להודעות נכנסות בפורט מסויים, סטרימר ששולח Streaming Video למחשב אחר, רכיב שבודק כל X שניות מה הסטטוס של רכיב אחר, וכו' וכו'. לכל רכיב שכזה יש בד&quot;כ שני מצבים: &quot;פעיל&quot; או &quot;לא פעיל&quot;. קלאסי ל Startable.</p>
<h2>מימוש רגיל</h2>
<p>המימוש הוא די פשוט:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">namespace</span> Groundhog.<span class="me1">Lib</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">enum</span> StartableStatus<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Started,<br />
&nbsp; &nbsp; &nbsp; &nbsp; Stopped<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">class</span> StartableStateMachine<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> StartableStatus status<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">event</span> Action OnStart<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">event</span> Action OnStop<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> StartableStateMachine<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw1">this</span><span class="br0">&#40;</span>StartableStatus.<span class="me1">Stopped</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> StartableStateMachine<span class="br0">&#40;</span>StartableStatus initialStatus<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status <span class="sy0">=</span> initialStatus<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">void</span> InvokeAction<span class="br0">&#40;</span>Action e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> <span class="sy0">==</span> e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">void</span> InvokeOnStop<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InvokeAction<span class="br0">&#40;</span>OnStop<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">void</span> InvokeOnStart<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InvokeAction<span class="br0">&#40;</span>OnStart<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Start<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>status <span class="sy0">==</span> StartableStatus.<span class="me1">Started</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// it was &quot;stopped&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// change to &quot;started&quot; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status <span class="sy0">=</span> StartableStatus.<span class="me1">Started</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// and raise the proper event</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InvokeOnStart<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Stop<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>status <span class="sy0">==</span> StartableStatus.<span class="me1">Stopped</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// it was &quot;started&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// change to &quot;stopped&quot; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status <span class="sy0">=</span> StartableStatus.<span class="me1">Stopped</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// and raise the proper event</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InvokeOnStop<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> StartableStatus Status<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; get<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> status<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>סקירת קוד קצרה:</p>
<ul>
<li>יש כאן enum על הסטטוס: Started או Stopped</li>
<li>אפשר לקבל את הסטטוס הנוכחי באמצעות המאפיין Status (דה!)</li>
<li>בנוסף יש שתי מתודות: Start ו Stop שהן ה&quot;לב&quot; של ה state machine שלנו</li>
<li>וכדי להודיע לעולם שהסטטוס השתנה, יש שני אירועים: OnStart ו OnStop.</li>
</ul>
<p>מה אין כאן?<br />
הקוד הוא לא thread-safe, מיד נגיע לזה.</p>
<h2>הפרדת interface מהמימוש</h2>
<p>ממוש, תפריד לי את ה interface מהמימוש, טוב?<br />
הנה, מותק:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">namespace</span> Groundhog.<span class="me1">Lib</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">public</span> <span class="kw4">interface</span> IStartableStateMachine<br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">event</span> Action OnStart<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">event</span> Action OnStop<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">void</span> Start<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; StartableStatus Status <span class="br0">&#123;</span> get<span class="sy0">;</span> <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">void</span> Stop<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>ועכשיו, אחרי שיש לנו הפרדה בין החוזה למימוש, אפשר לממש בצורות אחרות.</p>
<h2>מימוש עם נעילות</h2>
<p>כדי שהקוד יהיה thread-safe, אפשר:</p>
<ul>
<li>להשתמש בנעילות רגילות (או באבסטרקציה שהצעתי <a href="http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker/">בפוסט אחר</a>)</li>
<li>לעבוד עם Interlock, שמהווה מנגנון יותר light-weight לנעילות מהסוג שצריך כאן</li>
</ul>
<p>כל הקוד לנעילות השונות נמצא <a href="http://heblog.ronklein.co.il/wp-content/uploads/2010/03/Groundhog.zip">בקובץ המצורף</a>. אני לא נכנס לזה פשוט כי זה לא העיקר בפוסט הזה.</p>
<h2>הדגמה פשוטה</h2>
<p>הנה קוד של Console Application שנותן לנו קצת להרגיש את כל מה שהיה לנו עד עכשיו.</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">using</span> <span class="co3">Groundhog.Lib</span><span class="sy0">;</span><br />
<span class="kw1">namespace</span> Groundhog.<span class="me1">ConsoleApp</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw4">class</span> Program<br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">static</span> <span class="kw1">void</span> Main<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; IStartableStateMachine ssm <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> StartableStateMachine<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">OnStart</span> <span class="sy0">+=</span> MyOnStart<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">OnStop</span> <span class="sy0">+=</span> MyOnStop<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;===========================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;simple flow: start and stop&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;===========================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span>ssm.<span class="me1">Status</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span>ssm.<span class="me1">Status</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span>ssm.<span class="me1">Status</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;========================================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;multiple starts and then multiple stops,&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;should invoke each event just once&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;========================================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span>ssm.<span class="me1">Status</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; ssm.<span class="me1">Stop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span>ssm.<span class="me1">Status</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;===================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;press enter to quit&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;===================&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">ReadLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">static</span> <span class="kw1">void</span> MyOnStart<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;hey, it started!&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">static</span> <span class="kw1">void</span> MyOnStop<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;dude, this thing stopped&quot;</span><span class="br0">&#41;</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>והפלט יהיה:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">===========================<br />
simple flow: start and stop<br />
===========================<br />
Stopped<br />
hey, it started!<br />
Started<br />
dude, this thing stopped<br />
Stopped</p>
<p>
========================================<br />
multiple starts and then multiple stops,<br />
should invoke each event just once<br />
========================================<br />
hey, it started!<br />
Started<br />
dude, this thing stopped<br />
Stopped</p>
<p>
===================<br />
press enter to quit<br />
===================</div>
</div>
<p>כפי שניתן לראות, גם אחרי מספר קריאות עוקבות ל start, הסטטוס נשאר started, וכנ&quot;ל גם לגבי קריאות למתודה stop. כלומר יש לנו state machine בדיוק כמו שרצינו.</p>
<p>בהזדמנות הבאה אני אראה איך משתמשים בקוד הזה בירושה (ובדרך נוספת), בדיוק עבור אותם רכיבים שמבצעים איזושהי עבודה ברקע.</p>
<p>תכנות נעים!</p>
<p>כל הקוד בפוסט הזה <a href="http://heblog.ronklein.co.il/wp-content/uploads/2010/03/Groundhog.zip">נמצא כאן</a>.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2010/03/startable-state-machine-part1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Chainsaw Session at ALT.NET tools meeting&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/02/chainsaw-session-at-alt-net-tools-meeting/</link>
		<comments>http://heblog.ronklein.co.il/2010/02/chainsaw-session-at-alt-net-tools-meeting/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 21:04:45 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Chainsaw]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=273</guid>
		<description><![CDATA[&#8235;לפני שבועיים בערך הייתי במפגש של קבוצת ALT.NET ישראל.
מה זה ALT.NET? הנה העקרון הכללי:

We are a self-organizing, ad-hoc community of developers bound by a desire to improve ourselves, challenge assumptions, and help each other pursue excellence in the practice of software development.

(מתוך אתר ALT.NET)
בקיצור, כן מתכנתים בדוט נט, אבל לא עם הראש בקיר (ובעיקר לא [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>לפני שבועיים בערך הייתי במפגש של <a target="_blank" href="http://www.facebook.com/group.php?gid=22976817716">קבוצת ALT.NET ישראל</a>.<br />
מה זה ALT.NET? הנה העקרון הכללי:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">We are a self-organizing, ad-hoc community of developers bound by a desire to improve ourselves, challenge assumptions, and help each other pursue excellence in the practice of software development.</div>
</div>
<p>(מתוך אתר <a target="_blank" href="http://altdotnet.org/">ALT.NET</a>)<br />
בקיצור, כן מתכנתים בדוט נט, אבל לא עם הראש בקיר (ובעיקר לא &quot;כי ככה אמרו במיקרוסופט&quot;). כן להיפגש, אבל לא בהרצאות מובנות, אלא בשיחה פתוחה.</p>
<p>המפגש שבו השתתפתי עסק יותר בכלים שונים שיכולים ללוות את המתכנת או לשנות את צורת העבודה שלו. <a target="_blank" href="http://weblogs.asp.net/israelio/archive/2010/02/04/atl-net-tools-the-videos.aspx">אוהד ישראלי מתאר את זה בפוסט משלו</a>. תודה ל<a target="_blank" href="http://www.kenegozi.com/blog/">חן אגוזי</a> על הארגון ולחברת Delver על האירוח <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>אני נתתי session על Chainsaw, מתוך כוונה ברורה &quot;להפיץ את הבשורה&quot; ולאפשר למתכנתים נוספים להכיר את ה viewer החביב הזה. בהפסקה נגשו אלי פה ושם אנשים שאמרו שזה באמת מחדש להם והם ינסו את זה. אשריני. אפשר לצפות בוידאו, אבל בעיקר שומעים אותי, וגם זה בקושי. אז הנה, למיטיבי השמיעה שביניכם:</p>
<p><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="370" id="viddler"><param name="movie" value="http://www.viddler.com/player/f3c8a8af/" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><param name="flashvars" value="fake=1"/><embed src="http://www.viddler.com/player/f3c8a8af/" width="437" height="370" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" flashvars="fake=1" name="viddler" ></embed></object></p>
<p>בהזדמנות אני אוסיף לפוסט את המצגת ואת קבצי המקור.</p>
<p>ניסור נעים!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2010/02/chainsaw-session-at-alt-net-tools-meeting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;We&#039;re Hiring&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/01/we-are-hiring/</link>
		<comments>http://heblog.ronklein.co.il/2010/01/we-are-hiring/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 11:25:45 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[job]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=262</guid>
		<description><![CDATA[&#8235;החברה שבה אני עובד, אקסייטס מדיה, מגייסת בימים אלה עובדים/ות למשרות פיתוח.
בגדול מדובר בשלוש משרות פיתוח:

Server Side Developer
Web Developer
Junior Developer

לתיאור המשרות ולפרטים נוספים &#8211; לחצו כאן.
&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>החברה שבה אני עובד, <a target="_blank" href="http://www.xsights.com/index.php">אקסייטס מדיה</a>, מגייסת בימים אלה עובדים/ות למשרות פיתוח.</p>
<p>בגדול מדובר בשלוש משרות פיתוח:</p>
<ol>
<li>Server Side Developer</li>
<li>Web Developer</li>
<li>Junior Developer</li>
</ol>
<p>לתיאור המשרות ולפרטים נוספים &#8211; <a target="_blank" href="http://www.xsights.com/index.php?option=com_content&#038;view=article&#038;id=37&#038;Itemid=34">לחצו כאן</a>.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2010/01/we-are-hiring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Locking by Decorator&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/01/locking-by-decorator/</link>
		<comments>http://heblog.ronklein.co.il/2010/01/locking-by-decorator/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 08:00:21 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Decorator]]></category>
		<category><![CDATA[Design-Patterns]]></category>
		<category><![CDATA[locking]]></category>
		<category><![CDATA[Multi-Threading]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=252</guid>
		<description><![CDATA[&#8235;בפוסט הזה אני מציע דרך נוספת לעטוף רכיב בנעילה, תוך שימוש ב Design Pattern שנקרא Decorator. המטרה היא שוב להפריד בין לוגיקת רכיב ללוגיקת נעילה, כדי ליצור קוד נקי יותר וגמיש יותר לפי צרכי הפרויקט.&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>בפוסט הזה:</p>
<ul>
<li>הקדמה</li>
<li>הגדרת החוזה</li>
<li>מימוש רגיל ללא נעילות</li>
<li>נעילה באמצעות Decorator</li>
<li>יישום</li>
</ul>
<h2>הקדמה</h2>
<p>לא מזמן כתבתי <a href="http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker/">פוסט</a> שמציע להפריד בין לוגיקה של רכיב ללוגיקה של נעילה ע&quot;י אבסטרקציה. בפוסט הזה אני מציע דרך נוספת לעטוף רכיב בנעילה, תוך שימוש ב Design Pattern שנקרא Decorator. המטרה היא שוב להפריד בין לוגיקת רכיב ללוגיקת נעילה, כדי ליצור קוד נקי יותר וגמיש יותר לפי צרכי הפרויקט.</p>
<h2>הגדרת החוזה</h2>
<p>כדי לא להסתבך יותר מדי, אני אמשיך את הרעיון מהפוסט ההוא, ולכן דוגמת ה Counter תלווה אותנו גם כאן. נמיר את ה Counter שלנו מ class ל interface באופן הבא:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">interface</span> ICounter<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">void</span> Hit<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> Current <span class="br0">&#123;</span> get<span class="sy0">;</span> <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<h2>מימוש רגיל ללא נעילות</h2>
<p>המימוש הרגיל והמיידי ל interface הנ&quot;ל:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">class</span> Counter <span class="sy0">:</span> ICounter<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">int</span> counter <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Hit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">++</span>counter<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">int</span> Current<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; get <span class="br0">&#123;</span> <span class="kw1">return</span> counter<span class="sy0">;</span> <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span class="br0">&#125;</span></div>
</div>
<p>עד כאן טוב ויפה, אבל המימוש הוא כמובן לא thread-safe. עם זאת, הלוגיקה שבמימוש הזה ברורה וקריאה, ונוכל לכתוב unit tests שמתייחסים למימוש הזה בצורה פשוטה ומהירה. זה יתרון חשוב.</p>
<h2>נעילה באמצעות Decorator</h2>
<p>קצת הקדמה: מה זה Decorator?</p>
<p>אז ככה: בגדול, Decorator זה Design Pattern שמתייחס ל interface-ים ול<strong>הוספת פונקציונליות בזמן ריצה, לא על ידי ירושה</strong>. אפשר לקרוא עוד ב<a target="_blank" href="http://en.wikipedia.org/wiki/Decorator_pattern">ויקיפדיה</a>. במקרה שלפנינו, נוסיף פונקציונליות של נעילה על המימוש של ICounter. או, בניסוח אחר: &quot;נקשט&quot; את הפונקציונליות של Counter בנעילה, אבל נשמור על ה interface. כלומר החוזה נשמר אבל נקבל עוד משהו במימושים.</p>
<p>ניגש לקוד עצמו של ה Decorator שלנו:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">class</span> CounterLockDecorator <span class="sy0">:</span> ICounter<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">readonly</span> ICounter core<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">readonly</span> <span class="kw4">object</span> syncObject <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> <span class="kw4">object</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> CounterLockDecorator<span class="br0">&#40;</span>ICounter coreCounter<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> <span class="sy0">==</span> coreCounter<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">throw</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> ArgumentNullException<span class="br0">&#40;</span><span class="st0">&quot;coreCounter&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; core <span class="sy0">=</span> coreCounter<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Hit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">lock</span> <span class="br0">&#40;</span>syncObject<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; core.<span class="me1">Hit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">int</span> Current<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; get <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">lock</span> <span class="br0">&#40;</span>syncObject<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> core.<span class="me1">Current</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>כפי שניתן לראות, ה Decorator מממש בעצמו את החוזה ICounter. אבל הוא לא עושה את כל העבודה &#8211; <strong>הוא מצפה לקבל בקונסטרקטור שלו מימוש קיים ל ICounter ו&quot;מגלגל&quot; אליו את הקריאות לפי הצורך</strong>. כך, למשל, במימוש של המתודה Hit: ה Decorator רק עוטף בנעילה את הקריאה למתודת ה Hit של המימוש הקיים שהוא מחזיק.</p>
<h2>יישום</h2>
<p>הקריאה ל Counter הרגיל, ללא נעילות, יכולה להתבצע כך:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">ICounter myCounter <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Counter<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>ואם רוצים את הפונקציונליות של הנעילות, נוכל לקבל ICounter באופן הבא:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">ICounter myCounter <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> CounterLockDecorator<span class="br0">&#40;</span><a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Counter<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<h2>סיכום</h2>
<p>גם בפוסט הזה הראיתי כיצד ניתן להפריד בין הלוגיקה של הרכיב לבין הנעילות שלו. יש להפרדה הזו גם יתרונות וגם חסרונות. היתרונות העיקריים הם קוד גמיש וטסטבילי (כלומר כזה שניתן לבדיקות בצורה קלה). גם הקוד של הרכיב עצמו קריא וברור. עם זאת, יש אי אילו חסרונות להפרדה הזו: פתאום יש שלושה קבצים לתחזק (החוזה, המימוש הרגיל וה decorator) במקום אחד, והקריאה הופכת להיות קצת יותר מורכבת (אפשר לפתור את זה עם factory). יש פתרון נוסף לעניין הזה, והוא שימוש ב dynamic proxy. אם יהיה לי זמן אני ארחיב על זה, אבל הרעיון הכללי הוא ליצור את ה Decorator בזמן ריצה באמצעות הכלים הסטנדרטיים של דוט נט כמו <a target="_blank" href="http://msdn.microsoft.com/en-us/library/y2k85ax6.aspx">CodeDOM</a> או באמצעות פריימוורק שהוא קצת יותר high level כמו <a target="_blank" href="http://www.castleproject.org/dynamicproxy/index.html">Dynamic Proxy</a> של Castle.</p>
<p>אגב, אפשר להשתמש בנעילה האבסטרקטית שהצעתי <a href="http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker">בפוסט ההוא</a> בתוך ה Decorator וכך &quot;להרוויח&quot; עוד קצת גמישות בבחירת מנגנון הנעילה עצמו, אבל זה כבר עניין אחר <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>כל הקוד נמצא <a href="http://heblog.ronklein.co.il/wp-content/uploads/2010/01/Attollo.zip">כאן</a>, ושיהיה קישוט נעים!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2010/01/locking-by-decorator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;Tip: Setting a startup project in the .sln file&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/01/tip-setting-a-startup-project-in-the-sln-file/</link>
		<comments>http://heblog.ronklein.co.il/2010/01/tip-setting-a-startup-project-in-the-sln-file/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 08:38:01 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[sln]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=233</guid>
		<description><![CDATA[&#8235;טיפ: איך שומרים על ה startup project כחלק מקובץ ה sln? -שימושי כשרוצים להעלות דוגמאות לרשת כחלק מ open source projects או כחלק מפוסט.&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>הכנתי פרויקט Lib מסוג Class Library והכנתי פרויקט Demo (שמשתמש ב Lib) מסוג Console Application, ושניהם באותו solution.<br />
שמרתי הכל, והגדרתי שה Demo יהיה ה startup project. הגיוני.<br />
ועכשיו רציתי לשים את הכל כדוגמה לפוסט, אז כיווצתי הכל ל zip.</p>
<p>רק שניה, לפני שאני מעלה את זה, רק כדי לוודא שהכל עובד, אני פותח את הזיפ בתיקיה חדשה וריקה, ומשם פותח את ה Visual Studio 2008 ולוחץ F5 כדי להריץ&#8230; ופתאום הוא בוכה שאי אפשר להריץ Class Library, ואני הרי זוכר שממש לפני דקה הגדרתי שה startup project יהיה ה Demo. <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_mad.gif' alt=':mad:' class='wp-smiley' /> </p>
<p>טוב, בטח אני לא הראשון שנתקל בזה, אז קדימה <a target="_blank" href="http://www.google.com/search?q=setting+startup+project+visual+studio+sln">לגגל</a>!<br />
הגעתי (איך לא) ל<a target="_blank" href="http://stackoverflow.com/questions/694730/why-is-set-as-startup-option-stored-in-the-sou-file-and-not-the-sln-file">דיון דומה ב stackoverflow.com</a>, וגם ל<a target="_blank" href="http://www.ariankulp.com/archive/2009/02/23/2557.aspx">פוסט בנושא בבלוג של Arian Kulp</a>.<br />
מה מסתבר? שההגדרה של ה startup project לא נשמרת ב sln, אלא ב suo. <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_eek.gif' alt=':shock:' class='wp-smiley' /><br />
יש דרך לעקוף את זה:<br />
פותחים את קובץ ה sln באיזה text editor כמו notepad (אני אישית מעריץ נלהב של <a title="Notepad++" target="_blank" href="http://notepad-plus.sourceforge.net/uk/site.htm">NPP</a>), ושם יש שורות כמו אלו:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">Microsoft Visual Studio Solution File, Format Version 10.00<br />
# Visual Studio 2008<br />
Project(&quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&quot;) = &quot;Lib&quot;, &quot;Lib\Lib.csproj&quot;, &quot;{F959D3D9-052F-4C62-B957-BF6459CB2209}&quot;<br />
EndProject<br />
Project(&quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&quot;) = &quot;Demo&quot;, &quot;Demo\Demo.csproj&quot;, &quot;{852E3624-B5EB-40DF-A2EE-481037C8F47B}&quot;<br />
EndProject<br />
&#8230;</div>
</div>
<p><strong>פשוט מעבירים את החלק של Project&#8230;EndProject של הפרוייקט הרצוי להיות הראשון</strong>. בהמשך לדוגמה הזו, המצב הרצוי הוא:</p>
<div class="codesnip-container" >
<div class="text codesnip" style="font-family:monospace;">Microsoft Visual Studio Solution File, Format Version 10.00<br />
# Visual Studio 2008<br />
Project(&quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&quot;) = &quot;Demo&quot;, &quot;Demo\Demo.csproj&quot;, &quot;{852E3624-B5EB-40DF-A2EE-481037C8F47B}&quot;<br />
EndProject<br />
Project(&quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&quot;) = &quot;Lib&quot;, &quot;Lib\Lib.csproj&quot;, &quot;{F959D3D9-052F-4C62-B957-BF6459CB2209}&quot;<br />
EndProject<br />
&#8230;</div>
</div>
<p>וזה עושה את העבודה.</p>
<p>שימושי כשרוצים להוסיף פרויקט דוגמה לפוסט, ו/או בפרויקטים של קוד פתוח ברשת.<br />
תוכלו <a href="http://heblog.ronklein.co.il/wp-content/uploads/2010/01/Poseidon.zip">לנסות בעצמכם</a> <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/2010/01/tip-setting-a-startup-project-in-the-sln-file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;From lock to abstract locker&#8236;</title>		<link>http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker/</link>
		<comments>http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 18:15:36 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[abstraction]]></category>
		<category><![CDATA[Dependency-Injection]]></category>
		<category><![CDATA[locking]]></category>
		<category><![CDATA[Multi-Threading]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=214</guid>
		<description><![CDATA[&#8235;לא חייבים לנעול רק עם lock. בפוסט הזה נראה מתי ואיך משתמשתים באבסטרקציה של נעילה.&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>כמו שמשתמע מהכותרת של הפוסט הזה, לא חייבים לנעול דווקא עם lock (כלומר נעילה שמבוססת על Monitor).<br />
יש נעילות נוספות (למשל, Spin-Lock), ולכן אני מציע כאן אבסטרקציה לנעילה.</p>
<p>במילים אחרות, במקום הקוד הזה:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">lock</span><span class="br0">&#40;</span>locker<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// do something</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>אני מציע משהו כזה:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">locker.<span class="me1">Enter</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="co1">// do something</span><br />
locker.<span class="me1">Exit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>אלא שזה קצת מעצבן, ולכן אפשר לשכלל את זה אם נשתמש ב IDisposable וניצור משהו יותר נחמד עם ה using שהוא סוג של מאקרו בדוט נט:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">using</span><span class="br0">&#40;</span>locker.<span class="me1">EnterLock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// do something</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>אז בפוסט הזה יש:</p>
<ul>
<li>קצת אבסטרקציה</li>
<li>קצת מוטיבציה</li>
<li>קוד בסיס</li>
<li>2 ירושות</li>
<li>וקצת אינטגרציה <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ul>
<h2>קצת מוטיבציה</h2>
<p>מתי זה שימושי?<br />
-בעיקר אם נרצה לכתוב class שיכול להיות שימושי גם בסביבה שהיא single-threaded וגם בסביבה שהיא multi-threaded.</p>
<h2>קצת קוד בסיס</h2>
<p>ניגש לקוד עצמו. הנה ה base class עם תוספת פנימית בשביל ה using הנכסף:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">using</span> <span class="co3">System</span><span class="sy0">;</span></p>
<p><span class="kw1">public</span> abstract <span class="kw4">class</span> LockerBase<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> abstract <span class="kw1">void</span> Enter<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> abstract <span class="kw1">void</span> Exit<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">class</span> DisposableLocker <span class="sy0">:</span> IDisposable<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">readonly</span> LockerBase locker<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> DisposableLocker<span class="br0">&#40;</span>LockerBase locker<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">locker</span> <span class="sy0">=</span> locker<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Dispose<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; locker.<span class="me1">Exit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> DisposableLocker EnterLock<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Enter<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DisposableLocker<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>המתודות Enter ו Exit הן אבסטרקטיות, וכל מי שירצה לרשת מה base class הזה יצטרך לממש אותן.<br />
אגב, אני לא מת על ירושה (לא בתכנות, לפחות), אבל כאן זה נראה יותר מתאים, כי יש איזה state לשמור עליו.</p>
<h2>ירושה &#8211; המימוש ה&quot;רגיל&quot;</h2>
<p>בואו נראה למשל, את המימוש המתבקש לנעילה &quot;שגרתית&quot;:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">using</span> <span class="co3">System.Threading</span><span class="sy0">;</span></p>
<p><span class="kw1">public</span> <span class="kw4">class</span> MonitorLocker <span class="sy0">:</span> LockerBase<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">readonly</span> <span class="kw4">object</span> syncRoot<span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> MonitorLocker<span class="br0">&#40;</span><span class="kw4">object</span> syncObject<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; syncRoot <span class="sy0">=</span> syncObject<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> MonitorLocker<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw1">this</span><span class="br0">&#40;</span><a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> <span class="kw4">object</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">override</span> <span class="kw1">void</span> Enter<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Monitor.<span class="me1">Enter</span><span class="br0">&#40;</span>syncRoot<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">override</span> <span class="kw1">void</span> Exit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Monitor.<span class="me1">Exit</span><span class="br0">&#40;</span>syncRoot<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span class="br0">&#125;</span></div>
</div>
<p>בקונסטרקטור נשים אובייקט שתפקידו להיות המשאב המשותף שעליו מבוססים השיתוף והנעילה.</p>
<h2>ירושה &#8211; המימוש הריק</h2>
<p>ועכשיו לקוד קצת אחר: class שלמעשה לא נועל. מעין dummy class שרק שומר על הפונקציונליות כלפי חוץ:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">class</span> DummyLocker <span class="sy0">:</span> LockerBase<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">override</span> <span class="kw1">void</span> Enter<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">override</span> <span class="kw1">void</span> Exit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>בעקרון ה class הזה לא ישבור קומפילציה, אבל הוא לא באמת נועל כלום. זה ה dummy שלנו למקרה שמריצים את הקוד בסביבה שהיא single-threaded.</p>
<h2>קצת אינטגרציה</h2>
<p>אחרי כל הקוד הזה, נראה שימוש לאבסטרקציה הזו. נניח שיש לנו class בשם Counter. כל מה שיש שם זה מתודה בשם Hit ופרופרטי בשם Current.<br />
וכל מה שצריך לקרות זה שכל קריאה ל Hit מעלה ב 1 את הערך של Current (שערכו ההתחלתי הוא 0).<br />
אנחנו יודעים מראש שיהיו מצבים שבהם ה class הזה יהיה שימושי בסביבה שהיא single-threaded וכן בסביבה שהיא multi-threaded. לכן נשתמש בנעילה האבסטרקטית:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw4">class</span> Counter<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw1">readonly</span> LockerBase locker<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">private</span> <span class="kw4">int</span> counter <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> Counter<span class="br0">&#40;</span>LockerBase locker<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">this</span>.<span class="me1">locker</span> <span class="sy0">=</span> locker<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw1">void</span> Hit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">using</span> <span class="br0">&#40;</span>locker.<span class="me1">EnterLock</span><span class="br0">&#40;</span><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; &nbsp; <span class="sy0">++</span>counter<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">int</span> Current<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; get<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">using</span> <span class="br0">&#40;</span>locker.<span class="me1">EnterLock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> counter<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>הקוד די פשוט: כל התייחסות ל counter הפנימי &quot;עטופה&quot; בנעילה, אבל אנחנו לא יודעים מה יהיה המנעול שאיתו נעבוד.<br />
המנעול עצמו יכנס ל class דרך הקונסטרקטור (ולזה קוראים Dependency Injection).<br />
כך, למשל, ניצור instance של Counter לסביבה שהיא single-threaded (כלומר ללא צורך בנעילות):</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">Counter myCounter <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Counter<span class="br0">&#40;</span><a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DummyLocker<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>אבל, כדי לא לעצבן את המתכנת שישתמש ב class הזה, אולי כדאי שנוסיף overload עם ה dummy-locker שלנו כברירת מחדל לקונסטרקטור ריק:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> Counter<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw1">this</span><span class="br0">&#40;</span><a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DummyLocker<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>ואז השימוש יהיה קל יותר:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">Counter myCounter <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Counter<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>נוכל גם להוסיף מתודה סטאטית שתפקידה ליצור instance שהוא thread-safe באופן הבא:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">public</span> <span class="kw1">static</span> Counter Synchronized<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Counter<span class="br0">&#40;</span><a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> MonitorLocker<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>והקריאה:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;">Counter myCounter <span class="sy0">=</span> Counter.<span class="me1">Synchronized</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<h2>סיכום</h2>
<p>מה שהצעתי כאן זה אבסטרקציה למנגנון הנעילה, תוך שימוש במאקרו של using כדי לכתוב קוד שמתנהג קרוב ככל האפשר ל lock המוכר.<br />
האבסטרקציה הזו שימושית אם יודעים מראש שיש איזה class שיהיה שימושי גם בסביבה שהיא multi-threaded וגם בסביבה שהיא single-threaded.<br />
עם זאת, יש דרכים נוספות להשיג את התוצאה הזו.<br />
למשל, לכתוב interface ל Counter וליצור decorator שהוא יעטוף כל פעולה בנעילה, או dynamic proxy שיעשה את זה באופן אוטומטי. אולי אני ארחיב על זה בהזדמנות.<br />
בכל מקרה, מה שאנחנו משיגים כאן זו הפרדה של הלוגיקה של הקוד עצמו מהלוגיקה של הנעילה, וזה נחמד לכשעצמו, וגם נותן לנו יתרון משמעותי אם נרצה לכתוב unit testing לקוד הזה.</p>
<p>ניתן להוריד את הקוד של הפוסט הזה מהלינק <a href="http://heblog.ronklein.co.il/wp-content/uploads/2010/01/Magna.zip">הזה</a>.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2010/01/from-lock-to-abstract-locker/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>&#8235;log4net &#8211; המדריך למלגלג (חלק 3 &#8211; למצוא viewer נורמלי)&#8236;</title>		<link>http://heblog.ronklein.co.il/2009/12/log4net-part3/</link>
		<comments>http://heblog.ronklein.co.il/2009/12/log4net-part3/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 19:48:41 +0000</pubDate>
		<dc:creator>&#8235;רון קליין&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[Chainsaw]]></category>
		<category><![CDATA[log4net]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=99</guid>
		<description><![CDATA[&#8235;כתבנו ללוג, ועכשיו מה? -כדי לצפות בלוג, כדאי להשתמש בתוכנה רצינית. אני משתמש ב Chainsaw, שכולל מנוע שאילתות רציני.&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>בפוסט הזה:</p>
<ul>
<li> למה צריך viewer ללוג</li>
<li> קריטריונים ל viewer נורמלי</li>
<li> איזה viewerים קיימים</li>
<li>Chainsaw &#8211; ה viewer המועדף עלי (מאיפה מורידים, איך מגדירים וכו')</li>
</ul>
<h2>למה צריך Viewer ללוג</h2>
<p>אז עשית try/catch (ואולי גם finally), וכתבת ללוג את ה exception. נפלא.<br />
עכשיו מה?<br />
הרי עכשיו, אם אתה יודע שיש איזו שגיאה אי שם בלוג, צריך להתחיל לבדוק מה הסיפור שלה, מה גרם לה להתרחש, מה ומה ומה.<br />
לכל error יש סיפור מאחוריו, עלילה שלמה. בשביל זה צריך viewer &#8211; תוכנה שבעזרתה ניתן לראות את הלוג ולנסות להבין את הסיפור.</p>
<p>Log Viewer זו תוכנה די יבשה, שמציגה שורות על גבי שורות, כל שורה היא הודעה ללוג.<br />
הנה כמה תמונות מסך מ viewers שונים:</p>
<div class="ron">
<table class="border1 my_center_all">
<tbody>
<tr>
<td><a class="lightbox" rel="lightbox[logger-screenshots]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/log4view-screenshot.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/log4view-screenshot-thumb.png" alt="" /></a></td>
<td><a class="lightbox" rel="lightbox[logger-screenshots]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/kiwi-screenshot.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/kiwi-screenshot-thumb.png" alt="" /></a></td>
<td><a class="lightbox" rel="lightbox[logger-screenshots]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/chainsaw-screenshot.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/chainsaw-screenshot-thumb.png" alt="" /></a></td>
</tr>
<tr>
<td>log4view</td>
<td>Kiwi Log Viewer</td>
<td>Chainsaw</td>
</tr>
</tbody>
</table>
</div>
<h2>קריטריונים ל Viewer</h2>
<p>כל viewer חייב מערת סינון (filter), כך שמתוך כל ההודעות בלוג יוצגו רק אלו שעונות לתנאי/ם מסויימ/ים.<br />
יהיה נחמד אם ב viewer תהיה גם אפשרות &quot;לקפוץ&quot; להודעה הבאה שמקיימת תנאי מסויים (כמו Find או Search בעורכי טקסט)<br />
יהיה מאוד נחמד לקבל צביעת שורות לפי תנאים מסויימים (לאו דווקא אותם תנאים של הסינון)<br />
אז בואו נפרסם הודעת &quot;דרושים&quot; ל-viewer האידיאלי<br />
לפרויקט עם log4net דרוש viewer לצפיה בלוג:<br />
יודע לקרוא קבצי לוג, גם סגורים וגם פתוחים<br />
יודע לתת חתכי &quot;וגם&quot; (and) &#8211; חובה<br />
יודע לתת חתכי &quot;או&quot; (or) &#8211; חובה<br />
יודע לתת חתכי טקסט חלקי (like) &#8211; חובה<br />
יודע לבצע חיפוש (קפיצות) ע&quot;פ הקריטריונים הנ&quot;ל &#8211; יתרון<br />
צביעת שורות על פי תנאים &#8211; יתרון<br />
תיעוד טוב &#8211; יתרון</p>
<h2>אז מה כבר קיים בשוק?</h2>
<p>קודם כל, אפשר לכתוב הודעות לוג ל DB. נכון שזה חתיכת overhead לרשום הודעות לוג ל DB, אבל זה אפשרי ב live, ואפשר גם לקחת קובץ לוג, לקרוא אותו, ו&quot;לשפוך&quot; את ההודעות ל DB. מה זה נותן לנו? הרבה כוח לבצע חיתוכים כמה ואיך שאנחנו רוצים. כל מי שהתעסק פעם עם SQL יודע שאפשר ליצור שאילתות פשוטות בזמן קצר. ואפשר להעזר בכל designer כדי לכתוב שאילתות מורכבות יותר. גם ה SQL Management Studio שבא יחד עם MS-SQL-Server עובד יפה.<br />
במילים פשוטות, אם רוצים, אז אפשר לבנות שאילתות מול DB ובאמצעותן לקבל כמעט את כל מה שרוצים. אמנם לא בצבעים יפים, אבל תכלס זה אפשרי ופרקטי.</p>
<p>כמו שסבתא שלי היתה אומרת: נו, וחוץ מזה?</p>
<p>או, אז באמת יש כמה דברים:</p>
<ul>
<li> <a href="http://www.kiwisyslog.com/kiwi-log-viewer-overview/" target="_blank">Kiwi</a> Log Viewer &#8211; שזה יותר tail עם צביעת שורות, אבל שיהיה</li>
<li><a href="http://www.log4view.com/" target="_blank">Log4View</a></li>
<li>Log4Net <a href="http://www.log4view.com/">Dashboard</a></li>
<li>Apache <a href="http://logging.apache.org/chainsaw/" target="_blank">Chainsaw</a></li>
</ul>
<p>אתם מוזמנים לבדוק כל כלי בנפרד. אני בדקתי, ולמרות שמצאתי פיצ'רים חביבים פה ושם, רק Chainsaw עונה על הקריטריון הכי משמעותי מבחינתי: ביצוע חתכי &quot;או&quot;. לדוגמה: אני מעוניין לצפות בכל הודעות הלוג שמופיעה בהן המילה &quot;session&quot; ו/או בהודעות הלוג שהגיעו מ class שנקרא &quot;MailSender&quot;. כמה טריויאלי, כמה נחוץ, וכמה לא קיים כמעט בשום מקום.</p>
<p>שום מקום חוץ מ Chainsaw, כאמור. הפרויקט הזה, Chainsaw, הוא בכלל ב Java ולמען לוגים בפורמט של log4j. כן, כמו הרבה דברים שקשורים בדוט נט, גם כאן זה התחיל ב Java. אלא מה, הפעם אין שום מקבילה ראויה ל Chainsaw בדוט נט. כך שה look and feel אמנם קצת צולע, אבל הי, חכו תראו איזה מנוע שאילתות מגיע עם הקביים!</p>
<h2>Chainsaw &#8211; ה Viewer המועדף עלי</h2>
<h3>הורדות והתקנות</h3>
<p>1. הורדות: כדי להריץ את ה Chainsaw הלז צריך שיהיה לכם מותקן על המחשב <a href="http://www.java.com/en/download/index.jsp">JRE</a>. וכמובן, צריך להוריד את המסור <a href="http://logging.apache.org/chainsaw/index.html">מהאתר הרשמי של Apache</a>. אני ממליץ להוריד את גרסת ה Unix/Dos Standalone. ה Chainsaw חינמי ברשיון Apache גירסה 2.<br />
2. הורדתם? יופי. עכשיו תתקינו. פשוט לעשות Unzip של גירסת ה Standalone לתיקיה מספיק נוחה לגישה בהארד דיסק. תסלחו לי על הנאיביות, אבל אצלי זה מותקן ב C:\chainsaw-bundle. פשוט ככה, כמו בימי DOS העליזים, כששיחקנו Doom ושאר משחיתי-נוער.<br />
3. התקנתם? יופי, עכשיו תפעילו (פשוט תריצו את הקובץ chainsaw.bat) ומיד תקבלו ניג'וס ראשון &quot;זאת הפעלה ראשונה שלך, בלה-בלה, לא מוגדרים receiver-ים&quot;. לא נורא, נגדיר ידנית (ראו תמונה).</p>
<p><a title="מסך פתיחה" class="lightbox" rel="lightbox[chainsaw-first-nag.png]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/chainsaw-first-nag.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/chainsaw-first-nag-thumb.png" alt="" /></a></p>
<p>ויש עוד ניג'וס כללי: החלון של ה bat &#8211; פשוט נמצא שם, מכוער במלוא תפארתו. לא חייבים להשלים עם המונומנט המכוער, אפשר להוריד Launcher ל Java ולעטוף הכל יפה יפה. אני ממליץ על <a href="http://jsmooth.sourceforge.net/" target="_blank">jsmooth</a> (עוד על זה בפוסט נפרד).</p>
<h3>הגדרות ב log4net</h3>
<p>זה נחמד שמותקן ה Chainsaw, אבל לא מספיק. כמו שציינתי, במקור ה Chainsaw מגיע מעולם ה Java, וזה אומר שהוא מצפה לקרוא את ההודעות בפורמט של log4j. אז כדי שה log4net יוציא הודעות כאלו, צריך לשנות קצת את ההגדרות. אם נתייחס לדוגמה מהפוסט הקודם, אז נשנה את קובץ ה config באופן הבא:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;log4net<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;appender</span> <span class="re0">name</span>=<span class="st0">&quot;WowItsTheLog4jFileAppender&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Appender.FileAppender&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;file</span> <span class="re0">value</span>=<span class="st0">&quot;mylog.txt&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;appendToFile</span> <span class="re0">value</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;layout</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Layout.XmlLayoutSchemaLog4j&quot;</span> <span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;locationInfo</span> <span class="re0">value</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/layout<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/appender<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; <span class="sc3"><span class="re1">&lt;root<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;level</span> <span class="re0">value</span>=<span class="st0">&quot;DEBUG&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;appender-ref</span> <span class="re0">ref</span>=<span class="st0">&quot;WowItsTheLog4jFileAppender&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/root<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/log4net<span class="re2">&gt;</span></span></span></div>
</div>
<p>לפני שנחזור ל Chainsaw, נכתוב תוכנית קטנה ש&quot;עובדת קשה&quot; ונותנת הודעות ללוג מכל מיני classים ובת'רדים שונים, כולל exceptions ייזומים. בקיצור, תוכנית שעושה שמח. אני לא ארשום כאן את הקוד של התוכנית, כי זה לא מה שמעניין. מה שמעניין זה איך התוכנית כותבת ללוג ואיך משתמשים ב Chainsaw כדי לצפות בהודעות שמתקבלות. בכל מקרה, <a href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/Log4NetDemo.zip">התוכנית מצורפת</a> כולל כל ה source.</p>
<h3>עובדים עם Chainsaw &#8211; למנסרים הידד</h3>
<p>עכשיו נחזור ל Chainsaw שלנו. התוכנית שלנו שמרה את הודעות הלוג בקובץ. פשוט נגרור אותו לתוך ה Chainsaw, ואחרי כמה שניות טובות (תלוי כמה המחשב שלכם סוחב Java), הכל נפתח ומוצג. קודם כל, צריך להתרגל קצת <a rel="lightbox[chainsaw-main]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/chainsaw-screenshot.png">למסך הראשי</a>. החלק העיקרי מציג את הודעות הלוג עצמן, עם עמודות מתאימות. העץ שמשמאל מתאר את היררכיית הלוגרים בקונטקסט הנוכחי. לצערנו, גם הלוגרים של ה Chainsaw עצמו מוצגים שם <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />  אלא מה, אפשר להעביר את הפוקוס ללוגר הרצוי, ואז יוצגו רק ההודעות הרלוונטיות במסך הראשי.</p>
<p>כדי לבצע שאילתות על ההודעות המוצגות, צריך להשתמש בתחביר של מנוע השאילתות של Chainsaw, ולהקליד באזור של Refine focus on. נטעם קצת ע&quot;י דוגמאות:</p>
<div class="ron">
<table class="border1">
<tbody>
<tr>
<td class="my_english">MSG ~= 'email'</td>
<td class="my_hebrew">מציג רק את ההודעות שמכילות את המילה email</td>
</tr>
<tr>
<td class="my_english">MSG ~= 'email' &amp;&amp; LOGGER ~= 'sender'</td>
<td class="my_hebrew">רק הודעות שמכילות את המילה email ששם הלוגר שלהן מכיל את המילה sender</td>
</tr>
<tr>
<td class="my_english">MSG ~= 'go' || MSG ~= 'before'</td>
<td class="my_hebrew">מציג הודעות שמכילות את המילה go ו/או הודעות שמכילות את המילה before</td>
</tr>
<tr>
<td class="my_english">( LOGGER == 'mylogger' &amp;&amp; MSG ~= 'cat' ) || ( THREAD == 1234 )</td>
<td class="my_hebrew">מציג הודעותשהגיעו מת'רד מספר 1234 ו/או הודעות שמכילות את המילה cat שהגיעו מלוגר שנקרא mylogger</td>
</tr>
<tr>
<td class="my_english">PROP.log4jid &gt;= 400</td>
<td class="my_hebrew">מציג את כל ההודעות החל משורה 400</td>
</tr>
<tr>
<td class="my_english">LEVEL &gt;= 'warn'</td>
<td class="my_hebrew">מציג רק הודעות מסוג Warn או גבוה ממנו (למשל Error יוצג, אבל Info לא יוצג)</td>
</tr>
</tbody>
</table>
</div>
<p>שימו לב שיש רווח לפני ואחרי פתח/סגור סוגריים וכן לפני/אחרי אופרטורים וכד'. בקיצור, צריך רווחים, וה Chainsaw לא סולח ולא שוכח. אם משהו בתחביר השאילתה לא תקין, ה Chainsaw פשוט מתעלם ממנה, ולא מציג שום הודעת שגיאה. כזה הוא, לא משהו ביחס למשתמשים. שיהיה.</p>
<h3>קבלת הודעות ב UDP</h3>
<p>ב Chainsaw, כמו גם ב viewerים אחרים, יש אפשרות של קבלת הודעות לוג באמצעות תקשורת TCP וכן UDP. כלומר, כמו שה log4net כותב הודעות לוג לקובץ, הוא יכול לשלוח אותם בפרוטוקול TCP או UDP לאן שנרצה. וככה אפשר לצפות בהודעות תוך כדי ריצה של כמה תוכנות במקביל. כשעובדים בסביבה מבוזרת זה פיצ'ר מאוד חזק. אגב, ב UDP לא ניתן לשלוח הודעות לוג ארוכות. מה לעשות, ככה זה.</p>
<p>אז איך?</p>
<p>1. בכל תוכנה רלוונטית, מגדירים ב log4net שליחת הודעות לוג ב UDP:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;appender</span> <span class="re0">name</span>=<span class="st0">&quot;HeyLetsGoWithUdp&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Appender.UdpAppender&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;remoteAddress</span> <span class="re0">value</span>=<span class="st0">&quot;localhost&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;remotePort</span> <span class="re0">value</span>=<span class="st0">&quot;48899&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;layout</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Layout.XmlLayoutSchemaLog4j&quot;</span> <span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;locationInfo</span> <span class="re0">value</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/layout<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/appender<span class="re2">&gt;</span></span></span></div>
</div>
<p>2. מגדירים receiver ב Chainsaw שיאזין להודעות ב UDP באותו פורט שהגדרנו קודם. התמונות הבאות מסבירות את זה:</p>
<table style="border: 0pt none;" >
<tbody>
<tr>
<td style="border: 0pt none ; text-align: center;"><a class="lightbox" rel="lightbox[udp-screenshots]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/udp-create-1.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/udp-create-1-thumb.png" alt="" /></a>
</td>
<td style="border: 0pt none ; text-align: center;"><a class="lightbox" rel="lightbox[udp-screenshots]" href="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/udp-create-2.png"><img src="http://heblog.ronklein.co.il/wp-content/uploads/2009/12/udp-create-2-thumb.png" alt="" /></a>
</td>
</tr>
<tr>
<td style="border: 0pt none ; text-align: center;" align="center" >מוסיפים
</td>
<td style="border: 0pt none ; text-align: center;" align="center" >ומגדירים
</td>
</tr>
</tbody>
</table>
<p>זהו.</p>
<h3>ועוד כמה דברים על ה Chainsaw</h3>
<p>הסקירה כאן היא רק ברמה של היכרות, ויש עוד כמה דברים חביבים ב Chainsaw הפרחח:</p>
<p>אפשר לצבוע שורות לפי אותו מנוע שאילתות, כולל תיעדוף צביעה (במידה שאותה שורה עונה על שני תנאי צביעה שונים). זה פיצ'ר קצת חבוי, אבל מגיעים אליו די מהר.</p>
<p>ניתן לבצע Find</p>
<p>אפשר למיין את ההודעות (המיון הדיפולטי הוא סדר ההודעות כפי שנרשמו ללוג או כפי שהתקבלו ע&quot;י ה Chainsaw, וזה לא בהכרח ה Timestamp שלהן)</p>
<p>הגדרות &#8211; מציע לכם לשנות בהגדרות שה Cyclic buffer size יהיה, נניח, 50000. ובאותו מקום אפשר גם להסיר את הסימון מ Confirm Exit.</p>
<p>ה Chainsaw יכול להיתקע בגלל מחסור בזכרון. כדי להתגבר על זה, רצוי להגדיר בקובץ bat הקצאת זיכרון גדולה יותר. פשוט להוסיף את הטקסט <span style="unicode-bidi: bidi-override; direction: ltr;">-Xms32m -Xmx1024m</span> אחרי ה java. כך שהתוצאה היא</p>
<div class="codesnip-container" >
<div class="dos codesnip" style="font-family:monospace;">java -Xms32m -Xmx1024m -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger -classpath jakarta-oro-2.0.6.jar;jmdns.jar;log4j-1.3alpha-7.jar;log4j-chainsaw-2.0alpha-1.jar;log4j-optional-1.3alpha-7.jar;log4j-oro-1.3alpha-7.jar;log4j-smtp-1.3alpha-7.jar;log4j-xml-1.3alpha-7.jar;log4j-zeroconf.jar;xstream-1.1.2.jar org.apache.log4j.chainsaw.LogUI</div>
</div>
<h2>סיכום</h2>
<p>זהו, עד כאן לענייני Chainsaw ו log4net. יש, כמובן, כלים נוספים, ויש תשתיות לוג כאלו ואחרות (יש למשל את <a title="SmartInspect by Gurock Software" href="http://www.gurock.com/smartinspect/" target="_blank">SmartInspect</a> &#8211; אני לא מת על הקונספט שלהם, כי זה להכניס business logic לתוך תשתית הלוג, אבל שווה בדיקה). אני לא מתיימר לקבוע ש log4net טובה יותר מתשתיות אחרות. אבל אני כן חושב ש log4net היא תשתית מצויינת ללוג, עושה את העבודה בצורה טובה, מאפשרת הגדרות מתקדמות כמו סינונים, ומאפשרת הרחבות. בנוסף לכל, log4net היא open source, וזה אומר שגם אם יש באג, אפשר בקלות להכנס לקוד ולראות מה קורה גם בפנים. כדי לצפות בתוצרי הלוג אני משתמש ב Chainsaw, שהוא כלי מצוין לחתכים ולשאילתות, אבל מצריך קצת סבלנות בעבודה.</p>
<p>אם יש להשיג viewer טוב יותר ל log4net &#8211; תנו לי פינג.</p>
<p>ועד אז, לגלוג נעים!</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2009/12/log4net-part3/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>&#8235;log4net &#8211; המדריך למלגלג (חלק 2 &#8211; הגדרות וקוד)&#8236;</title>		<link>http://heblog.ronklein.co.il/2009/10/log4net-part2/</link>
		<comments>http://heblog.ronklein.co.il/2009/10/log4net-part2/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 20:36:40 +0000</pubDate>
		<dc:creator>&#8235;ronklein&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[log4net]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=48</guid>
		<description><![CDATA[&#8235;הרעיון של הפוסט הזה הוא פשוט: מעין cookbook שמסביר איך להתחיל עם log4net מההתחלה, מתוך הנחה שכבר יש לכם Visual Studio 2005 ומעלה (או כל IDE אחר לפיתוח בדוט נט בגירסה 2.0 ומעלה)
אז מה יהיה לנו:

הורדה של log4net
דוגמה פשוטה של כתיבה ללוג באמצעות log4net ע&#34;י שמירה לקובץ טקסט
כתיבה של exception
ומה עוד?

מת-חי-לים!
הורדה והתקנה של log4net
דבר ראשון [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>הרעיון של הפוסט הזה הוא פשוט: מעין cookbook שמסביר איך להתחיל עם log4net מההתחלה, מתוך הנחה שכבר יש לכם Visual Studio 2005 ומעלה (או כל IDE אחר לפיתוח בדוט נט בגירסה 2.0 ומעלה)</p>
<p>אז מה יהיה לנו:</p>
<ul>
<li>הורדה של log4net</li>
<li>דוגמה פשוטה של כתיבה ללוג באמצעות log4net ע&quot;י שמירה לקובץ טקסט</li>
<li>כתיבה של exception</li>
<li>ומה עוד?</li>
</ul>
<p>מת-חי-לים!</p>
<h3>הורדה והתקנה של log4net</h3>
<p>דבר ראשון &#8211; ההורדה של log4net &#8211; כדי להוריד את גירסה 1.2.10 אפשר פשוט ללחוץ <a title="log4net version 1.2.10" href="http://archive.apache.org/dist/incubator/log4net/1.2.10/incubating-log4net-1.2.10.zip">כאן</a>. לפרטים נוספים &#8211; <a href="http://logging.apache.org/log4net/download.html" target="_blank">כאן</a> תמצאו את דף ההורדות של log4net ב Apache.</p>
<p>הורדתם? יופי. עכשיו לעשות unzip לתיקיה חביבה (שתשרת אתכם די הרבה). נניח C:\<a title="Open Source Software - Wiki" href="http://en.wikipedia.org/wiki/Open_source_software" target="_blank">oss</a>\log4net.</p>
<h3>תוכנית ראשונה עם log4net</h3>
<p>נמשיך:</p>
<p>ניצור פרוייקט פשוט ב VS, נניח Console Application, ונכתוב בו את ה hello world המפורסם:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">static</span> <span class="kw1">void</span> Main<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;Hello world&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; Console.<span class="me1">ReadLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>עכשיו נכניס פנימה שירותי logging ע&quot;י log4net:</p>
<p>1. נוסיף רפרנס ל log4net תוך שימוש בתיקיה ההיא, לנתיב bin\net\2.0\release\log4net.dll</p>
<p>2. כדי להגדיר את log4net דרך קובץ חיצוני (ולא דרך קוד):</p>
<p>א. נוסיף קובץ app.config (מה שנקרא &quot;Application Configuration File&quot;)</p>
<p>ב. נערוך את ה app.config באופן הבא:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;configuration<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;configSections<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;log4net&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;System.Configuration.IgnoreSectionHandler&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/configSections<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;log4net<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;appender</span> <span class="re0">name</span>=<span class="st0">&quot;OhMyGodItsTheFileAppender&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Appender.FileAppender&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;file</span> <span class="re0">value</span>=<span class="st0">&quot;mylog.txt&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;appendToFile</span> <span class="re0">value</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;layout</span> <span class="re0">type</span>=<span class="st0">&quot;log4net.Layout.PatternLayout&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;conversionPattern</span> <span class="re0">value</span>=<span class="st0">&quot;%date [%thread] %-5level %logger [%property{NDC}] &#8211; %message%newline&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/layout<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/appender<span class="re2">&gt;</span></span></span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;root<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;level</span> <span class="re0">value</span>=<span class="st0">&quot;DEBUG&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;appender-ref</span> <span class="re0">ref</span>=<span class="st0">&quot;OhMyGodItsTheFileAppender&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/root<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/log4net<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/configuration<span class="re2">&gt;</span></span></span></div>
</div>
<p>3. כדי ש log4net יתחיל לעבוד ויצא מתרדמת החורף שלו, צריך איזה טריגר שיעיר אותו. אפשר לעשות את זה דרך הקוד, ואפשר בצורה קצת יותר שקופה, ע&quot;י שימוש בקובץ די ביישן בשם AssemblyInfo.cs. זה קובץ שנמצא מתחת ל Properties. שם צריך להוסיף את השורה הבאה (אחרי כל ה using שיש שם, במיקום כלשהו):</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="br0">&#91;</span>assembly<span class="sy0">:</span> log4net.<span class="me1">Config</span>.<span class="me1">XmlConfigurator</span><span class="br0">&#40;</span>Watch <span class="sy0">=</span> <span class="kw1">true</span><span class="br0">&#41;</span><span class="br0">&#93;</span></div>
</div>
<p>4. עכשיו, כדי לכתוב ללוג, אנחנו צריכים להשתמש באיזה אובייקט שיתן לנו את שירותי ה logging. את זה עושים, למשל, ע&quot;י הוספת שדה סטטי ל class שלנו (ולכל class שבו נצטרך logging):</p>
<p>א. להוסיף בחלק של ה using את שני הבחורים הבאים (אם אינם):</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">using</span> <span class="co3">System.Reflection</span><span class="sy0">;</span><br />
<span class="kw1">using</span> <span class="co3">log4net</span><span class="sy0">;</span></div>
</div>
<p>ב. להוסיף את השדה הסטטי עצמו:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">private</span> <span class="kw1">static</span> <span class="kw1">readonly</span> ILog Logger <span class="sy0">=</span> LogManager.<span class="me1">GetLogger</span><span class="br0">&#40;</span>MethodBase.<span class="me1">GetCurrentMethod</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">DeclaringType</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>זהו, עכשיו אפשר להשתמש ב logger שלנו. הפעולות 1-3 הנ&quot;ל הן פעולות חד פעמיות לפרויקט שלנו. פעולה מספר 4 חוזרת על עצמה בכל class בפרויקט. הנה קצת תוספות לקוד:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">static</span> <span class="kw1">void</span> Main<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; Logger.<span class="me1">Debug</span><span class="br0">&#40;</span><span class="st0">&quot;starting up&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;Hello world&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; Logger.<span class="me1">Debug</span><span class="br0">&#40;</span><span class="st0">&quot;done&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; Console.<span class="me1">ReadLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>נריץ את הפרויקט. ונראה את ה hello world הידוע לשמצה. ואיפה כל ההודעות שרשמנו ללוג? הן נמצאות בתוך הקובץ mylog.txt, שנמצא במיקום של ה exe של הפרוייקט שלנו: בד&quot;כ בנתיב bin\debug או bin\release. אפשר לשנות את שם הקובץ mylog.txt לכל שם אחר. ויש עוד הרבה הגדרות, לא לדאוג&#8230;</p>
<p>בשלב זה יש לנו תוכנית עם logger, שמבצעת כתיבות ללוג, שלמעשה נשמרות לקובץ. <strong>זה הבסיס ל-log4net</strong>. זה המתכון, אם תרצו, להוספת log4net לפרוייקט שלכם בצורה יחסית פשוטה ופורטבילית.</p>
<h3>כתיבת exception ללוג</h3>
<p>לכתוב exception ללוג זה לא סיפור גדול: זה כמעט אותו הדבר כמו כתיבה רגילה, רק משתמשים בחתימה שכוללת אובייקט מסוג Exception. מן הסתם, זה יהיה בתוך try/catch. הנה דוגמה קטנה:</p>
<div class="codesnip-container" >
<div class="csharp codesnip" style="font-family:monospace;"><span class="kw1">static</span> <span class="kw1">void</span> Main<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; Logger.<span class="me1">Debug</span><span class="br0">&#40;</span><span class="st0">&quot;starting up&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="kw4">string</span> fileName <span class="sy0">=</span> <span class="st0">&quot;file-does-not-exist.txt&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">string</span> contents <span class="sy0">=</span> <span class="kw5">System.<span class="me1">IO</span></span>.<span class="me1">File</span>.<span class="me1">ReadAllText</span><span class="br0">&#40;</span>fileName<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; <span class="kw1">catch</span> <span class="br0">&#40;</span>Exception ex<span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; Logger.<span class="me1">Error</span><span class="br0">&#40;</span><span class="st0">&quot;cannot read contents of file &quot;</span> <span class="sy0">+</span> fileName, ex<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; Console.<span class="me1">WriteLine</span><span class="br0">&#40;</span><span class="st0">&quot;oops, an error occured. see log for details&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span></p>
<p>
&nbsp; Logger.<span class="me1">Debug</span><span class="br0">&#40;</span><span class="st0">&quot;done&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; Console.<span class="me1">ReadLine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>מומלץ מאוד להשתמש במתודות עם חתימת ה Exception, כי ה exception נשמר קצת אחרת, וזה מאפשר לבצע חתכים אחרים ולתצוגה שונה דרך ה viewer (בפוסט הבא).</p>
<h3>לאן ממשיכים מכאן</h3>
<p>אפשר לכתוב ל-EventLog. שימו לב שזה דורש הרשאות גבוהות יחסית.</p>
<p>אפשר לכתוב ל-Trace ולעקוב אחריו עם כלים חיצוניים כמו <a href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx" target="_blank">DebugView</a> של SysInternals. זה שקול ל-System.Diagnostics.Trace.WriteLine</p>
<p>ואפשר עוד הרבה דברים, כמו לכתוב ל DB, לכתוב ל TCP, ל UDP, לשלוח מייל ועוד. גשו ל<a href="http://logging.apache.org/log4net/release/config-examples.html" target="_blank">דף הדוגמאות</a> ב Apache ותהנו.</p>
<p>אגב, לפי ההגדרות שבפוסט הזה, אפשר לשנות <strong>בזמן ריצה</strong> את ההגדרות של ה log4net &#8211; וההתנהגות של ה logging תשתנה בהתאם. מאגניביישן.</p>
<p>לסיכום, זה פוסט שכל המטרה שלו היא לתת מתכון פשוט לשימוש ב log4net. בפוסט הבא נראה איך אפשר לנתח את הלוגים, ע&quot;י viewer כמו Chainsaw.</p>
<p>לגלגו ותהנו <img src='http://heblog.ronklein.co.il/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><a href="http://www.ronklein.co.il/qwe/wp-content/uploads/2009/10/example.zip">פרויקט דוגמה</a></p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2009/10/log4net-part2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8235;log4net &#8211; המדריך למלגלג (חלק 1 &#8211; מבוא)&#8236;</title>		<link>http://heblog.ronklein.co.il/2009/10/log4net-part1/</link>
		<comments>http://heblog.ronklein.co.il/2009/10/log4net-part1/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 20:05:20 +0000</pubDate>
		<dc:creator>&#8235;ronklein&#8236;</dc:creator>				<category><![CDATA[תכנות]]></category>
		<category><![CDATA[log4net]]></category>

		<guid isPermaLink="false">http://heblog.ronklein.co.il/?p=40</guid>
		<description><![CDATA[&#8235;בפוסט הזה:

מבוא
למה בכלל לכתוב ללוג?
סוגי הודעות לפי רמות חוּמרה
מה כותבים ללוג

מבוא
חלק בלתי נפרד מאפליקציה רצינית הוא הלוג &#8211; שירות שמאפשר כתיבת הודעות.
בזמן שהאפליקציה חיה ונושמת היא יכולה לכתוב הודעות שונות ללוג. ההודעות יכולות להיות בסגנון &#34;עכשיו מתבצע כך וכך&#34; או &#34;יש כאן שגיאה לא צפויה&#34;.
הלוג עצמו יכול להישמר כקובץ, או קבצים, או כרשומות ב DB.
או [...]&#8236;]]></description>			<content:encoded><![CDATA[<div dir="rtl"><p>בפוסט הזה:</p>
<ul>
<li>מבוא</li>
<li>למה בכלל לכתוב ללוג?</li>
<li>סוגי הודעות לפי רמות חוּמרה</li>
<li>מה כותבים ללוג</li>
</ul>
<h2>מבוא</h2>
<p>חלק בלתי נפרד מאפליקציה רצינית הוא הלוג &#8211; שירות שמאפשר כתיבת הודעות.<br />
בזמן שהאפליקציה חיה ונושמת היא יכולה לכתוב הודעות שונות ללוג. ההודעות יכולות להיות בסגנון &quot;עכשיו מתבצע כך וכך&quot; או &quot;יש כאן שגיאה לא צפויה&quot;.<br />
הלוג עצמו יכול להישמר כקובץ, או קבצים, או כרשומות ב DB.<br />
או שהלוג יכול לא להישמר כלל, אלא רק סוג של Console.WriteLine או Debug.WriteLine או Trace.WriteLine.<br />
או שהלוג שולח את ההודעות באמצעות TCP או UDP למקום אחר.<br />
או שהלוג שולח מייל למישהו&#8230;<br />
בקיצור, יש את העניין של לכתוב ללוג (&quot;יש כאן שגיאה לא צפויה&quot;), ויש את העניין של מה תהיה התוצאה של הכתיבה ללוג (ההודעות נשמרות/מוצגות וכד').<br />
בנוסף לכל זה, גם אם כתבנו ללוג והכל טוב ויפה, נרצה אח&quot;כ גם לצפות בתוצאה, ולעשות חיתוכים שונים. במילים אחרות, נרצה איזה Viewer &#8211; תוכנה נורמלית עם UI חביב שתאפשר לנו את התצוגה והחיתוכים.<br />
אה, ועוד משהו. נרצה גם לוג מספיק חכם כך שאם נרצה לשנות את ההגדרות שלו לא נצטרך להוריד את האפליקציה ולטעון אותה מחדש.</p>
<p>אז מה היה לנו: הודעות ללוג ואיך הן &quot;נכתבות&quot;, תוכנת viewer, טעינה חכמה אחרי שינוי ההגדרות.<br />
כל זה ניתן למימוש בקלות עם log4net &#8211; תשתית מוכחת ועובדת ללוג, שהיא open source. אבל לפני הכל, עוד קצת מבוא.</p>
<h2>למה בכלל לכתוב ללוג?</h2>
<p>שאלה טובה.</p>
<p>לא חייבים.</p>
<p>אבל הנסיון שלי מראה שכתיבה מושכלת ללוג מאפשרת למפתחים להבין באגים (ולפתור אותם) מהר יותר, בהשפעה אפסית על הביצועים.</p>
<p>בנוסף, קהל היעד של הלוג הוא לא רק מפתחים. גם אנשי IT או אנשים שמתחזקים את האפליקציה יכולים להעזר בו.</p>
<p>בשורה התחתונה, כתיבה ללוג היא גם כדי לוודא שהאפליקציה עובדת כמצופה וגם כדי לתעד מצבים לא תקינים ואת אפשרויות הטיפול בהם.</p>
<h2>סוגי הודעות לפי רמות חוּמרה</h2>
<p>רגע לפני שמתחילים, כמה מילים על ההודעות השונות שאנחנו מכניסים ללוג.</p>
<p>ב log4net, ולא רק שם, ההודעות ללוג מתחלקות לסוגים הבאים:</p>
<ul>
<li>Debug</li>
<li>Info</li>
<li>Warn</li>
<li>Error</li>
<li>Fatal</li>
</ul>
<p>נרחיב קצת&#8230;</p>
<p>הודעות Debug (ורק הן) מיועדות למפתחים עצמם, ואפשר להשתולל איתן כמה שרוצים. כפי שנראה מאוחר יותר, אפשר לשנות את ההגדרות כך ש log4net יתעלם מהן לחלוטין. בד&quot;כ כותבים ל Debug הודעות כמו &quot;עכשיו לפני פתיחת חיבור ל DB&quot; ו&quot;התחברתי בהצלחה ל DB&quot; וכו'. בקיצור, אבני דרך למפתחים עצמם.</p>
<p>הודעות Info מכילות מידע מתומצת על המצב של האפליקציה, שהוא בחזקת &quot;טוב לדעת&quot;. לדוגמה, כמעט כל service (או console שמדמה service) שכתבתי בדוט נט קורא את הקונפיגורציה ומיד אח&quot;כ כותב הודעת info ללוג בנוסח &quot;שירות xyz עלה בהצלחה עם ההגדרות הבאות: &#8230;&quot;.</p>
<p>הודעות Warn מתייחסות למקרים שבהם האפליקציה נתקלה ב exception או במצב לא תקין, אבל היא יודעת להתאושש ממנו. למשל, המערכת שלנו לא מצליחה להוציא מייל כרגע. לא נורא, היא תנסה שוב עוד דקה.</p>
<p>הודעות Error מתייחסות למקרים שבהם האפליקציה נתקלת ב exception או במצב לא תקין והיא לא יודעת להתאושש ממנו. זה יכול להשפיע רק על המשתמש הנוכחי (נניח אם זו אפליקציית web) וזה יכול להיות משהו יותר תשתיתי.</p>
<p>הודעות Fatal מתייחסות למקרי קצה שבהן האפליקציה שלנו לא יכולה להתאושש ממשהו לא תקין וכדאי שמישהו יסדר את זה בהקדם האפשרי. כלומר יש כאן גם הנחיה לגבי ניתוח הלוג וטיפול בשגיאות. הודעות Fatal צריכות להיות בודדות כדי לא ליצור מצב של &quot;זאב-זאב&quot;.</p>
<h2>מה כותבים ללוג</h2>
<p>אם אתם לוקחים אתכם משהו מהפוסט הזה &#8211; קחו את זה: לא רק כותבים ללוג &quot;היתה כאן שגיאה&quot; ומצרפים את האובייקט של ה exception. <strong>כותבים את כל הקונטקסט הרלוונטי כדי שאח&quot;כ נוכל להבין טוב יותר מה קרה</strong>. למשל &quot;לא הצלחתי לקרוא את התוכן של הקובץ X כאשר הבקשה היתה Y&quot; בצירוף ה exception. כן, זה לוקח עוד דקה, אבל זה כל כך שווה את זה.</p>
<p>אלא שלפעמים, מטעמי security או privacy לא כדאי לכתוב <strong>ממש</strong> הכל. למשל, &quot;לא הצלחתי להתחבר ל SQL Server שנמצא בכתובת X עם שם משתמש U וסיסמה P&quot; נשמע לי רעיון לא טוב, כי זה חושף את פרטי ההתחברות ל DB כולל הסיסמה. אפשר אולי במקום לכתוב את הסיסמה לכתוב את ה hash שלה לפי הדוט נט (GetHashCode), או לפי סטנדרט חזק יותר כמו MD5, כאשר כותבים את ערך ה hash ב base64 (וגם אז, אפשר לכתוב רק את N התוים הראשונים מטעמי חסכון ונוחות קריאה).</p>
<p>זהו, עד כאן המבוא. בפוסטים הבאים &#8211; איך משתמשים ב log4net כדי לכתוב ללוג, איזה viewer-ים קיימים ועוד.</p>
</div>]]></content:encoded>			<wfw:commentRss>http://heblog.ronklein.co.il/2009/10/log4net-part1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
