اشکال زدایی اردکی

به عنوان یک برنامه‌نویس حتماً تا حالا در موقعیتی بوده‌اید که به باگی در برنامه برخورد کرده‌اید که اصلاً و ابداً نمی‌فهمید چرا چنین باگی وجود دارد. چون بارها و بارها برنامه را چک کرده و دلیلش را نفهمیده‌اید. در واقع چندین ساعت وقت گذاشته‌اید ولی ذهنتان به هیچ جایی نمی‌رسد. معمولاً هم علت این جور باگ‌ها خیلی ساده است و پیدا کردن آن مجدداً شخص را عصبانی می‌کند چرا که چنین مورد ساده‌ای وقت او را کلی تلف کرده است.

افراد راه حل‌های مختلفی برای این طور مواقع دارند. مثلاً بعضی‌ها به پیاده روی می‌روند، بعضی‌ها کار را تعطیل می‌کنند و به منزل بر می‌گردند، بعضی‌ها دوش می‌گیرند و… اما یک راه حل جالب دیگر وجود دارد: اشکال زدایی اردکی.

در این روش برنامه‌نویس یک اردک پلاستیکی (اسباب بازی) را روی میز گذاشته و تک تک خطوط برنامه را برایش توضیح می‌دهد. به این ترتیب امکان پیدا کردن خطا خیلی بالاتر می‌رود. تجربه نشان داده که توضیح دادن کامل برنامه به یک نفر دیگر می‌توان در پیدا کردن زودتر باگ موثر باشد. نام دیگر این روش «بلند فکر کردن» است.

‫‫‫‫داستان بی‌سوادی ما – ۴: Visual Studio Debugging

یکی از جاهایی که کار می‌کردم دو تا Solution خیلی بزرگ داشتیم. اولی که ۶۴ تا پروژه‌ی ویژوال استودیو بود که همگی تبدیل به dll می‌شدند و دومی که یک پروژه‌ی وب حجیم بود با چیزی بالای ۶۰۰ صفحه aspx. بعضی وقت‌ها که ایرادی پیش می‌آمد مجبور می‌شدم Solution اول را روی کامپیوتر خودم Build کنم، dllهایش را به Solution دوم اضافه کنم، Solution دوم را در حالت Debug بالا بیاورم، آن صفحه‌ای را که مشکل را داشت را باز کنم، روی آن خطی که dllهای Solution اول را صدا می‌زد Break Point بگذارم و هر وقت که اجرای برنامه به آن خط می‌رسید آنقدر F11 می‌زدم و از کلاس‌ها و متودهای مختلف رد می‌شدم تا به آنجایی که تازه می‌خواستم وجود یا عدم وجود ایراد را بررسی کنم برسم. این پروسه خودش در بهترین حالت ۲۰ دقیقه طول می‌کشید تازه بعضی وقت‌ها علت خطا را پیدا کرده و درست می‌کردم و می‌خواستم دوباره آن را امتحان کنم، این خودش یعنی ۲۰ دقیقه‌ی دیگر. حالا خودتان حساب کنید بعضی روزها که می‌افتادیم روی دنده‌ی Debug، چقدر باید وقتمان تلف می‌شد.

چند بار سعی کرده بودم این پروسه را با فراخوانی dllها در یک برنامه‌ی ویندوزی آزمایشی، حذف موقتی بعضی صفحات کم استفاده‌ی Solution دوم، استفاده از Unit Test، استفاده از logging و… کوتاه‌تر و بهینه‌تر کنم اما چندان موفق نبودم. چون به هر صورت بعضی چیزها را فقط در خود پروژه‌ی وب می‌توانستم Debug کنم. متاسفانه این بعضی چیزها خیلی کم تعداد نبودند و همیشه روی اعصاب من و بقیه راه می‌رفتند تا آنجا که بعضی وقت‌ها درخواست‌های Debug یک بخش را کلاً بی‌خیال شده و آن بخش را مجدداً بازنویسی می‌کردم یا این که ایرادهایی را که می‌دانستم قطعاً وجود دارند را مدام پشت گوش می‌انداختم چون واقعاً اعصاب و وقت دیباگ همچون پروژه‌ی حجیمی را نداشتم.

البته تا اینجای کار فقط یک حالت مشکل را شنیدید. حالت دیگر آن وقتی است که امکان استفاده از Break Point را ندارید و اصلاً نمی‌توانید Debug کنید. مثل وقتی که یک عملیاتی از قبیل Data Binding یا به روز رسانی اطلاعات از طریق کدهای Markup یا Declarative صفحات aspx انجام می‌شود.

این مشکلات چند سال است که گریبان‌گیر من است و من دیگر وجود آن را قبول کرده بودم تا این چند وقت پیش با یک ور رفتن کوچولو با StackOverflow فهمیدم که چقدر تا حالا وقتم بیهوده تلف می‌شده است. چون می‌توانستم به راحتی آب خوردن از گزینه Attach to Process ویژوال استودیو برای این کار استفاده کنم بدون آن که این همه وقتم تلف شود.

