Friday, November 25, 2016

The art of note taking

Over the years, my note taking has evolved and I developed a system which consists of
  • Point of interest: Similar to ordinary bullet points, usually a dot or an asterix.
  • Action item: Things that I have to do. I encircle a point of interest to mark it as an action item.
  • Done: A check to the left of an action item means that I have completed it.
  • Doodles: Help me concentrate and relax. For the concept of "relaxed concentration", see The Inner Game of Tennis.
At work I copy my handwritten notes to OneNote and throw away the physical paper. For personal stuff, I copy them to Google Drive. Below is an example:

Listening to:

Algorithms in Save My Cheese

In this post, I will go into the algorithmic details of Save My Cheese. The game consists of several sub-problems:
  1. Drag and snap shapes.
  2. Calculate path from where the mouse is to cheese location. Pathfinding has to take obstacles (unpassable cells) on map into account.
  3. Update map when user places a piece in its place, i.e. make that portion of map unpassable so that a new path to cheese might be needed.

Thursday, November 24, 2016

Converting a desktop game to a web app

Two years ago, I wrote a simple desktop game, Save My Cheese, mainly to explore the A* pathfinding algorithm. In the game you are trying to block the path of mice by puzzle pieces and prevent the mice from reaching the cheese. When you finish the puzzle before the mice reach the cheese, you finish that level.

Monday, November 21, 2016

Geoid

Recently I was testing Matlab2012a geoid functions of which there are two: geoidheight (in Aerospace Toolbox) and egm96geoid (In Mapping Toolbox). I wrote the following script to check if there is a difference between these two function results for the same inputs (takes about half an hour to run):
clc; clear all;
[NVec,refvec] = egm96geoid(1, [-89.75  89.75],[-180 180]);
i = 0;
for lat_deg = -89:89
    fprintf(1, 'lat_deg = %1.1d\n', lat_deg);
    for lon_deg = 0:360
        i = i+1;
        N1_m(i) = geoidheight(lat_deg, lon_deg); %#ok<*SAGROW>

        N2Linear_m(i) = ltln2val(NVec,refvec,lat_deg,lon_deg,'bilinear');
        N2BiCubic_m(i) = ltln2val(NVec,refvec,lat_deg,lon_deg,'bicubic'); %to check if interpolation method makes any difference
    end
end
diff1 = N1_m-N2Linear_m;
diff2 = N2BiCubic_m-N2Linear_m;
subplot(2,1,1)
plot(diff1)
ylabel('diff1')
grid on
subplot(2,1,2)
plot(diff2)
ylabel('diff2')
grid on

As you can see from the plot, the difference between the two functions (diff1) can be as high as 7m! I checked the results with the zip files from NASA EGM96 and found that geoidheight is within 0.01m. This means that there is something wrong with egm96geoid or ltln2val.

Conclusion: Use geoidheight to get geoid offsets. Do not assume that Matlab's functions are correct and ABT (Always be testing). This error seems to be fixed in Matlab 2014 and later versions.

Saturday, November 05, 2016

My software development cycle

When developing software, after getting the overall customer requirements, I first design a little bit, then add some features, fix bugs, then do refactoring and then repeat. While refactoring, I do not attempt to fix bugs or update the overall design. When I see a serious (i.e. more than a days work) bug or the need to update the design of some part, I write it down to Jira. That way I am not distracted from what I do for short term and do not loose my ideas for the long term. I call this the "zoom-in, zoom-out cycle".


GSON

I needed to use GSON to create a JSON string to serialize an object. It is quite easy for simple objects but if your object has fields with NaN values or lists of another class type, it gets a little complicated. After I solved all these problems, the final form of GSON call was:
Gson gson = new GsonBuilder().registerTypeAdapter(MyObj.class, new MyGSONTypeAdapter()).serializeSpecialFloatingPointValues().excludeFieldsWithModifiers(java.lang.reflect.Modifier.TRANSIENT).create();
String jsonStrToSave = gson.toJson(myObj);
Details:
  • GSON does not generate data for
    • private fields without public set/get.
    • null objects
  • To include NaN in JSON string you have to call serializeSpecialFloatingPointValues().
  • To save static fields or to exclude fields, you add the transient keyword to class's field definition and call excludeFieldsWithModifiers(Modifier.TRANSIENT).
  • If your class has lists of other objects, you might get stack overflow error. One way to solve it is to define and register an adapter class. Example:
