DCSIMG
Idan Felix's Blog

Idan Felix's Blog

Life was very simple - And then some one thought of adding some Technical Details.

Entity Framework Bad Practices and solutions with EF-Prof

Entity Framework Bad Practices – and solutions with EF-Prof

This week I had to find and fix an interesting bug. For some reason, when using Entity Framework, we’ve seen database queries that were causing a TimeoutException to be thrown. We used EF-Prof to find which query was giving us troubles, and found a few additional issues. Solving these issues has improved the performance of our server by a great deal.

While there are many ways to abuse ADO.Net Entity Framework, these were the two issues I’ve stumbled upon this week:

Setting the environment

In order to demonstrate the issues, I’m using an ultra-simple Entity Framework Model:

01-SimpleModel

The model is created in a Console Application.

Badly Interpreted Queries

The first issue we looked for was the TimeoutException. Consider the following code:

 using  (var  context = new  PubsEntities())
 {
     var  latestIds = from  pubs in  context.Pubs
                      where  pubs.City != null  && pubs != null
                      group  pubs by  pubs.City
                         into  cities
                         select  cities.Max(pub => pub.Id);
 
     var  latest = from  pub in  context.Pubs
                   where  latestIds.Contains(pub.Id)
                   select  pub;
 
     foreach  (var  pub in  latest)
     {
         Console .WriteLine("{0}:{1}" , pub.CityId, pub.Name);
     }
 }
 

Breakdown: This code finds the pub that has the largest Id in each city. Since the model uses auto incrementing identity, it’s safe to say that it finds the most recent pub added in each city. It does that by picking up the max Id of pubs in a city, and then gets all pubs, according to the latestIds.

The trivial problem is easy to see (because I painted it yellow Smile) - There’s a redundant check there, to verify that a row coming from the context is not null, which can’t really happen. The interesting thing is to check what’s going on in the generated SQL code:


SELECT [Id] AS [Id], [Name] AS [Name], [Owner] AS [Owner], 
       [NumberOfSeats] AS [NumberOfSeats], [Street] AS [Street], 
       [HouseNumber] AS [HouseNumber], [City] AS [City] 
FROM [Pub] 
WHERE EXISTS (
       SELECT 1 AS [C1] 
       FROM (  
              SELECT E3.[Id] AS [K1], E3.[Name] AS [K2], 
                     E3.[OtherUnusefulInformation] AS [K3], 
                     MAX([E2].[Id]) AS [A1] 
              FROM   [Pub] AS [E2] 
              LEFT OUTER JOIN [City] AS E3 
              ON     [E2].[City] = E3.[Id] 
              WHERE  ([E2].[City] IS NOT NULL) 
              AND    (cast(1 as bit) <> cast(0 as bit))
              GROUP BY E3.[Id], E3.[Name], E3.[OtherUnusefulInformation]) AS [GroupBy1] 
       WHERE [GroupBy1].[A1] = E1.[Id])

See the weird condition? It is evaluated for each record, because it can’t be cached by SQL-Server. That little piece of code slowed the query on a large enough dataset, and caused a timeout. By removing the nullity check, we reduced the query runtime from 30 sec to 34ms.

How did we find it? Whenever an error is thrown, the EF-Profiler shows an alert. Rest of the time, it was our most expensive query, according to the EF-Profiler.

Select N+1

Once the profiler was hooked and the timeout was gone, we went on and randomly clicked buttons on our application. We’ve found that a few of the methods had code that resembled the following:

 using  (var context = new PubsEntities())
 {
     var cities = context.Cities;
     foreach (var  city in  cities)
     {
         Console.WriteLine(city.Name);
         foreach (var  pub in  city.Pubs)
         {
             Console.WriteLine(“\t{0}”, pub.Name);
         }
     }
 }

Now, in an object oriented world, this code makes perfect sense – However, when using EF, this causes a lot of different SELECT statements – once for each pub being used. This is caused because the Pubs are Lazy-loaded. This issue is called “The Select N+1 data access anti-pattern”.

Solution? simple indicate to EF that the Cities collection should be loaded with pubs, like this:

 var cities = context.Cities.Include("Pubs");

The Include method causes the pubs collection to be eagerly loaded, thus only one call is made to the database. This reduces a lot of overhead. This issue was the most common alert given by EF-Prof.

Conclusions