روش کار بدین صورت است که اول آن Solution وبی را باز می‌کنید و بدون حالت Debug به اجرا در می‌آورید. بعد Solution حاوی dllها را باز کرده و مطمئن شوید که به غیر از فایل‌های dll، فایل‌های pdb را هم دارید. البته اگر ندارید نگران نباشید. این فایل‌ها با یک بار Build به طور خودکار ساخته می‌شوند. قدم بعدی انتخاب گزینه‌ی Attach to Process از منوی Debug ویژوال استودیویی است که Solution حاوی dllها در آن باز است. حالا از فهرست پیش رو، process مربوط به ASP.NET Web Development Server را که معمولاً اسمش با WebDev شروع می‌شود را انتخاب نمایید. در این لحظه ویژوال استودیو خود به خود به حالت Debug می‌رود. شما می‌توانید هر جا که خواستید Break Point بگذارید. اگر به آن صفحه‌ای که نهایتاً آن کد را اجرا می‌کند بروید، می‌بینید که ویژوال استودیوی حاوی dll در محل Break Point انتخابی شما آماده دریافت F10 و F11 است. به همین سادگی! این کار حتی در مورد کدهایی هم که به طور مستقیم از markup صدا زده می‌شوند نیز قابل انجام است.

به عنوان سورپریز این قضیه را داشته باشید که می‌توانید عین همین کار را بدون اجرا کردن پروژه‌ی وبی از طریق ویژوال استودیوی اول هم انجام دهید البته به شرطی که همان پروژه را در IIS کامپیوترتان داشته باشید. روش کار به این صورت است که در بخش Attach to Process به جای Web Development Server از process مربوط به IIS که اسمش در ویندوز دو هزار و هشت w3wp است استفاده کنید.

سورپریز دومی هم وجود دارد. می‌توانید به جای استفاده از IIS کامپیوتر خودتان از IIS دیگر کامپیوترها هم استفاده کنید. یعنی می‌توانید از طریق ویژوال استودیوی کامپیوتر خودتان Web Applicationهایی که در IIS یک کامپیوتر دیگر نصب هستند را Debug کنید. اسم این کار Remote Debugging است.

‫نحوه خطایابی عملیات ارسال/دریافت ایمیل

debug یکی از مشکلاتی که همیشه در آزمایش و راهبری پروتکل ECE به وجود می‌آید مشکلات مربوط به ارسال/دریافت ایمیل است. متاسفانه امکانات اولیه کلاس‌ها و کامپوننت‌های این کار اطلاعات چندان کاملی از خطای رخ داده به دست نمی‌دهند و گاها به یک خطای timed out بسنده می‌کنند. به عنوان مثال به خطای زیر که حاصل اجرای عملیات ارسال ایمیل با کلاس SmtpClient است توجه فرمایید:

(SendingMailException): The operation has timed out.,
(SmtpException): The operation has timed out.,

در این جور مواقع می‌توانید کلیه فعالیت‌های System.Net را زیر نظر بگیرید، شاید که مشکل ارسال/دریافت ایمیل را پیدا کردید. دقت کنید که با انجام این کار هر فعالیتی که بر روی TCP/IP انجام گیرد log شده و حجم فایل log در یک چشم به هم زدن به چندین مگابایت خواهد رسید. علاوه بر این پیدا کردن اطلاعات مورد نظر در این حجم زیاد اطلاعات کار چندان ساده‌ای نیست. در ادامه بخشی از این اطلاعات به عنوان نمونه آمده است:

System.Net.Sockets Verbose: 0 : [2616] Socket#23006966::Send()
System.Net.Sockets Verbose: 0 : [2680] Socket#23006966::Dispose()
System.Net.Sockets Error: 0 : [2616] Exception in the Socket#23006966::Send – A blocking operation was interrupted by a call to WSACancelBlockingCall
System.Net.Sockets Verbose: 0 : [2616] Exiting Socket#23006966::Send()     -> 0#0
System.Net Error: 0 : [2616] Exception in the SmtpClient#49662634::Send – Unable to write data to the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall.

حال برای فعال کردن «خطایابی» در برنامه خودتان کافی است کد زیر را به web.config یا app.config خود اضافه کنید. این کد در بالاترین سطح و درست زیر <configuration> اضافه می‌شود. همان جایی که <appSettings> و <system.web> قرار دارند:

<system.diagnostics>
<
trace autoflush="true" />
<
sources>
<
source name="System.Net" >
<
listeners>
<
add name="MyTraceFile"/>
</
listeners>
</
source>
<
source name="System.Net.Sockets">
<
listeners>
<
add name="MyTraceFile"/>
</
listeners>
</
source>
</
sources>
<
sharedListeners>
<
add
name="MyTraceFile"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="d:usersSystem.Net.trace.log"/>
</
sharedListeners>
<
switches>
<
add name="System.Net" value="Verbose" />
<
add name="System.Net.Sockets" value="Verbose" />
</
switches>
</
system.diagnostics>