/**
* GSON type adapter class to solve stack overflow error.
* Assumes you have a class called MyClass with getVal() method.
*/
class MyGSONTypeAdapter <T extends MyClass> extends TypeAdapter {

   @Override
   public void write(JsonWriter writer, T t) throws IOException {
       if (t == null) {
           writer.nullValue();
       } else {
           writer.value(t.getVal());
       }
   }

   @Override
   public T read(JsonReader reader) throws IOException {
       double val = reader.nextDouble();
       return (T) new MyClass(val);
   }
}

Tuesday, November 01, 2016

Understanding vs. Explaining

Understanding something is much easier than explaining it. The next time you are about to complain that someone does not understand what you are talking about, ponder how you could explain the topic better. It is also much easier to change your own behaviour than other's.

Tuesday, October 11, 2016

Idea vs. Implementation

Today I talked with my fellow engineers about personal business ideas. I got the impression that they had spend no time in trying to implement even the bare minimum - which makes them fantasies rather than ideas.

Implementation is very important because during implementation, you become aware of technical, time and cost constraints. You also might get new ideas, it trains you in how to develop ideas. As an example, let's say you want to build a new über-coffee machine that can be installed in university campuses. Before getting into the technical details of the machine, you should call the university and see if you can talk with someone that is in the position of authorizing coffee machines on campus. Even if you get a negative response, you will have practiced talking with strangers about money and business.

I do not take seriously any idea which is not backed up by some effort. That's why I am trying things out even if they almost certainly will not become a business. They will serve as self-education and inspiration - an incubator of other ideas.

Converting Legacy Code to MVC

I am currently converting a legacy 50KLOC Java application to MVC. After a few days of analysis, I concluded that the View-Controller (VC) part is quite complex and I should first focus on isolating the model classes. When isolating them, I also remove dependies to VC classes. That way, I will be able to have independent, resusable model code in a fairly short amount of time. If time runs out before I finish the VC part, I will still have accomplished something.

Tuesday, September 27, 2016

Lego Mindstorms EV3

A couple of months ago, I purchased Lego Mindstorms EV3 31313. I am very satisfied, it exceeded my expectations. It lets you build and program robots without bothering you with time consuming electrical/electronic details.

When programming it, I noticed that some things that would be very easy with languages like Java or C# take longer with the EV3 programming environment. As an example, I wanted to record the reflected light intensity from the color sensor for 5 seconds and then display the largest value. Below you can see the screen shot of the program. You can download it from my GitHub lego repo.


Update October 2016: I started teaching robotics to a 13 year old son of a relative. You can see our first video here.

Thursday, September 01, 2016

Keywords in code comments

When writing comments in my code, I sometimes use HACK, TODO and NOTE keywords to mark that comment as especially important. I can easily search for these keywords to find the comments and review the code.

HACK: Used for sections that are not obvious/easy to understand. Worse, one might misunderstand and try to change the code.
Examples:
/* HACK: Do scrolling back and forth so that active tab will be visible even when the there are multiple tabs and the active tab does not fit pane. This happens after the fourth tab, i.e. the 5th tab is created and selected but is not visible on frame. Worse, the right arrow of tabbed pane is disabled. I only could come up with this hack to solve it. There must be a better solution... */

/* HACK: Analyze stack trace to check if call was due to mouseRelease because we need to ignore the other calls due to mouse press and click to prevent adding the same point twice. */
TODO: Used for remaining work.
Examples:
//TODO: When is this called? I could not get here by closing the window.

//TODO this calculation has to be updated when user changes height.

//TODO: To have correct normals, vertex orders have to be the same. It will show its effect when CULL_ is selected.

//TODO: Add reference.

//TODO: Enable this try-catch when color problem is resolved.

//TODO: Should we also issue an error message?

//TODO This method similar (same?) to the method in Sphere.

//TODO Review this validity check.

//TODO : Due to a bug, it starts from t = 1 second.
NOTE: I add this keyword to sections where in the past I changed the code to a seemingly better form and failed because I did not think about some edge cases. The next time I am tempted to change the code, I read the comment and think twice.
Examples:
//Note: You cannot use showException() here because that would cause recursive calls and lead to stack overflow.

//Note: We cannot load the same dll two times in a row, even after garbage collection. But we can load it after a different one has been loaded.

//Note: In order the use invokeLater here, the whole GUI creation process has to be refactored, i.e. couple of days work.

//NOTE: We had to use JButton instead of JLabel because only JLabel does not gain focus while JButton can.