1. When using an O/RM, such as ADO.Net’s entity framework, make sure to use a profiler to find any performance bottlenecks.

2. Don’t trust the generated queries blindly– go over the queries, and check their translation to SQL.

3. Using ADO.Net Entity Framework, or any O/RM for that matter, does not hide the database – it makes it much easier to use, but still – be aware that there’s a database under the hood, and do your best, to minimize the number of queries the database has to execute.

Happy Coding!

Refactoring telerik RadScheduleView ReadOnly example to attached behavior

Refactoring to attached behavior

At the project I’m currently working on, I had to integrate Telerik’s RadScheduleView in a WPF application that uses Caliburn Micro as MVVM framework. The RadScheduleView is a time management  component, however, we needed it only for presentation – thus we had to make it a read only control.

The control itself does not expose an “IsReadOnly” property, so I found this post at Telerik’s forums. It includes a code sample that shows how to do it, but it does not conform nicely to the M-V-VM Pattern – So I had to refactor it to Attached Behavior.

The Problem: Code in Code-Behind

The demo project places the event handling code of 4 events (AppointmentCreating, AppointmentDeleting, AppointmentEditing and ShowDialog) in the code behind the MainWindow (MainWindow.xaml.cs file).

Since we’re using Caliburn, we did not want to break pattern and add code to our view’s .xaml.cs file. This way, our code behind will remain slim and clean.

The Solution: Attached Behaviors

Attached Behaviors enable changing of behavior of WPF controls in a declarative manner, with no unwanted code residue in the view.

The magic uses Attached Properties: Since attached properties are dependency properties, code can register to a property change event. The event handler then modifies the control’s properties and events to have the required functionality.

Result (Code):

(Code is provided as-is.)

 using  System;
 using  System.Windows;
 using  Telerik.Windows.Controls;
 
 namespace  Wpf_RadScheduleView
 {
     public  static  class  ReadOnlyBehavior 
     {
         private  const  string  INVALID_TYPE_ERROR_MESSAGE = 
             "This attached behavior can only be aplied on RadScheduleView controls." ;
 
 
         public  static  bool  GetIsReadOnly(DependencyObject  obj)
         {
             return  (bool )obj.GetValue(IsReadOnlyProperty);
         }
 
         public  static  void  SetIsReadOnly(DependencyObject  obj, bool  value)
         {
             obj.SetValue(IsReadOnlyProperty, value);
         }
 
         public  static  readonly  DependencyProperty  IsReadOnlyProperty =
             DependencyProperty .RegisterAttached("IsReadOnly" , 
                                                 typeof (bool ), 
                                                 typeof (ReadOnlyBehavior ), 
                                                 new  UIPropertyMetadata (false , 
                                                                        IsReadOnlyChanged));
 
         private  static  void  IsReadOnlyChanged(DependencyObject  d, 
                                               DependencyPropertyChangedEventArgs  e)
         {
             if  (d == null )
             {
                 throw  new  ArgumentNullException ("d" );
             }
             var  scheduleView = d as  RadScheduleView ;
             if  (scheduleView == null )
             {
                 throw  new  ArgumentException (INVALID_TYPE_ERROR_MESSAGE, "d" );
             }
 
             var  shouldBeReadOnly = (bool )e.NewValue;
             if  (shouldBeReadOnly)
             {
                 RegisterInteractionEventHandlers(scheduleView);
             }
             else 
             {
                 var  shouldCleanup = (bool )e.OldValue;
                 if  (shouldCleanup)
                 {
                     UnregisterInteractionEventHandlers(scheduleView);
                 }
             }
         }
 
         private  static  void  UnregisterInteractionEventHandlers(RadScheduleView  scheduleView)
         {
             scheduleView.AppointmentCreating -= CancelAppointmentCreating;
             scheduleView.AppointmentDeleting -= CancelAppointmentDeleting;
             scheduleView.AppointmentEditing -= CancelAppointmentEditing;
         }
 
         private  static  void  RegisterInteractionEventHandlers(RadScheduleView  scheduleView)
         {
             scheduleView.AppointmentCreating += CancelAppointmentCreating;
             scheduleView.AppointmentDeleting += CancelAppointmentDeleting;
             scheduleView.AppointmentEditing += CancelAppointmentEditing;
         }
 
         private  static  void  CancelAppointmentEditing(object  sender, 
                                                      AppointmentEditingEventArgs  e)
         {
             e.Cancel = true ;
         }
 
         private  static  void  CancelAppointmentDeleting(object  sender, 
                                                       AppointmentDeletingEventArgs  e)
         {
             e.Cancel = true ;
         }
 
         private  static  void  CancelAppointmentCreating(object  sender, 
                                                       AppointmentCreatingEventArgs  e)
         {
             e.Cancel = true ;
         }
     }
 }
 

