Sunday, September 13, 2015

עבודה שחורה

Working in the dirt

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

בנוסף, יצא שסיימתי לכתוב את הפוסט כמה דקות לפני כניסת ראש השנה - שנה טובה לכולם!

--------------------------

I assume that every software tester has faced here and there the following situation: Sometime you stumble upon a bug. it might be related to what you were currently testing, or it might not be, at any rate - it is something important enough to invest some time in investigating it. It turns out to be a bit complicated, but once you understand what has caused this to happen you can hear yourself saying "I would have never *intentionally* try testing this scenario!"
Such a case happened to me (again) this week - I was going over some changes in a rather simple part in our over-complicated system: it reads a line from a table in our database, formats it nicely and sends it to a designated server. couldn't be simpler, right?
As it happens, we have one problem with this process - it's not fast enough. It works kind of o.k. under the normal state of affairs, but if for some reason, this process was down for a while, or we have a busy day, this process has a hard time catching up. So, what do you do when you want something to work faster? The easiest answer is - you multi-thread and hope it works. One of our developers took up the task, and after several attempts came up with a nice idea - each thread will "lock" a time window and handle all the work that should be done there.
In the process of getting to this solution, we went through another one that didn't quite work as we hoped, and by the time we got to this implementation we were already working on this task for three weeks instead of the planned 3 or 4 days we assumed the original fix would take us. And, as every new implementation is, this one didn't work perfectly the first time (including a cute OBOB), so after toying with this for a month or so, we finally ditched it for higher priority items. When we got back to this feature after over a month of dealing with those higher priories, I noticed that the automation checking this is failing. Three days later we found the issue - apparently, I had some junk in my database that caused the time-window locking mechanism to fail, sending the process to sleep for a day.
Now, in retrospect, I think there were some ways I could go hunting specifically for this type of bug. However, the locking mechanism was not the priority target of my tests (I was more interested in the potential throughput), it was tested before and seemed reliable enough at the time, so I did not invest too much effort on checking every edge case. I got lucky.
The way I got lucky sent me thinking:  When I made my first steps in the testing world, I learned that at least in theory, each "test case", and especially those automated scenarios, has three steps - setup, where all the necessary preparations are being done, the actual test case, and then cleanup - where the test makes sure it will not affect other tests running after it. However, I stumbled across my bug when not cleaning it, and had I cleaned my data properly, I would not have found the bug at all.
So, I probably need to think about it a bit to understand how to implement it, but I rather like the idea of working in a "dirty" environment, after all - while a clean environment sure helps a lot in debugging, your production system won't run in sterile conditions, so why not test it with dirty data?, you might be able to find some interesting stuff.

And, is it happens, I finish writing just as the Jewish new year is approaching,
Have a great year!

No comments:

Post a Comment