//Note: mousePressed is more responsive than mouseClicked.

//NOTE: Do not perform lengthy operations (e.g. setting font to bold) inside this paint method because it causes 100% CPU load.

//Note: Math.IEEEremainder(10.04, 10) = 0.03999999999999915

/* NOTE: Due to precision limitation (15 digits after decimal point) of double, Long.MAX_VALUE + 1024.0 is the same as Long.MAX_VALUE. Only after +1025.0 are we able to see a difference. double d = Long.MAX_VALUE results in a double value of 9.223372036854776E18 although Long.MAX_VALUE = 9223372036854775807 = 9.223372036854775807E18. The last three digits (807) are lost due to rounding during double conversion. Same is true for lower bound. */

Saturday, August 13, 2016

What makes software development difficult

The Law of Leaky Abstractions: "...suddenly one day we need to figure out a problem where the abstraction leaked, and it takes 2 weeks."

I don't have time to read the spec of every function before using it, I make assumptions based on the name of the function. This means that I take risks by using something without completely understanding it. The benefit is speedy development. As long as the problems are limited to a couple of things that leak, it is manageable by testing and debugging. But sometimes many of them team up and you have a "bugfestation". Unfortunately, even one simple error can crash and burn the whole system in unpredictable ways.

Example1: I assume that the strlen function in C returns the whole length of the string and use strlen result in malloc. Later I am greeted with system crashes which happen only on some versions of Windows. After months of debugging looking for the bug in unrelated places, I realize that strlen does not return the terminating null character and in malloc you have to do strlen+1.

Example2: I write a script to synchronize my drive to my network backup. Then I realize that some folders were not copied. After analysis I see that xcopy fails with "insufficient memory" error when path+file name is longer than 255 characters, but I don't infer that at first from the error message. A better message would be "file name longer than 255 characters". It would be even better if xcopy didn't have this limitiation in the year 2016!

Example3: I assume NASA code is correct, but that is not always the case.

Example4: I assume MATLAB functions are correct, but that is not always the case. The more depressing fact is that the MATLAB folks will resist your claims, even after you mathematically demonstrate that there is an error.

These issues make self discipline and testing early/often so critical. It's also the reason why 95% of code takes 95% of the time and the remaining 5% take another 95% of the time, because in the last 5%, you realize that libraries you trusted had errors in them. Therefore it is common to be late by at least 2x the planned time.

Bonus: Case of the Unexplained

Friday, August 12, 2016

What do I add to science?

From time to time, during discussions with my fellow engineers, the question of what we add to science comes up. To contribute something new to existing science knowledge is very challenging. If you focus on newness you might feel bad, and it might not help you move forward. My approach is to make sure that I get better at something everyday. That thing might not be new for science, but it will be new for me.

A similar post: Obsession with authenticity

A software training instructor's interesting observation [Hanselminutes podcast 331]: Men do a small thing and feel amazing while women worry about the stuff that is still left.

An example of a small step for mankind but joy for me, my very first Lego Mindstorms EV3 line follower:

Sunday, May 22, 2016

Life as a Game

I like computer games. In the past, I played Starcraft to the point of exhaustion, playing it more than 10 hours at a time for days. The problem with games is that they don't add much to your life. Besides, games are not all fun. Every game I played had a lot of boring repetitive tasks, which resembles real life in that respect.

A good game starts simple and builds up over time whereas in real life I am usually confronted with a large mess. That is what makes games fun and real life a chore. A main reason of procrastination is that I don't know where to start, so I keep postponing it. When I spend some extra time to analyze the problem and divide it into smaller pieces, it becomes manageable, even fun. Writing down what I think helps a lot. And when I solve a problem in real life, I gain skills that I carry with me my whole life, besides having the satisfaction of doing something useful and being able to control my environment.

I still play games (currently Clash of Clans) but I only spend about half an hour a day. I have more fun doing real things (teaching my 4 year old, learning how to make Mousse, developing web apps). I encourage you to view life as a growth opportunity, as a game where every skill you gain unlocks new ones. The key is mentally breaking large chunks of work down into less threatening smaller ones. These small chunks can be dealt with as if they were levels of a larger game.

Inspiration:



Saturday, May 21, 2016

Puana Göre Üniversite Sıralama

İstediğin taban puan aralığını girip üniversitelerin bölümlerini sıralayabileceğin bir web uygulaması oluşturdum, linki şu: http://universite-sorgulama.appspot.com/