Now, this behavior can be applied in XAML like this:

 <telerik:RadScheduleView x:Name="schedule"  
          AppointmentsSource="{Binding Appointments}" 
          ResourceTypesSource="{Binding ResourcesTypes}" 
          local:ReadOnlyBehavior.IsReadOnly="True" > 
     <!-- ... --> 
 
 

Last Step

In order for the project to compile, I have to change the ReadOnlyDragAndDropBehavior’s base class inherit from ScheduleViewDragDropBehavior and not from DefaultDragDropBehavior, as it is obsolete.

Next Possible Steps

It is also possible to turn this Attached Behavior to a System.Windows.Interactivity.Behavior, but we thought it would be overshooting.

Another option to include the ReadOnlyDragAndDropBehavior in the attached behavior, but since I knew we’re not going to set the behavior to re-enable editing, and the assignment is still done in xaml, I did not really care about where to set it.

Update: I’ve noticed that Telerik also have a RadScheduler control, and that Scheduler has read only capabilities – so if it’s possible, consider using that control instead of the RadScheduleView.

ReUpdate: It turnes out that the RadScheduleView is the new control of the two.. If you need to migrate, Telerik has a help post about it.

Enjoy, and happy coding!

חוויה אישית – Waze – משחק יום העצמאות 2010

חוויה אישית – Waze – משחק יום העצמאות 2010

שבת, 24/04/10, 19:30, בדרך מראש העין לרעננה. “הולכים לראות סרט?” שאלתי אותה, וחשבתי שזאת שאלה רטורית – הרי הקלטנו את “גבעת חלפון אינה עונה” ב-Max, וכבר תכננו על הפופקורן. “כן, אבל מה זה תיבת האוצר הזאת שיש באיזור בצרה?” היא ענתה. בלי לדעת לאן השאלה הזו תוביל אותנו – פשוטו כמשמעו.

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

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

20:00 “אהם, עידני, כאן ימינה, לפני פסי הרכבת”. זה כביש עפר, בין שדות. נורא יפה, פסטורלי. השמש כבר שקעה. התיבה נראתה ממש מעבר לפינה, ו-Waze הכינה בשבילנו מסלול. גילינו שליד התיבה יש אייקון נוסף. בטח עוד שנייה נראה שוב אספלט, ונגיע הביתה.

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

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

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

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

כל הכבוד Waze.

שיעורים אחרונים, מבוא למדעי המחשב

אהלן חברים.

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

ניתן להוריד את כל המצגות מהלינקים.

בהצלחה בבחינה!

שיעור חמישי, מבוא למדעי המחשב

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

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

תהנו, ובהצלחה בתרגיל 5!

פליקס.

שיעור שני, מבוא למדעי המחשב

אהלן שוב.

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

תהנו,
פליקס

שיעור ראשון, מבוא למדעי המחשב

לכל משתתפי השיעור, היה אחלה שיעור. נתראה בשני הבא.

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

תהנו!

מדהים: Sketch2Photo

Sketch2Photo_Crop

מדהים: Sketch2Photo

זה פשוט העיף אותי, וחשבתי לחלוק את זה עם העולם. סקץ’2פוטו (Sketch2photo) היא פיתוח של מספר מדעני מחשב, וביניהם ד”ר אריק שמיר, שהיה אחד המורים שלי.

יחד עם המאמר, התפרסם גם הסרטון הזה:

לדעתי, זה מדהים.

עוד רגע קטן של אושר

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

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

איזה כיף זה!

 

Touched and Burned by SilverLight

Imagine, for a second, that you get a .abc file from a friend of yours, and try to open it - just to find out that your new shiny version of ABCReader* can't open .abc files, because it is expecting .abcx files.
You'd be mad, right? You would at least expect to see a warning message, while installing the new version of ABCReader, that warns you about Backward Compatibility issues.

