פלאנט תוכנה חופשית בישראל (Planet FOSS-IL)

23 אפריל, 2014

ik

anti patterns של מתודולוגיות עבודה

הפוסט המקורי לא הובן כפי שהתכוונתי אליו, ולכן שכתבתי את הפוסט לגרסה הזו.

הקדמה

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

הדגמות

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

כך שימוש בכפית הוא למעשה anti-pattern, היות והוא לא מוביל לאן שאנו רוצים להגיע בדרך הגיונית.

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

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

הדגמה ראשונה:

לפני מספר חודשים, ראיתי הרצאה של אחד מיוצרי go (אינני זוכר בדיוק היכן, את שמה או את שם המרצה), והוא הסביר מדוע הוא הרגיש שהיה צורך ליצור שפה חדשה.
הוא בדק את הגישה הקיימת ב C ו ++C בצורה בה הן מבצעות include, ועשה בדיקה כמה פעמים פרויקט של מליוני שורות קוד עושה מעבר על אותם קבצי ה include, והגיע למצב מדהים: מדובר באלפי מעברים ולפעמים אף יותר !

לעומת זאת יש שפות שבהן מראש זה לא קורה: בשפות כמו פסקל (לא, לא חזרתי אליה) ו go.

בשפות אלו, המעבר הוא חד פעמי בלבד, דבר שלא רק מוריד חלק מבעיות קימפול ש++C למשל חווה, אלא גם ניהול התלויות (שלא לדבר על מהירות קימפול גבוהה יותר), מאפשר להשיג המון כוח. למשל בפסקל וגם בgo נוצר בעצם סוג של namespace. היצירה של namespace מאוד חשובה היות וזו נרשמת פעם אחת בצורה בינארית, ופשוט יש מיפוי לכל המקומות אשר מבקשים להשתמש בקוד עצמו, וכך יש הצבעה לאיזור מוגדר לכל מקום שרוצה להשתמש בקוד שכזה, במקום לכלול אותו בכל פעם מחדש. ועכשיו אין צורך יותר בhack של ifndef ואז define רק בשביל לגרום לקומפיילר לא להוסיף שוב פעם את הקוד. כמו כן, היות וכבר הnamespace נכנס לאיזשהו עץ בקומפיילר, במקום לקרוא שוב את התוכן, פשוט מסמנים שגם בנקודה הזו שהצהרנו שוב על fmt (למשל) צריך להשתמש ב namespace הזה עם שם פונקציה מסויימת, ובכך יש symbol ייחודי עם namespace ושם הפונקציה שנכתבת רק פעם אחת.

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

בשפה PHP הצליחו ליצור עם include עוד סוג של anti-pattern בכך שהם הוסיפו את include_once. למעשה הם זרקו את האחריות על המתכנת, במקום על המפרש, ובכך יצרו מצב שיכול להכניס להרבה מאוד בעיות, בייחוד כאשר לא מבינים עד הסוף מתי יש להשתמש ב include ומתי להשתמש ב include_once.

הדגמה שנייה:

יש החושבים כי פירוש השימוש ב SQL הוא ניהול מידע בעל קשרי גומלין. כלומר, אפשר לנהל קשרי גומלין בין טבלאות שונות בצורה טובה ויעילה.
העניין הוא שזה לא כזה פשוט כמו שזה נשמע.
זו הסיבה ששאילתות join כל כך מסובכות, ויש במסדי נתונים רציניים, גם הרבה סוגים מהם, עם המון משמעויות שונות ומשונות (inner/outer left/right/natural וכיוב'). אם לא מודעים להבדלים הנכונים בין קשרי הגומלין לפי השאילתא (לא לפי כוונת מתכנן הטבלאות, אלא לפי פרשנות מסד הנתונים את השאילתא), המידע לא מגיע בצורה יעילה, אבל יותר חמור, לפעמים הסיבה שהמידע מגיע שגויה, או נראה כאילו אין מידע מתאים, או מגיע מידע, אבל מסיבות לא נכונות, ואז לא תמיד מגלים שזה בעצם שגוי.

זו הסיבה שיש מסדי נתונים אחרים אשר בנויים לגישה נוחה/מתאימה יותר של קשרי גומלין. לא בהכרח no-sql, אבל יכול להיות שכן (אבל זה לא כזה משנה). העניין הוא שהן יוצרות גישה מסוימת המתאימה יותר למה שחשוב לך לבצע.
כך למשל אם יש הרבה מידע היררכי, לפעמים מסד נתונים שהוא בנוי כעץ מתאים יותר.
אם מידע שצריך להישמר פעם אחת אבל אינו שייך לטבלה הראשית, בSQL יהיה צורך ב pivot table, אבל גם כאן, יש מסדי נתונים שבהם עדיין אפשר לשמור את זה כרשומה בודדת ולשנות את התפיסה הזו.

הדגמה שלישית:

לפני מספר שבועות קראתי פוסט מאוד מעניין על כך שבשנות ה70 יצאו 2 ניסויים בעולם התוכנה על הרעיון של איך לבנות עורך טקסט:

בעוד שהלימוד מemacs תפס, הלימוד של vi מעולם לא באמת נלמד כתצורת מימוש של עורכי טקסט.

ברעיון של emacs יש API אשר משמש לביצוע פעולות.
ברעיון של vi, יש הבדל בין תנועה, זיהוי גבולות ופעולות העורך.

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

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

אותה התנהגות קיימת גם להליכה אחורה, ולשם כך משתמשים בתווים b ו B.
גם הן משפיעות על התחלת המילה (התו הראשון של המילה), ולא על סופה.
גם אם אינכם יודעים את ההבדל בין אות גדולה לקטנה של b, עדיין תוכלו לנחש די טוב בזכות ההסבר על w מול W מה התפקיד של כל תו. והנה לכם תבנית ש־קל להבין את המשמעות שלה.

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

כך שאם אנחנו נעמוד בתחילת המילה "הדגמה", ונלחץ על dw הוא ימחק את המילה ובמידה ויש רווח אחריה, אז גם אותו.
במידה ועמדנו באמצע המילה, הוא ימחק מהתו שעליו אנחנו עומדים עד לסוף המילה (כולל הרווח במידה וקיים).

אם נלחץ על dW, הוא יפעל אותו הדבר, אבל ימחק כל תו שהוא לא רווח שנמצא עד המילה הקרובה הבאה.

למחוק אנחנו יודעים כי זו פעולה המתחילה ב"d” (במקרה הזה). אם אנחנו רוצים להעתיק עכשיו מילים, נשתמש באות y (מציינת yank – למשוך). כלומר מה שהשתנה זה במקום שנלחץ על d נלחץ על y, הגבולות של מה להעתיק (במקרה הזה) נשארות לאחר ה "y” בצורה זהה לאותן הגדרות של פעולת המחיקה ועכשיו יצרנו תבנית (pattern) עבודה.

למעשה vi מאפשר לנו להיות כמה שיותר יעילים במה שאנחנו מבצעים בצורה הזו. אנחנו משתמשים בפעולה עם תזוזה מסויימת בשביל להשיג תוצר מסויים.
היכולת הזו מאפשרת ל vi להיות כלי מאוד חזק, היות והוא מאפשר לשלב מספר "כלים" בתוכו במקום להכיל פקודות API לכל דבר.

הוא מאפשר לנו ליצור מצב שאנחנו זוכרים תבניות עבודה, וככול שמכירים יותר תבניות מגיעים ליותר יכולות מדהימות, כאשר עדיין יש הבדל בין גבול לפעולה בפועל.

סיכום

הצגתי מספר דרכים בהם הגישה לפעמים מהווה anti-pattern ובהדגמה על vi, הדגמתי הפוך, כיצד ניתן ליצור סוג של pattern בעבודה, אם רק משנים את הצורה שבה ניגשים לדברים.

חשוב לזכור כי לפעמים כלים לא מתאימים עבורינו, ולפעמים התפיסה/ההבנה שלנו של הכלי אינה מתאימה לעבודה שלנו.
מה שאינו מתאים ומעקב אותנו, גורם לנו להיות לא יעילים ולכן הכלי אינו מתאים. שימוש בו גורם לסוג של anti-pattern רק בשל עובדה זו.

וכפי שניתן להבין, ניתן למצוא אין סוף anti-patterns, וזיהוי שלהם עוזר לנו להתמקד בעיקר במקום בלמצוא איך להתמודד עם המצב.

כך שאם מתעכבים על התמודדות עם כלי/שפה/מימוש מסויים יותר מידי, סביר להניח כי יש שם anti-pattern, גם אם הכלי עצמו "מצויין".


תויק תחת:nosql, טיפים וטריקים, טכנולוגיה, מסדי נתונים, פיתוח, קהילה, קוד פתוח, תוכנה, תכנות

23 אפריל, 2014 09:22 AM

22 אפריל, 2014

Tomer Cohen

המראה החדש של פיירפוקס

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

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

דפדפן האינטרנט הראשון הראשון נקרא WorldWideWeb והוא פותח למעשה יחד עם פרוטוקול HTTP ושפת העיצוב HTML. ככזה, הוא היה הדפדפן שנתן את הטון וכל הדפדפנים שבאו אחריו היו חייבים לחקות את אופן עבודתו. בשנים שלאחר מכן הופיעו דפדפנים נוספים שכל אחד מהם אימץ את התכונות והמראה של קודמיו ובמקביל השמיט דברים שנראו למפתחיו מיותרים. מספר שנים לאחר מכן שוק הדפדפנים די התייצב עם דפדפנים כגון "נטסקייפ", "אינטרנט אקספלורר" ונוספים, שגרמו להכחדתם של הדפדפנים החלוציים ולמעשה יצרו מעין מראה אחיד בין הדפדפנים השונים במראה ובתפקודם. באותה תקופה כבר הופיעו כפתורי ניווט קדימה ואחורה בהיסטוריה, המושג "דף בית" שמוביל לדף שנבחר על־ידי המשתמש כנקודת מוצא לגלישה ברשת, סימניות/מועדפים וכדומה.

שנים לאחר מכן, עם צמיחתה של רשת האינטרנט והשיפורים הרבים בכוח המחשוב השתנתה גם התנהגותם של משתמשי הרשת, ובמקום לגשת לדף בודד הם התחילו לפתוח מספר דפים במקביל, והשלב האבולוציוני הבא היה התווספותן של הלשוניות (או כרטיסיות, או טאבים, כפי שבוודאי הבנתם אין הסכמה ברורה על המושגים והמונחים). הלשוניות הופיעו בהתחלה בדפדפני נישה דוגמת נטקפטור, ובהמשך הגיעו לדפדפנים נפוצים יותר דוגמת אופרה ומוזילה. דפדפן אינטרנט אקספלורר באותה תקופה היה הנפוץ ביותר עם גרסאות 5.5 ו־6, והיה נראה שמפתחיו מסרבים להאמין שהאופנה החדשה תתפוס, עד שלבסוף הופיעו גם בו לשוניות, בהתחלה כסרגל כלים נלווה ולראשונה כחלק מהדפדפן כשיצא אינטרנט אקספלורר 7, אם כי עברו עוד מספר שנים עד שאפשר היה להשוות את היכולות של תכונה זו לדפדפנים אחרים שהקדימו לאמץ את ממשקי הלשוניות.

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

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

Google Chrome 1 UI taken from Google Chrome comic book

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

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

למשל שורת הכתובת, שבעבר הופיעו בה כתובות קודמות שהמשתמש ביקר בהן כעת הפכו לחכמות יותר; גוגל למשל נוהגים לשלב בהן בכרום תוצאות חיפוש, בעוד בפיירפוקס ניתן דגש להיסטורית הגלישה של המשתמש ולסימניות. דפי הפתיחה הפכו להיות מותאמים יותר למשתמש ומציגים את האתרים המועדפים על המשתמש, וכדומה. באופן דומה לשינויי הממשק ביישומים אחרים, דוגמת סרגלי הכלים של Microsoft Office בגרסאותיו האחרונות, שינוי אופן השימוש בסביבות עבודה מובילות בלינוקס דוגמת Gnome ו־KDE, כיום מקובל לתת דגש רב יותר על הפעולות שנמצאות בשימוש תדיר, ולהצניע כפתורים ופעולות שהמשתמש אינו נוהג להשתמש בהן.

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

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

לחצו כדי לצפות במצגת.

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

המראה החדש של פיירפוקס במחשב האישי

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

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

Firefox 29 menu panel screenshot

לוח התפריט המאוחד בפיירפוקס 29

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

Firefox 29 customization screenshot

התאמה אישית של פקדי הדפדפן

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

פיירפוקס עם מראה מותאם אישית

פיירפוקס עם מראה מותאם אישית

בר הרחבה – ללא ספק, הרחבות מאפשרות לשנות את מראה הדפדפן ואופן התפקוד שלו. המראה החדש שומר על קו עיצובי עם המראה של הדפדפן בסביבות אחרות, אבל לא נחסמת האפשרות לבצע בו שינויים ושיפורים הן באמצעות תפריטי היישום, העדפות נסתרות, ערכות נושא והרחבות. אנשים שלא אוהבים את המראה החדש של הדפדפן יכולים, למשל, לבחור להשתמש בהרחבה Classic Theme Restorer המתיימרת להחזיר לדפדפן את המראה השמרני והמרובע, או להתקין כל אחת מאלפי ערכות הנושא הזמינות באתר התוספות.

הלאה אל העתיד – המראה החדש של הדפדפן לא צפוי להשתנות באופן ניכר בגרסאות הבאות, אבל אין זה אומר שלא יבוצעו במראה הדפדפן בגרסאות הבאות. החל משילוב תכונות מדף הלשונית החדשה בדף הפתיחה, המשך העברת חלונות יישום ללשוניות (נסו להקליד בשורת הכתובת about:permissions או about:preferences כדי לצפות במימוש החלקי עוד היום), החלפת תפריטי ההקשר הטקסטואליים בתפריט נוח יותר לשימוש שניתן להתאמה אישית בדומה ללוח התפריט החדש, יכולות הטמעה משופרות ליישומי רשת שיוצגו במסכים משלהם ללא סרגלי הדפדפן זאת כדי להתאים את המראה והתפקוד שלהם ליישומים טבעיים במערכת, ועוד ועוד, השמיים הם הגבול.

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

הטקסט המלא

22 אפריל, 2014 04:07 AM

21 אפריל, 2014

Guy Rutenberg

Comparison of Hebrew Fonts on Kindle Paperwhite

I’ve decided to compare the looks of four, freely available Hebrew fonts, on the Amazon Kindle Paperwhite.
Frank Ruehl (Culmus), Size 5 David (Culmus), Size 5 Alef (HaGilda), Size 4 Times New Roman (Microsoft), Size 5

The fonts are:
1. Frank Ruehl (Culmus).
2. David (Culmus).
3. Alef (HaGilda).
4. Times New Roman (Microsoft, taken from Corefonts).

All the fonts are in Kindle’s size 5, except Alef which seems a bit bigger than the Culmus fonts so I’ve used it in size 4. The actual size is a bit smaller than the one commonly found in Hebrew paperback books. Alef lacks (in the free version) Italic and Bold-Italic variants, but Kindle’s faux-variants seems to be readable.

Adding fonts can be done without jailbreak using the USE_ALT_FONTS trick. Just remember to unplug the kindle before restarting, else it won’t work. The screenshots were taken by pressing two opposing corners of the screen simultaneously. The test eBook is בדיקת_עברית.azw3.

21 אפריל, 2014 09:11 AM

20 אפריל, 2014

Shlomi Noach

The mystery of MySQL 5.6 excessive buffer pool flushing

I'm experimenting with upgrading to MySQL 5.6 and am experiencing an unexplained increase in disk I/O utilization. After discussing this with several people I'm publishing in the hope that someone has an enlightenment on this.

We have a few dozens servers in a normal replication topology. On this particular replication topology we've already evaluated that STATEMENT based replication is faster than ROW based replication, and so we use SBR. We have two different workloads on our slaves, applied by two different HAProxy groups, on three different data centres. Hardware-wise, servers of two groups use either Virident SSD cards or normal SAS spindle disks.

Our servers are I/O bound. A common query used by both workloads looks up data that does not necessarily have a hotspot, and is very large in volume. DML is low, and we only have a few hundred statements per second executed on master (and propagated through replication).

We have upgraded 6 servers from all datacenters to 5.6, both on SSD and spindle disks, and are experiencing the following phenomena:

The faster replication speed motivates us to continue with the experiment, and is of a significant factor in our decision. However we are concerned about the I/O utilization and excessive flushing.

The above graphs depict the 5.6 status without any configuration changes as compared to 5.5. I took some days to reconfigure the following variables, with no change to the rate of flushed pages (though some changes visible in double-wite buffer writes):

And more... Have done patient one-by-one or combinations of the above where it made sense. As you see I began with the usual suspects and moved on to more esoteric stuff. I concentrated on new variables introduced in 5.6, or ones where the defaults have changed, or ones we have explicitly changed the defaults from.

The above is consistent on all upgraded servers. On SSD the disk utilization is lower, but still concerning.

Our use case is very different from the one presented by Yoshinori Matsunobu. and apparently not too many have experienced upgrading to 5.6. I'm hoping someone might shed some light.

20 אפריל, 2014 06:14 AM

19 אפריל, 2014

Hetz Ben Hemo

כמה מילים על הדרייבר של nVidia ועל מסכים בעייתיים

ישנו דרייבר אחד בלינוקס שיש לו היסטוריה ארוכה של בעיות "פוליטיות" והגדרות טכניות – זהו הדרייברים של כרטיסי המסך של nVidia. רבות כבר נכתב על הדרייברים של nVidia, כמה הם סגורים, מורכבים, לא תואמים תמיד, ו"עקשנים" בסירובם לרוץ בסביבות מסויימות. … להמשיך לקרוא

הטקסט המלא

19 אפריל, 2014 12:11 PM

Shlomi Noach

Monitoring DML/slow queries with graphite

pt-query-digest, Anemometer or "Anemomaster" do a great job of analysing your queries and giving you visibility into what's going on with your MySQL servers. However, the place where the query digests are written is just some MySQL tables on some server. Do you have monitoring/alerts on that table? How will you verify a specific query does not exceed some runtime/execution count threshold, and get notified when it does?

At Outbrain we use Graphite to collect almost all of our data. We like it for its simplicity and for the fact it has a "push" strategy as opposed to "pull" strategy: every service/server/collectd writes (pushes) its own data to Graphite, as opposed to having some centralized monitoring service trying to pull data from thousands of servers & services. We also have a great Graphite dashboard (developed at our company by Erez Mazor) called graphitus, which is a very sophisticated and easily configurable visualization solution (see documentation).

Our love/hate relationship with Nagios boil down to having a single Nagios plugin: one that reads data from Graphite. We use Nagios to generate our alerts, and dream of the day we will substitute it with something else (there's not too much love in this love/hate relationship).

Graphite is a numeric timeseries data monitoring solution. How do you throw MySQL query analysis into Graphite, then?

The answer lies within the flexible structure of a Graphite metric entry, which is a freely composed path, such as collectd.hosts.us-east.myhost01.mysql.gauge-Threads_running.value. Graphite does not require you to pre-define paths, and you can use anything that makes sense to you. Thus, you can use a slow query's text, for example, as part of the Graphite entry path. This is not entirely simple as the graphite path limits the allowed characters. So this is what we do:

Any query that is written to Graphite is transformed into a "canonical form". We strip it of excessive information and write enough of it that still makes sense to us. Actually, we found out that we usually do well with just the bare bones of "what type of query this is and what tables are involved". For better drill down we then go to Anemometer/Anemomaster. Hence, the canonical form of the following query:

UPDATE my_documents SET document_owner='Wallace'  WHERE document_domain='Gromit'

is simply

update_my_documents

Thankfully the pt-query-digest report tables are already timestamp based, and are already aggregated by query "fingerprints". This makes writing this data to graphite just a matter of text normalizing. The following script is a slightly modified version of what we use. Do note that we have the notion of "clustername" which is the name of the replication topology we're looking at. We have many topologies, like OLTP, OLAP, Metadata, etc. etc. We support this notion by adding a clustername_max column to the report tables and instructing pt-query-digest fill in this value.

We run the following shell script by cron every 10 minutes (based on the 10 minute interval of analysing our masters' DML):

#!/bin/bash

#
# This script should run on the anemomaster machine every 10 minutes, shortly after
# binary logs / relay logs are analyzed via pt-query-digest.
#

unixtime=$(date +%s)

# Get stats for the last round 10 minutes
# The query only takes one representative from each cluster
query=" select clustername_max, sum(ts_cnt), replace(fingerprint, '\n', ' ') from global_query_review_history join global_query_review using (checksum), (select date(now()) + interval hour(now()) hour + interval (minute(now()) div 10 *10) minute as search_to_timestamp) as search_to_timestamp_sel where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp and hostname_max in ( select min(hostname_max) from global_query_review_history where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp group by clustername_max) group by clustername_max, fingerprint order by sum(ts_cnt) desc "

mysql -umyself -psecret anemomaster --silent --silent --raw -e "$query" | while IFS=$'\t' read -r -a result_values
    do
        fingerprint_cluster=${result_values[0]} ;
        fingerprint_count=${result_values[1]} ;
        fingerprint_query=${result_values[2]} ;
        fingerprint_query=$(echo $fingerprint_query | sed -r -e "s/^(-- .*)]//g")
        fingerprint_query=$(echo $fingerprint_query | tr '\n' ' ' | tr '\r' ' ' | tr '\t' ' ')
        fingerprint_query=${fingerprint_query%%(*}
        fingerprint_query=${fingerprint_query%%,*}
        fingerprint_query=${fingerprint_query%% set *}
        fingerprint_query=${fingerprint_query%% SET *}
        fingerprint_query=${fingerprint_query%% where *}
        fingerprint_query=${fingerprint_query%% WHERE *}
        fingerprint_query=${fingerprint_query%% join *}
        fingerprint_query=${fingerprint_query%% JOIN *}
        fingerprint_query=${fingerprint_query%% using *}
        fingerprint_query=${fingerprint_query%% USING *}
        fingerprint_query=${fingerprint_query%% select *}
        fingerprint_query=${fingerprint_query%% SELECT *}
        fingerprint_query=$(echo $fingerprint_query | tr -d "\`")
        fingerprint_query=$(echo $fingerprint_query | tr -d "*")
        fingerprint_query=$(echo $fingerprint_query | tr -d "?")
        fingerprint_query=$(echo $fingerprint_query | tr " " "_")
        fingerprint_query=$(echo $fingerprint_query | tr "." "__")
        echo "data.mysql.dml.${fingerprint_cluster}.${fingerprint_query}.count ${fingerprint_count} $unixtime" | nc -w 1 my.graphite.server 2003
    done

If you don't need the "clustername stuff", modify the query to read:

select 'mysql' as clustername_max, sum(ts_cnt), replace(fingerprint, '\n', ' ') from global_query_review_history join global_query_review using (checksum), (select date(now()) + interval hour(now()) hour + interval (minute(now()) div 10 *10) minute as search_to_timestamp) as search_to_timestamp_sel where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp and hostname_max in ( select min(hostname_max) from global_query_review_history where ts_min >= search_to_timestamp - interval 10 minute and ts_min < search_to_timestamp) group by fingerprint order by sum(ts_cnt) desc

The graphite metric path will look like data.mysql.dml.oltp.update_my_documents.count, which makes for a perpefctly valid metric to monitor, graphically visualize and get alerts on.

19 אפריל, 2014 06:27 AM

18 אפריל, 2014

Shlomi Noach

"Anemomaster": DML visibility. Your must-do for tomorrow

Here's our take of master DML query monitoring at Outbrain (presented April 2014). It took a half-day to code, implement, automate and deploy, and within the first hour of work we managed to catch multiple ill-doing services and scripts. You might want to try this out for yourself.

What's this about?

What queries do you monitor on your MySQL servers? Many don't monitor queries at all, and only look up slow queries on occasion, using pt-query-digest. Some monitor slow queries, where Anemometer (relying on pt-query-digest) is a very good tool. To the extreme, some monitor TCP traffic on all MySQL servers -- good for you! In between, there's a particular type of queries that are of special interest: DML (INSERT/UPDATE/DELETE) queries issued against the master.

They are of particular interest because they are only issued once against the master, yet propagate through replication topology to execute on all slaves. These queries have a direct impact on your slave lag and on your overall replication capacity. I suggest you should be familiar with your DMLs just as you are with your slow queries.

In particular, we had multiple occasions in the past where all or most slaves started lagging. Frantically we would go to our metrics; yes! We would see a spike in com_insert. Someone (some service) was obviously generating more INSERTs than usual, at a high rate that the slaves could not keep up with. But, which INSERT was that? Blindly, we would look at the binary logs. Well, erm, what are we looking for, exactly?

Two such occasions convinced us that there should be a solution, but it took some time till it hit us. We were already using Anemometer for monitoring our slow logs. We can do the same for monitoring our binary logs. Thus was born "Anemomaster".

Quick recap on how Anemometer works: you issue pt-query-digest on your slow logs on all MySQL hosts (we actually first ship the slow logs to a central place where we analyse them; same thing). This is done periodically, and slow logs are then rotated. You throw the output of pt-query-digest to a central database (this is built in with pt-query-digest; it doesn't necessarily produce human readable reports). Anemometer would read this central database and visualize the slow queries.

Analysing DMLs

But then, pt-query-digest doesn't only parse slow logs. It can parse binary logs. Instead of asking for total query time, we ask for query count, and on we go to establish the same mechanism, using same pt-query-digest and same Anemometer to store and visualize the DMLs issued on our masters.

When analysing DMLs we're interested in parsing binary logs -- and it makes no sense to do the same on all slaves. All slaves just have same copy of binlog entries as the master produces. It only takes one server to get an accurate picture of the DMLs on your replication topology.

One server could be the master, and this can indeed be done: just FLUSH MASTER LOGS, parse the binary logs with pt-query-digest, and you're done. But like others, we tend to look at our masters as tender babies. We care for them, and do not wish to overload them unnecessarily. We chose to get the binlog entries from our slaves, instead. We also chose to get the entries from the relay logs, since these are unaffected by slave performance and as long as network is good, we can expect the relay logs to be very up to date. At any given time we have two slaves that take this role (this is automated and verified). On a 10 minute period we would flush the relay logs on these servers, and analyse whatever relay logs we have not analysed as yet.

The script below is a slightly modified version of our own, and should work for the standard installation. Modify to fit your own data (in particular, it assumes relay logs are named mysqld-relay-bin; datadir is specified in /etc/my.cnf, and please don't ask me how to do this on Windows):

#!/bin/bash

# 
# Digest latest relay logs file, write results to "anemomaster"
#
# This script can run from any machine; it only needs to execute on a single machine per mysql cluster, but for
# analysis availability it should execute on at least two hosts per cluster.
#

DATADIR=`grep datadir /etc/my.cnf|awk -F= '{print $2}'`
TMPDIR=/tmp
DIGESTED_RELAY_LOGS_FILE=${DATADIR}/digested_relay_logs.txt

touch $DIGESTED_RELAY_LOGS_FILE
chown mysql:mysql $DIGESTED_RELAY_LOGS_FILE

hostname=$(hostname)

echo "deleting old relay logs from ${TMPDIR}"
rm ${TMPDIR}/mysqld-relay-bin.[0-9]*

echo "Getting current relay log files"
existing_relay_log_files=$(ls -tr ${DATADIR}/mysqld-relay-bin.[0-9]* | head -n -1)
for existing_relay_log_file in $existing_relay_log_files
do
    cp -u $existing_relay_log_file $TMPDIR
done
echo "flushing relay logs"
/usr/bin/mysql -umyself -psecret -e 'flush relay logs\G;' 2>/dev/null
# sleep because the log file takes some time to disappear
sleep 1

echo "Getting current relay log files"
existing_relay_log_files=$(ls -tr ${DATADIR}/mysqld-relay-bin.[0-9]* | head -n -1)
for existing_relay_log_file in $existing_relay_log_files
do
    cp -u $existing_relay_log_file $TMPDIR
done

cd $TMPDIR
for relay_log_file in mysqld-relay-bin.[0-9]*
do
    # Filter this relay log file, since it's already been digested
    grep $relay_log_file $DIGESTED_RELAY_LOGS_FILE && rm $relay_log_file
done

for relay_log_file in mysqld-relay-bin.[0-9]*
do
    echo "digesting $relay_log_file"
    mysqlbinlog $relay_log_file | /usr/bin/pt-query-digest \
      --type binlog --order-by Query_time:cnt --group-by fingerprint --limit 100 \
      --review  P=3306,u=anemomaster,p=secret,h=anemomaster_host,D=anemomaster,t=global_query_review \
      --history P=3306,u=anemomaster,p=secret,h=anemomaster_host,D=anemomaster,t=global_query_review_history \
      --filter=" \$event->{Bytes} = length(\$event->{arg}) and \$event->{hostname}=\"$(hostname)\" " \
      --no-report
    echo "$relay_log_file" >> $DIGESTED_RELAY_LOGS_FILE
    rm $relay_log_file
done
# make sure the file does not bloat. 20 entries is more than enough.
tail -n 20 $DIGESTED_RELAY_LOGS_FILE > ${TMPDIR}/DIGESTED_RELAY_LOGS_FILE
cat ${TMPDIR}/DIGESTED_RELAY_LOGS_FILE > $DIGESTED_RELAY_LOGS_FILE
echo "done"

As for Anemometer, we patched it to support multiple environments ("clusters") -- but irrelevant to the DML change. If you just want to make it visualize DMLs, here's the major configuration changes to config.inc.php (marked with bold):

$conf['history_defaults'] = array(
	'output'		=> 'table',
	'fact-group'	=> 'date',
	'fact-order'	=> 'date DESC',
	'fact-limit' => '90',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-90 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('date', 'query_time_avg','ts_cnt','Query_time_sum')
);

$conf['report_defaults'] = array(
	'fact-group'	=> 'checksum',
	'fact-order'	=> 'ts_cnt DESC',
	'fact-limit' => '20',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-1 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('checksum','snippet', 'query_time_avg','ts_cnt','Query_time_sum'),
	'dimension-pivot-hostname_max' => null,
	'dimension-pivot-clustername_max' => null
);

$conf['graph_defaults'] = array(
	'fact-group'	=> 'minute_ts',
	'fact-order'	=> 'minute_ts',
	'fact-limit' => '',
	'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-7 day')),
	'dimension-ts_min_end'	=> date("Y-m-d H:i:s"),
	'table_fields' => array('minute_ts'),
	// hack ... fix is to make query builder select the group and order fields,
	// then table fields only has to contain the plot_field
	'plot_field' => 'ts_cnt',
);

With a 10 minute rotation & digestion, we are able to analyze near real-time what's been done on our masters. If we see a spike in com_insert/com_update/com_delete, or just see slave lags, we turn to Anemomaster and within a couple minutes know exactly what service is guilty of abusing our database. We are also working to protect our database against abuse, but that's for another discussion.

18 אפריל, 2014 06:02 PM

Ilan Shavit

מתדולוגיות של הפצות – חלק שני

במאמר המשך זה אסקור תכונות וסוגים שונים של הפצות המתגלגלות:

הפצות מתגלגלות למחצה (part-rolling, semi-rolling, or half-rolling):
בהפצות אלו קיימים חלקים שלא מתגלגלים. מדובר בדר"כ ברכיבי ליבה (קרנל, xorg והמעטפת הגרפית). דוגמאות: PCLinuxOS, Chakra Linux, Aurora OS

הפצות מתגלגלות באופן מלא: (full-rolling )
בהפצות אלו כל מרכיבי ההפצה מתגלגלים. דוגמאות: Arch, Gentoo

הפצות מתגלגלות באופן מדומה (pseudo-rolling):
בהפצות אלו מנסים ליצב את הענף הלא יציב באמצעות תיקוני תוכנה (patches) המוכנסים אליו ואמורים לספק תכונות הקיימות בהפצות המתגלגלות. דוגמאות: aptosid, siduction, Semplice, antiX

הפצות מתגלגלות לפי בחירה (opt-rolling):
להפצות אלו יש גרסאות להורדה של הפצות מתגלגלות ושל הפצות לא מתגלגלות.
דוגמא: OpenSuse

הפצות מתגלגלות באופן מחזורי (cyclic-rolling):
הפצות אלו מפותחות במחזוריות (בעיקר בחלקיהם הלא מתגלגלים). לפיכך גיל החבילות והיציבות שלהם לא זהה בחלקים שונים של ההפצה. דוגמאות: antiX and LMDE

מקור

My Signature

18 אפריל, 2014 11:00 AM

Diego Iastrubni

חופש -שימוש ב־owncloud

כל משתמש אנדרויד שחובב חופש מנסה להימנע מהידיים של גוגל. אז מתקינים רומים נקיים (אני משתמש ב־cyanogenmod שאני בונה בעצמי). השלב הבא הוא להוציא את השירותים של גוגל. נתחיל מהמרק, במקומו נשתמש ב־fdroid והיא תוכנה שמתקינים על הסלולרי ומהווה חנות וירטואלית שמכילה רק תוכנות חופשיות. התוכנות שם די מאעפנות... זה לא מה שאני רגיל אליו ב"לינוקס". אני מניח שהעולם הזה עוד מתפתח ואני יכול לצפות לטובה. (דיברתי על זה בפוסט אחר, http://cucomania.dyndns.info/node/236).

אני משתמש גם ב־owncloud בתור שרת. זה מחליף את dropbox היומנים של גוגל ואנשי הקשר. הבעייה כאן, היא שיש המון הגדרות לעשות ידנית במכשיר, ואין תוכנה אחת שמטפלת בכל הפונקציונליות. 

התוכנות המדוברות כאן תוכנות חופשיות, וזמינות בשרתים של FDroid (אפשר להתקין הכל מהתוכנה).

הטקסט המלא

18 אפריל, 2014 10:50 AM

17 אפריל, 2014

Yaniv Gershoni

עתיקות...


מצאתי (אחרי שכל העולם כבר פרסם את זה...) את המקלדת הוירטואלית עם קיצורי הדרך של בלנדר.
(למי שלא ראה, זה כאן: http://waldobronchart.be/blenderkeyboard)

הסתובבתי קצת בין קיצורי הדרך וראיתי פתאום שאם לוחצים על Ctrl+Alt+מקש הרווח נכנסים למצב של...
"Create Orientation"

לחצתי וקיבלתי תפריט קטנצי'ק בצד שמאל למטה שנראה כך:


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

פרטים נוספים »

הטקסט המלא

17 אפריל, 2014 07:21 PM