Kodu GitHub'a koydum, meraklısı oradan inceleyebilir.

Başkaları tarafından yapılmış daha profesyonel hali: http://universitetercihleri.com/ygs-lys-tercih

Sunday, May 08, 2016

Graphical User Interface Nightmares in Java

Compared to Windows Forms, doing GUI work in Java is painful because you have to deal with a lot more detail. Recently, I was trying to customize tab drawing in JTabbedPane to make the font of the selected tab bold and its background color green. I ended up creating a class (MyTabbedPaneUI) that extends BasicTabbedPaneUI and overrides paintTabBackground().
public class MyFrame extends javax.swing.JFrame {
    public MyFrame() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        javax.swing.JTabbedPane jtp = new javax.swing.JTabbedPane();
        getContentPane().add(jtp);
        jtp.setUI(new MyTabbedPaneUI());
        jtp.add("My Tab 1", new javax.swing.JPanel());
        javax.swing.JLabel jl1 = new javax.swing.JLabel(jtp.getTitleAt(0));
        jtp.setTabComponentAt(0, jl1);
        jtp.add("My Tab 2", new javax.swing.JPanel());
        javax.swing.JLabel jl2 = new javax.swing.JLabel(jtp.getTitleAt(1));
        jtp.setTabComponentAt(1, jl2);
    }
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MyFrame().setVisible(true);
            }
        });
    }
}
public class MyTabbedPaneUI extends javax.swing.plaf.basic.BasicTabbedPaneUI {
    /**
     * NOTE: Do not perform lengthy operations (e.g. setting font to bold) 
     * inside this paint method because it causes high CPU load and has 
     * side effects like not being able to update java3D drawings.
     */    
    @Override
    protected void paintTabBackground(Graphics g, int tabPlacement, 
                       int tabIndex, int x, int y, int w, int h, 
                       boolean isSelected) {
        for (int i = 0; i < tabPane.getTabCount(); i++) {
            Color bgColor = Color.YELLOW;
            javax.swing.JLabel jl = (javax.swing.JLabel) 
                tabPane.getTabComponentAt(i);
            if (jl != null) {
                if (i != tabIndex) {
                    bgColor = Color.GREEN;
                    //jl.setFont(jl.getFont().deriveFont(Font.PLAIN));//BAD
                } else {
                    //jl.setFont(jl.getFont().deriveFont(Font.BOLD));//BAD
                }
            }
            Rectangle rect = rects[i];
            int pad = 2;
            g.setColor(bgColor);
            g.fillRect(rect.x+pad, rect.y+pad, rect.width-2*pad,
                rect.height-2*pad);
        }
    }
}
Setting font to bold (by uncommenting the lines commented as "BAD") in BasicTabbedPaneUI.paintTabBackground causes more than 7x CPU usage:


I have witnessed cases where CPU usage shot up to 100% and my app could not update a java3D drawing on another window. You can imagine that it was not easy to find out why.

Other examples of why Java should be avoided for GUI work:
  • Changing color of a JTable cell is a lot of work.
  • For background color to have any effect, JLabel has to be opaque while JTextArea has to be not opaque (opposite of their defaults)!
  • Due to the unintuitive layout mechanism, what I see on design view is completely different from what I see when I run the application.
  • When I change the layout, sometimes all the components dissappear (their width and height becomes zero).
  • Setting the width/height to "Preferred" sometimes causes the component to shrink to zero size. From what I understand, the layout mechanism is there to ensure proper resizing, i.e. to have a similar look when screen resolutions, font size etc. change. As usual, when trying the solve the most general case, you make it more difficult to solve simple cases.
  • To properly set size of a JFrame or JDialog, calling setPrefferedSize() is not enough, you have to call pack() afterwards.
  • When, in design mode, you rearrange buttons, labels or when you just change the border of panels, NetBeans might convert them to local variables and you have to manually convert them back to private to be able to reference them.
  • 10.04.2019: If you have rows of panels and want to use a JPanel instead of JTable to house subpanels, you have to call JPanel.setPreferredSize() and then revalidate() / repaint() for JScrollPane to update itself. JTable complicates matters due to it's editor / renderer mechanism, so use JPanel whenever you have a panel inside a table.
  • 10.04.2019: If you have a JFormattedTextField with latitude format in it, you might need to call JFormattedTextField.commit() when you edit the text and want degree sign to remain in field.