However, ABCReader could be Backward Compatible, so we could have liked it. We really started to enjoy using it, and would have probably continue to use it forever.
Should I start a new startup, ABCReader would be the first thing that I would install.

---

Silverlight Is Not Backward Compatible.

Note: For this post, I've made up a name for a software, called "ABCReader". If you know such a program, please let me know, so I could pick any other random 3 letters of the alphabet.

עד עכשיו לא התרגשתי

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

האאוטלוק הזכיר לי היום בבוקר את המפגש, ואת המשפט האלמותי של אחותי: "אתה יודע לתכנת... תעשה מצגת Power Point..." (זה לא ציטוט ישיר, ואני בכיף אעשה מצגת, אבל זה רק בגלל שלא היה לי כוח למצוא קוד של איזה Slideshow ב- WPF ולהתאים אותו כך שירוץ בלופ על קובץ XML לפי הסדר - אני תקוע מדיי באיזו אפליקציה טפשית ב- Facebook), ואני עסוק נורא בלהתרגש לקראת החתונה מחר.

עד שיחת הטלפון המפתיעה:

"תשמע, אתה בא היום למפגש, נכון?"
"ברור!"
"אחלה. אני ויוסי שכחנו להביא מצלמה..."

עכשיו אני מתרגש.

(עכשיו, ה- Workflow למי שמתעניין בצילום:
מדליקים את הדוד, שמים את הבטרייה שלה בהטענה, ופותחים את החבילה של הבטריות לפלאש. עוברים על התמונות של ה-Security Usergroup כדי להיזכר שהאורות שם מעורבבים, אז לעבור לאיזון לובן כמו בן-אדם, ושזה יקרה פחות. חוגרים את החצובה בתיק וחוזרים ל- Powerpoint)

תגובה לפוסט "טיפול כולל ב- Unhandled Exception"

זוהי תגובה לפוסט של מיקי בנושא טיפול בחריגים (Exceptions) שאותם לא הצלחנו לתפוס.

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

השאלות

במה הטיפול בשגיאה של UI שונה מהטיפול בשגיאה של Non-UI, חוצמזה שה- NonUI גורם ליציאה מהתוכנה? ולמה צריך לטפל בשלושה מקומות בשביל לבצע פעולה אחת (טיפול בחריג שלא טופל)? אני אנסה להבהיר את עצמי באמצעות התנסחות מתמטית: תהי E קבוצת כל החריגים. תהי U⊆E קבוצת החריגים של ה- UI. נסמן ב- U=E-U את קבוצת החריגים שאינם של ה- UI. קל לראות ש- U∪U=E - ולכן - למה צריך 3 מקומות?

התובנה

השתמשתי בקוד של מיקי, למרות השאלות. זה הגיע מהר ל- Production, כי טיפול בחריגים לא מטופלים זה חשוב, והשתמשתי ב- Log4Net כדי לקבל מייל על החריגים שנזרקו - אבל המידע הוא מידע חלקי ולא מאוד מועיל - בלי הפרמטרים שהגיעו למתודה שזרקה את החריג, גיליתי שקשה לי מאוד לשחזר את מה שקרה, או להבין מה קרה - אז שווה להזכיר כאן את ההרצאה של אוהד ישראלי, Mastering Infrastructure Development מ- Developers Academy II.

 

 

תמונות מאירוע המפתחים של השנה

צילמתי המון תמונות, ולא אשקר, הרוב הועברו מהמצלמה ל- Recycle bin בערך באותה המהירות שהן צולמו. היום הוכחתי שיש לי עוד על מה להתאמן.

תמונות מההרצאות - עכשיו זה סיפור אחר...

 DevAcadamy2 050DevAcadamy2 041DevAcadamy2 033DevAcadamy2 058DevAcadamy2 057DevAcadamy2 053

 

עכשיו הגיע הזמן לחזור לעשות שיעורי בית...

תודה לכווולם. היה לי גן עדן ועוד קצת.

יוחאי - אולי פעמיים כי טוב ?

System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

This is the most annoying bug I had to handle. Here's the exception details:

Message: "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."

Source: "System.Windows.Forms"

Stack Trace:

at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.ButtonBase.OnFrameChanged(Object o, EventArgs e)
at System.Drawing.ImageAnimator.ImageInfo.OnFrameChanged(EventArgs e)
at System.Drawing.ImageAnimator.ImageInfo.set_Frame(Int32 value)
at System.Drawing.ImageAnimator.AnimateImages50ms()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

The thing is, that the programmer who wrote the code that caused the problem knew nothing about multithreading, nor did he know how to read and understand the exception details, and the exception was thrown only after leaving all forms, and printing the "Program Closed Correctly" in the console window we use to debug, and it was thrown once in every 3 executions (more or less, depends on the computer's mood).

The reason for this bug was a button with an image, an animated gif image.

We got rid of that image, and the bug never rose his evil head again.

Now, can anyone tell me how to get rid of the exception, while still using the animated gif ? How can I ask, just before closing the form, to stop animations ? I have a graphic designer, and I'd hate to let him go just because I can't deliver my goods with animated buttons...

(oh, and saying "Just change everything to WPF" is not really a good answer - we're planning it, but it won't happen anytime soon - not for a few months - because we have to put everything else in place first (NHibernate, the BLL itself, and quite a few other modules) - so I know WPF is the answer, but I'm looking into something else.)

Thanks!

אמרו די לאוטומטי - צילום דיגיטלי

פתח דבר

לפני כמה שבועות מצאתי מאמר חמוד נורא על קומפוזיציה בצילום, בעברית, באתר מייקרוסופט. נכון, זה פורסם ב-1 במאי, 2002, אבל זה עשה לי ממש חשק - אז קניתי מצלמה דיגיטלית חדשה, Canon EOS 350D, או כמו שהחברה שלי קוראת לה, "מצלמה עם אף", והתחלתי להתנסות.

מסתבר, שלעוד אחד מהקהילה יש מצלמה כזו! ניגשתי אליו במפגש הבלוגרים השני, כחובב צילום מתחיל, וביקשתי לעצתו. הוא ענה לי "לעולם, אבל לעולם, אל תשתמש במצבי הצילום שהם באות ולא בציור" (קרי, P, Tv, Av ו- M). החלטתי לעשות מעשה, ולנסות להסביר למה כן להשתמש במצבים האלה. הפוסט הזה מוקדש באהבה רבה לאותו איש. אני לא אעבור על המצב P, כי הוא כמעט אוטומטי, ומאפשר שליטה נורמאלית רק על רגישות החיישן וגם לא על המצב M, שבו הכל ניתן לשליטה, כי אז הרבה יותר קל לפקשש ולגרום לתת-חשיפה, או לחשיפת-יתר. (אם זה נשמע כמו סינית, תקראו את הפוסט עד הסוף, ותחזרו לקרוא את המשפט הזה).

במפגש הבלוגרים דיברנו, בין השאר, על זכויות יוצרים - אז כדי להיות On the safe side, הצילומים היחידים שתראו בפוסט הזה צולמו ע"י עבדכם הנאמן, והועלו לפליקר, ופורסמו כ- Common Creatives.

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

בשביל מה ובשביל מי זה טוב

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

נתחיל: מה הולך שם בפנים

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

בדיוק אותו דבר קורה במצלמה. הזמן שבו אנחנו "שמים את הכוס מתחת לברז" נקרא מהירות התריס (Shutter Speed). הברז ממלא את תפקיד הצמצם (Iris), כך שככל שהברז (הצמצם) סגור יותר, פחות אור נכנס אל המצלמה (ליחידת זמן נתונה). גודל כוס המים משול לרגישות החיישן (קרי, ה- ISO שמצלמים בו). אם בסיום התהליך, בכוס אין מספיק מים, התמונה תסבול מתת חשיפה (ותצא חשוכה) או חלילה מחשיפת-יתר (ותצא בהירה, או שהמצולמים שלכם יצאו בהירים).

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

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

שליטה על מהירות התריס - מצב הצילום Tv

במצב הצילום Tv, המצלמה מאפשרת לנו לבחור את מהירות התריס, ובד"כ גם את רגישות החיישן. כשנלחץ על כפתור הצילום, המצלמה תבחר לבד את מפתח הצמצם הדרוש לה, בהתאם לרגישות החיישן ומהירות התריס שבחרנו, כדי להגיע לחשיפה מוצלחת. מהירות התריס נמדדת ביחידות זמן (לדוגמא: שנייה, עשירית השנייה, "אחד-חלקי-25-השניה", ועוד ועוד).

באנגלית, המצב Tv נקרא Time Value, כי הוא מאפשר לקבוע לכמה זמן התריס ייפתח. שם נוסף למצב זה, הוא Shutter Priority.

על מה משפיעה מהירות התריס, מלבד החשיפה ?

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

Doggy (2)

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

חשיפה ארוכה מאפשרת להציג תנועה דווקא בצורה מרוחה. הנה דוגמא, מרחוב קינג ג'ורג' בתל-אביב:

Motorcycle

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

שליטה על מפתח הצמצם - מצב הצילום Av

במצב הצילום Av, המצלמה מאפשרת לנו לבחור את מפתח הצמצם, ובד"כ את רגישות החיישן גם. בעת לחיצה על כפתור הצילום, המצלמה תבחר לבד את מהירות התריס הדרושה לה, בהתאם לרגישות החיישן ומפתח הצמצם שבחרנו, כדי להגיע לחשיפה טובה. מפתח הצמצם נמדדת ביחידות משונות שנקראות F-Stops, והן עובדות "הפוך" - מספר גדול יותר מייצג צמצם סגור יותר, ולהיפך (לחנונים אמיתיים: זוהי בעצם פונקציה מעריכית: הסימון 5 על המצלמה מייצג f/5, שזה יחסית פתוח, ו- 22 מייצג f/22, שזה יחסית סגור).
מצב זה נקרא גם Aperture Value, או Aperture Priority.

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

מה זה שדה בכלל ?

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

Garden Flower

זאת תמונה שצולמה מאוד מקרוב (מה שנקרא, Macro Photography, ועל חלק מהמצלמות מסומן ע"י הסימן של הפרח) בשעה עשר וחצי בבוקר, ביום בהיר עם הרבה שמש (וזאת התמונה האהובה על החברה שלי!) בגינה. הפרח שהיה הכי קרוב למצלמה נמצא לא בפוקוס, פשוט כי העדשה לא מסוגלת להתמקד על משהו שהוא כ"כ קרוב - אבל הרקע של התמונה גם מטושטש, וזה, בגלל שהרקע לא נמצא בשדה של התמונה - אלא "עמוק" יותר (שוב, לחנונים אמיתיים, רחוק יותר על ציר ה-Z, כאשר התמונה עצמה (~החיישן) היא מישור XY). בגלל שזה היה יום כל-כך בהיר, המצלמה בחרה לקבוע את מהירות התריס ל- 1/1600 שנייה (שזה 0.000625ש', שזה מהיר יחסית), ולכן, למרות שהיתה קצת רוח, בכלל אין Motion Blur.

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

Navit in Amsterdam

(צולם באמסטרדם, בשעה 13:30 בצהריים, עם צמצם פתוח (f/3.1) ומהירות תירס ממוצעת (1/640ש'). היינו מייד אחרי הטיסה, וקצת הלכנו לאיבוד בדרך למעוננו שם - בגלל זה הפרצוף המייואש...)

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

ואם אני רוצה את הכל?

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

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

Tel Aviv at night

התמונה הזו צולמה אחרי השקיעה, בשעה 17:40, מחוף יפו לכיוון תל-אביב, עם צמצם מאוד קטן (f/22), על חצובה. היה שם כל-כך מעט אור, שהמצלמה בחרה לבצע חשיפה של 20 שניות. בזכות הצמצם הקטן, לכל האורות יש צורה של כוכב, ולמרות שהבניינים הקרובים קרובים הרבה יותר מהבניינים הארוכים, הכל בפוקוס.

שיקול נוסף - רגישות החיישן

כדי להגביר את רגישות החיישן, המצלמה פשוט מעבירה לחיישן יותר חשמל. כתוצאה מכך, החיישן נהיה יותר רגיש, ולכן הוא 'רושם' יותר אור. זה משפיע מאוד על האלגוריתם של המצלמה - במצב Av, חיישן יותר רגיש יגרום לתריס יותר מהיר, ובמצב Tv, יגרום לצמצם סגור יותר - אבל יש לו תופעת לוואי - הוא גורם לרעש על התמונה (Noise, או Grain - זה בולט במיוחד כאשר מצלמים בלילה במצלמות וידאו).

מילים אחרונות

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

אם שדרתם עד כאן,
נאחל לכם וארץ ישראל יפה,
וצילום נעים!

More Posts Next page »