My layout strategy:
  • Create a frame
  • Add a panel with null layout.
  • Add subpanels to group components
  • Set the layout of subpanels. The layouts I use most often:
    • null
      • Advantage: You can set the location and size of components.
      • Disadvantage: If your form is resizable, components won't resize.
    • GridLayout;
    • BoxLayout
  • With null layout, to set location and size, use setBounds() instead of setPreferredSize().

Thursday, March 31, 2016

How to improve quality of legacy software

When developing software from scratch, I follow these steps: Use cases (aka concept of operation), requirements, design, code & unit tests, system test planning, system test.

Recently, I was asked how to improve the quality of a software written by other people a couple of years ago. I was informed that it was working, the only missing thing was compliance to software development procedures. I recommended to do the above sequence in reverse, i.e. first planning and executing full system tests. That way, we can answer the most important question, "is it working correctly". After we are satisfied with the tests, we can review and document the design and refactor code.

Even if we have to stop after testing, we will have added value to the existing product by being able to demonstrate in a repeatable manner that it is working. If we started the development sequence from the beginning and had to stop midway due to other priorities (which always happens), we would have wasted our time.

Wednesday, March 30, 2016

Model simplification strategies for testing

When developing complex models/algorithms, it is usually difficult to evaluate full model test results. The only option to verify complex model output is to compare it with some other implementation, for example Matlab toolboxes.

In addition to using 3rd parties for comparison, you should add functionality that lets you to simplify the model to a form whose results can be easily interpreted by a technical person. For example, if you are working on an algorithm that converts Geodetic coordinates to ECEF, you could have a function that temporarily sets the ellipsoid to a sphere (by making the eccentricity zero). It is easy to calculate expected results for a perfect sphere.

Similarly, if you develop a kinetic 6DoF flight simulation, you should have functions or flags that let you easily turn off complicating factors like aerodynamics (by multiplying coefficients with zero), wind, variable gravity, Coriolis, ellipsoidal Earth and terrain elevation. Your aim is to simplify your model to a ballistic flight in vacuum with constant gravity over a flat and non-rotating Earth. You can then use high school physics to calculate expected trajectories and compare them with your model outputs.

To clear doubts about your code, you should be able to quickly show that it obeys basic geometrical/physical laws.

Saturday, March 19, 2016

Error in NASA code

NASA World Wind java code is available on the internet. While looking at the their SDK2 EGM96.java file, I discovered that the simple two dimensional linear (bilenear) interpolation code has an error. The original code:
...
double ul = this.gePostOffset(topRow, leftCol);
double ll = this.gePostOffset(bottomRow, leftCol);
double lr = this.gePostOffset(bottomRow, rightCol);
double ur = this.gePostOffset(topRow, rightCol);

double u = (lon - lonLeft) / INTERVAL.degrees;
double v = (latTop - lat) / INTERVAL.degrees;

double pll = (1.0 - u) * (1.0 - v);
double plr = u * (1.0 - v);
double pur = u * v;
double pul = (1.0 - u) * v;

double offset = pll * ll + plr * lr + pur * ur + pul * ul;
...

I prepared a schematic to visualize the algorithm:


As you can see at the end of above code snippet, the offset formula starts with pll*ll. pll is (1.0 - u) * (1.0 - v). The correct multiplier of the ll term has to be v*(1-u).

A quick sanity check: Consider the case when lat=latBottom and lon=lonLeft, i.e. the lower left corner. In that case we expect the offset to be equal to ll. Plugging in the values we get v=1, 1-v = 0 and u=0, 1-u = 1. If we use the original (wrong) formula we get offset = 1*0*ll + 0*0*lr + 0*1*ur + 1*0*lu = 0 which is clearly wrong. If we use the corrected formula we get offset = 1*1*ll + 0*0*lr + 0*1*ur + 1*0*lu = ll which is the expected result.

The easiest way to fix the code is to swap the topRow and bottomRow indices when calling getPostOffset() function.

I guess the error was not detected since results do not differ too much because, although the points are used in wrong order, they are close to each other nonetheless, so the result might not have looked suspicious.

I tried to log a bug report on their Jira site, but I could not since I don't have an account. I was able to file a bug report on GitHub.

Lessons learnt:
  • Thoroughly test 3rd party code, even if it is from NASA or Mathworks. Every code is guilty unless proven innocent. Ignore this advice and you will find yourself chasing strange errors for a very long time.
  • Separate interpolation code into a function, write lots of unit test for that function to verify that it works correctly.

Good error messages

A good error message should contain the following:
  • Short description
  • What triggered the error?
  • What was expected?
Example: User inputs a negative value (-5) into a function foo that only accepts positive integers. A message similar to the following should be displayed:
Negative input!
The input value was -5. Function foo only accepts positive integers.

Tuesday, February 23, 2016

Çocuk yetiştirmek

Artık 3.5 yaşında olan oğlumuz Argun'un büyüme macerası ilginç derslerle doluydu. Bu derslerin Argun'un yapısı ile yakından alakalı olduğunun ve benzer çocuklarda (hareketli, neşeli erkek çocuk) daha çok işe yarayacağının farkındayım ama sanırım başka çocuklar için de geçerli şeyler vardır.

Başlangıçta çirkin bir ördek yavrusu olan Argun sonradan şirin bir çocuğa dönüştü:

Ana hatları ile gelişimi şu şekilde oldu:
  • 1. yaş: Yürüdü (herhangi bir yerden destek almadan beş adım atabildi)
  • 1.5 yaş: Kreşe verdik, ancak üç haftalık deneme süresinin ardından Argun'un henüz kreşe hazır olmadığına karar verip geri aldık.
  • 2. yaş: Cümle kurmaya başladı, emziği bıraktırdık.
  • 2.5 yaş: Kreşe tekrar başladı. Bezini bıraktırdık.
Yakın çevremdeki ebeveynleri izlediğimde çocukla ilgilenmenin çocukların özgürlüğünü ellerinden alacak boyutlara vardığını görüyorum. Muhtemelen onlara beni sorarsanız benim aşırı ilgisiz olduğumu söyleyeceklerdir (!)

Eski zamanlarda geçim derdiyle uğraşmaktan çocukla uğraşmaya pek zaman kalmıyordu, yedirecek şey sınırlıydı, götürecek doktor yoktu. İyi tarafı çocukların daha özgür olmalarıydı. Şimdilerde maddi olanaklardaki iyileşmeler ebeveynlerin ilgi, şefkat adı altında çocuklarının her işine karışan, sürekli kreşi telefonla arayan, en sıradan ateşte acillere koşan stres ve endişe küplerine dönüşmesine neden oluyor. Hem çocuklar zarar görüyor, hem de kendileri. Zaten yeterince zor olan şehir hayatı çocukla birlikte çekilmez hale gelebiliyor.

Çocuğun en önemli ihtiyacının özgürlük olduğunu düşünüyorum. Özgürlükten kastım kendi yardım talep etmedikçe veya geri dönülmez zarara uğrama ihtimali olmadıkça çocuğu rahat bırakmak. Küçük çocukların neredeyse tek öğrenme biçimi deneme yanılma. Denemesine izin vermek gerekiyor. Örneğin parka gitmişsek ve Argun birkez bile canı yanıp ağlamadan dönüyorsak bunu kayıp olarak görürüm çünkü sınırlarını yeterince zorlamamış ve yeterince öğrenmemiş demektir. Aşağıdaki videoda Argun bizim gözetimimizde iğne ile dikiş öğreniyor ve arada parmağına iğneyi batırıyor:


Bundan sonraki dönemde bizim işlevimiz Argun'a öğrenmeyi sevdirmek. Matematikten tarihe kadar her konunun ilginç bir özü, zengin gelişim öyküsü var. Biz bunları örneklerle, gezilerle, deneylerle verebiliriz. İlham için YouTube'daki Veritasium ve MinuteEarth kanallarına veya benim Science Experiments listeme bakılabilir.

Her çocuğun öğrenme biçimi farklı. Özellikle spor ve dans gibi bedenin karmaşık şekillerde kullanımını gerektiren aktivitelerde benim gibilere alt adımların anlatılması gerekir. Anlatılmayıp "benim yaptığım gibi yap" yöntemi uygulandığında başarılı olmam tesadüflere bağlı oluyor. Ortaokulda bir voleybol antrenmanında yeni gelen beden öğretmeninin benim bir hareketi yapamamam sonrası "sen nasıl okul birincisi olmuşsun, hayret" alaycılığı hala aklımdadır. "Seni başımıza öğretmen diye dikenlere lanet olsun" derdim içimden yüzüne karşı (!) Çocuğunuzun iyi bir öğrenim hayatı geçirmesini istiyorsanız bunu sadece okullara bırakamazsınız, kolları sıvayacaksınız. Hazır yeri gelmişken spor ve dans eğitiminde kullanılabilecek güzel bir kitap önereyim: The Inner Game of Tennis.
Dersleri listeleyecek olursak:
  • Çocukta karakter sorunu varsa ebeveyn önce kendine bakmalıdır. Kendizini iyileştirin yeter, çocukla uğraşmayın, çocuğa ozmozla geçer (!)
  • Ebeveynin rahatı da en az çocuğunki kadar önemlidir. Çocuğa ne kadar çok emek harcarsanız o kadar çok yorulursunuz ve çocuğa/eşinize/çevrenize kötü davranma olasılığınız artar. Enerjiyi idareli kullanın.
  • Ağlamasına müsaade edin ama ağlama için evin belli bir yerini kullabileceğini, her yerde ağlayamayacağını söyleyin. Ağladığı zaman kucaklayıp ağlama yerine bırakın, ağlaması bittiğinde geri gelebileceğini söyleyin.
  • Eğer yemek, banyo, uyku gibi önemli bir konuda çocuk itiraz ediyorsa bir-iki cümle ikna denenebilir, olmuyorsa aksiyona geçilir. Örnek: Sebze değil, pilav yemek istiyor. Sebze yedikten sonra pilav yiyebileceğini söylüyorum, tabii ki kabul etmiyor. Mutfaktan çıkarıyorum, ağlıyor, mutfakta ağlamanın yasak olduğunu, ağlama yerinin antre olduğunu söyleyip çırpınan Argun'u kollarından kaldırarak antreye götürüp bırakıyorum. Birkaç git-gelden sonra (15 dakika) ikna oluyor ve sebzesini yiyor.
  • Yemek yemeyi kendi talep etmeli, bir gün boyunca aç kalması göze alınmalı, iki öğün arasında yiyecek verilmemeli. Yemeği kendi talep ettiğinde hem yemeye ebeveyni tarafından zorlanıp özgürlüğü elinden alınmış olmaz, hem de yemekle sıkıntıyı değil, keyfi ilişkilendirir.
  • Çocuğa akıl vermeyi minimumda tutun. Örneğin yolda yürürken düşme riski var ancak düşerse en fazla bir yeri moraracaksa "düşersin" gibi uyarılarda bulunmayın. Parkta oynarken neyi nasıl yapması gerektiğini söylemeyin, kendisi düşe kalka keşfetsin.
  • Gün içinde çok sayıda eğitim fırsatı var. Örneğin masadaki kuruyemişleri yere saçmışsa bunun bir fırsat olduğunu hatırlayın. Kabukları toplamasını isteyin. "Topladım" dediğinde yerde kalan küçük parçaları gösterip "bunları da toplar mısın" deyin, bu işlemi en küçük parça bile toplanana kadar tekrar edin. Kritik olan sizin sabırlı, sakin ve kararlı olmanız. Böyle basit bir olay bile çocuğa dikkatten işini iyi yapmaya kadar çok şey öğretir.
  • Çocuğun işin içinde olduğu organizasyonları sakın aceleye getirmeyin, geniş bir zaman ayırın, yoksa sabırlı olmanız mümkün olmaz.
Kolaylıklar dilerim.

Güncelleme 21 Kasım 2016: 4 yaşını geçen Argun artık tablet bağımlısı oldu, eğer müdahale etmezsek sabahtan akşama kadar öğle yemeğini dahi ihmal ederek oynayabiliyor. Oynama süresini hafta içi 1 saat, hafta sonu 3 saat civarında sınırlıyoruz. Tabletin birtakım zararları (instant gratification, boyun fıtığı, yaşına uygun olmayan videolar izlemesi vb.) olabileceğini biliyorum. Bu zararlar süre sınırlama ve tablet tutucularla kabul edilebilir boyutlara indirilebilir. YouTube Kids bir gün Türkiye'de kullanıma sunulursa zararlı video da büyük ölçüde halledilir.

Elbette çocuğun öncelikli ihtiyacı başka çocuklar. Ancak şehir ortamında çocukları haftada birden fazla bir araya getirmek zor. Tabletin epeyce yararı var. Örneğin ebeveyne nefes alacak zaman kalıyor, oyunlar zekayı geliştiriyor, videolarla kendini eğitip oyuncakların kullanımını öğreniyor. En önemlisi de Argun yemek, uyku gibi tartışılmaz kurallara mızmızlandığında (istisnasız her gün) sakince "böyle devam edersen bugün tablet yasak" demek onu %50 oranında hizaya getiriyor. Diğer %50'de ceza vererek tablet süresini de doğal olarak sınırlanmış oluyoruz.

4 yaşın bir diğer güzelliği mantıkla ikna edilebilirliğinin artması. Örneğin sevmediği bir yemeği yemesi için aşağıdaki dialog işe yarayabiliyor:

Argun: Ben bu yemeği sevmiyorum!
Şamil: Ben de sevmiyorum ama güçlenmek için yiyorum, yoksa kolay hasta oluruz. Hasta olmak istiyor musun?
Argun: Haayıır (suratını ekşiterek gönülsüze yemeğini yer).

Tabi her zaman işe yaramıyor, o zaman tablet ceza tehdidi imdada yetişiyor :P

Güncelleme 2 Temmuz 2017: 4.5 yaşındaki Argun yemek yemekten hoşlanmıyor, görev olarak yapıyor. Bu nedenle ona bırakırsak savsaklıyor. "Ne yemek istersin" gibi sorular uzun bir pazarlıkla sonuçlanıyor, sürekli oyalanıyor ve masadan kalkması neredeyse 1 saat sürüyor. En etkili yöntem ona sormadan tabağına yemesi gereken her şeyi koyup mutfaktaki duvar saatinde 10 dakika sonra çizgisine işaret edip yelkovan oraya geldiğinde tabağındaki her şeyi bitirmiş olması gerektiğini, yoksa o gün için tabletle oynayamayacağını söylemek. Eğer 10 dakika sonra bitmemişse o gün için tablet cezası verip beş dakika sonra bitmemişse yarın da cezalı olacağını söylüyorum. Her ek beş dakika için ek bir gün ceza alıyor. Yaşasın cezalı eğitim :P

Thursday, February 11, 2016

Finding the Intersection of Lines

The classical y = m*x+n line equation fails when finding intersections with vertical lines. Normally, the intersection point of two lines is found as follows:

Y = m1*x+n1 = m2*x+n2 --> x = (n2-n1)/(m1-m2)

Consider the following example, which clearly has an intersection at x = 1 and y = 0.5:

The classical equation for line AB results in m1 = infinity and n1 = -infinity, and for CD results in m2 = 0.5, n2 = 0. When you plug these values into x = (n2-n1)/(m1- m2), you get x = (0 - (-infinity)) / (infinity - 0.5) = infinity/infinity = NaN.

You could try to solve this problem using a bunch of if statements to check if a line is vertical, horizontal etc which would be prone to bugs. Or you could use parametric line equations:

Applying the above parametric formula to our example problem, we obtain the following equations:

Line1: P1 = A + (B - A) * t
Line2: P2 = C + (D - C) * u

To find the intersection point we equate P1 to P2:

A + (B - A) * t  = C + (D - C) * u.

Using scalar components:
Ax + (Bx-Ax)*t = Cx + (Dx-Cx)*u --> Ax-Cx = (Ax-Bx)*t + (Dx-Cx)*t
Ay + (By-Ay)*t = Cy + (Dy-Cy)*u --> Ay-Cy = (Ay-By)*t + (Dy-Cy)*t

Rearranging into matrix form:

| Ax-Bx, Dx-Cx | |t|  = |Ax-Cx|
| Ay-By, Dy-Cy | |u| = |Ay-Cy|

We can solve this M*TU = K system and obtain t and u values: TU = M^-1*K. t and u are -0.25 and 0.5 respectively. Finally to get intersection x,y coordinates, we can use

xIntersect = Ax + (Bx-Ax)*t
yIntersect = Ay + (By-Ay)*t

Which gives us the correct result of (1, 0.5)

An additional benefit of the parametric line equation is that it can easily be extended to three dimensional space. It is also used in calculating intersection lines with a planes.

Lesson learnt: Don't use y = m*x+n, instead use P = A + (B - A) * t

Wednesday, January 27, 2016

Basic Software Design Report

A software design report should mainly answer "why" more than "how", because you might learn the "how" by looking at the code but not the "why". It should contain as a minimum the following:
  • Definition of problem
    • Why are you tackling this problem, where will the design be used?
    • Where will the resulting software be integrated to?
  • Sequence diagram of main flow
  • Class diagram showing most important classes
  • Constraints (time, memory, programming language due to platform to be integrated to etc.)
  • Detailed description of inputs from outside and outputs to outside (definition, data type), i.e. API
  • Explanation of non-trivial algorithms, selection reason of particular data structures, complexity analysis.
  • Design principles:
  • Error handling and logging