life, software,

Decision Matrix

I would like to demonstrate a technique I occasionally use to help me make a decision. I call it the “decision matrix”.

In our sample case, Joe needs to decide between 3 job alternatives:

  1. Join ABC Consulting and become a consultant. This is a top paying position with a high demand for overtime.
  2. Become a freelancer. This alternative lets Joe be free and flexible, but he would have zero income in periods he can’t find a contract.
  3. Join XYZ Merchandise and become a co-worker. This is a relatively easy job with a fixed schedule and medium income.

Let’s implement the decision matrix for Joe and help him decide.


First, Joe needs to write down his interests. Those are the direct or indirect things affected by his job decision.


Let’s break them down to understand Joe better:

  • Money: Self-explaining.
  • Time for hobbies: Joe is the sax player of a local band. He treasures his free time to study, rehearse and play live.
  • Big brand: Joe thinks that working for a big brand is important for his CV.
  • Self development: Joe expects his position to help him advance further in his profession by providing new learning opportunities.
  • Close to home: Joe hates traffic and it’s important for him to minimize the time lost in the car.
  • Ethic: Joe wouldn’t want to join a company ignorant of the environment.


Now it’s time to determine how important each interest is. For this purpose, Joe will have to assign a weight point between 1-5 to each interest. He will also mark the “show stopper” interests.


In this example, Joe marked “Ethic” as “show stopper”. This means; if a company performs poorly in terms of ethics, Joe will eliminate that alternative directly.


It’s time for Joe to put the job offers into the table. For each alternative, he will assign two columns – you’ll see why soon enough.



In this step, Joe will give points to each job offer; depending on how good they fulfill his interest.


The significant points are;

  • The consulting position (Job 1) has no ethical flaws and pays good, so it gets 5 points for “Money” and “Ethic”. However; due to the high demand for overtime, it would limit his musical schedule; so it gets 2 points for “Time for hobbies”.
  • Being a freelancer (Job 2) also has no ethical flaws and he can make his own schedule, so it gets 5 points for “Time for hobbies” and “Ethic”. However; working for himself is not exactly a “Big brand”, so that interest gets only 1 point.
  • Being a co-worker (Job 3) has mediocre points for each interest.

None of the positions has low points on “Ethic”, so Joe doesn’t have to eliminate any alternative at this time.

Weighted Points

In this step, Joe will multiply the points of each job with its corresponding weight.


If we sum up the weighted points, we see the interest fulfillment power of each alternative.


The table above shows that working as a consultant (Job 1: 80 points) quantitatively fulfills Joe’s interests the best; while being a freelancer (Job 2: 76 points) is a close second. However, becoming a co-worker (Job 3: 62 points) doesn’t seem to be a satisfying alternative.


The decision matrix is a helpful decision making tool, which quantitatively reflects the interest fulfillment rate of each alternative. You can re-use the table of Joe for any decision.

However; no decision should be made with the mind only. We can’t see the future and what the alternatives would bring, so logic alone might not be enough. Ideally; logic, intuition and emotions should be balanced to make a decision.

This tool merely helps to clear up the logic part.


Why I Gave Up Evernote

I used to prefer Evernote (why) over other productivity apps. I thought I’d never do it, but I have moved from Evernote to Apple Notes. Here are the reasons why; in random order.


Cross-device Evernote sync messes up my shortcuts within the app. After carefully organizing the shortcuts on my Mac, I turn on my (normally idle) iPad; which reverts the shortcuts back to the last time I had my iPad on. I couldn’t find any way to disable that.


Despite persistent user requests, Evernote Mac still doesn’t have a dark mode. After activating the dark mode of Mac Os Mojave, Evernote was the only bright & shiny window left, which was undesirable to tell the least.

When using Mojave in dark mode, the list view messes up with random black lines; and I was unable to get this bug through to the development team (read further).

In my opinion; Evernote is slow to follow the visual trends on Mac anyway. It doesn’t feel like a native modern Mac App to me; it sometimes feels like a program running in a virtual box or something.


Evernote editor is not very good if you use a lot of indentation in your notes. You can indent a line, but as soon as you hit enter, the new line starts at column zero. This might be insignificant for many users; but as a programmer working with indentations all the time, I find that frustrating.


I was using the paid version of Evernote, and expected to have a decent support. However; getting a bug or significant request to the actual development team is really painful and time consuming.

First, they assign you a random community member which assumes that you are a random dummy end-user and forces you to walk through uninstallation, deletion of cache and whatnot – which never helped in my cases. Then, you need to provide screenshots and videos; which is fair. But most of the time, the random member told me that this matter is or is not in the development plan; and you can’t get through that.

You can try posting on the forums, but I got no response from Evernote devs from there either. It is so time consuming and frustrating that I totally gave up submitting bugs and suggesting new ideas.


I have noticed that I don’t use most of the paid features at all. The ones that I use are available for free on other platforms. So, it didn’t make sense to keep my subscription active.

I have simplified my productivity workflow; and I don’t need the (otherwise wonderful) tagging / searching / linking / etc. capabilities any longer. The ones I need are available on other platforms as well; such as Apple-scripting, sharing, cross-device availability, etc.

(I am planning to write about my new simplified productivity workflow as well; follow me for updates.)

My Choice: Apple Notes

Looking for an alternative; I have found that the latest version of Apple Notes has all the capabilities I need + better Siri integration. Moving from Evernote to Notes was also very easy; I have simply exported my notes from Evernote and imported them into Notes, and was back to productivity within 15 minutes or so. Here is a useful guide on the subject.

Evernote is still a very good and powerful product though, if you like it and don’t have any frustrations, keep it.


ABAP Kodu Kopyalayarak Program Çalınabilir Mi?

ABAP Nedir?

ABAP, SAP R/3 sistemlerinin yazılım geliştirme dilidir. SAP’nin içerisinde hazır gelen programların tamamı ABAP ile yazılmıştır. SAP üzerinde ek geliştirme yapmak isteyen bir programcı, program kodlarını yine ABAP dili ile yazmaktadır.

ABAP, açık kaynak kodlu bir dildir. Yani; SAP’nin standart programlarına ait kaynak kodları, sisteme giren ve yetkisi olan herhangi bir kişi tarafından serbest bir şekilde kopyalanıp alınabilir. Bir firmanın kendine özel geliştirdiği programların kaynak kodları da, aynı şekilde serbest bir şekilde kopyalanıp alınabilir.

Bu konuda, SAP sisteminin özel bir önlemi bulunmamaktadır. Bilakis; kodların açık olması, hata analizi, yedekleme, program taşıma gibi pek çok işlemi kolaylaştırmaktadır.

Diğer Teknik Nesneler

SAP sisteminde; ABAP kodlarının yanı sıra Table, Data Element, Domain, Structure, Lock Object, Authorization Object, Class, Function, Transformation, Checkpoint Group gibi sayısız teknik nesne bulunmaktadır. Yazılım geliştiren bir programcı, ABAP kodunun yanı sıra, bu ve benzeri nesneleri de oluşturmaktadır.

Bir ABAP programının çalışabilmesi için, kaynak kodunun yanı sıra, sonradan geliştirilmiş tüm bu nesnelerin de sistemde mevcut olması gerekir.

SAP, tam da bu yüzden, geliştirmelerin şirkete ait sistemler arasında taşınabilmesi için Transport Request adı verilen bir mekanizma geliştirmiştir.

Kodların Kopyalanması

Bir programcı, sadece ABAP kodlarını kopyalayarak bir programı bir firmadan bir başka firmaya taşıyabilir mi?

Eğer geliştirme sadece ABAP kodundan ibaret basit bir program ise; evet, bu mümkün olabilir. Ancak, sadece ABAP kodundan ibaret olup diğer teknik nesneleri içermeyen bir geliştirme, muhtemelen görece basit ve önemsiz bir geliştirme olacaktır.

Daha büyük çaptaki programlarda ise; programın kaynak kodlarının yanı sıra, programcının geliştirdiği sayısız yardımcı teknik nesne bulunacaktır. Sadece programın kodlarının kopyalanması, o programın bir başka sistemde çalıştırılabilmesi anlamına gelmemektedir.

Zira; kaynak kodların yanı sıra; yukarıda zikredilen diğer teknik nesnelerin de hedef sisteme taşınıyor olması gerekmektedir. Bu teknik nesneler ise, program kodları gibi kopyala & yapıştır ile alınabilecek karakterde değildir.


Şirketlere ait süreçleri kapsayacak çaptaki bir geliştirme, ABAP kodunun yanı sıra, muhtemelen pek çok yardımcı teknik nesne içerecektir. Bu tarz bir geliştirmeyi, sadece ABAP kodunu kopyalamak suretiyle bir başka firmaya taşımak pratikte pek mümkün gözükmemektedir.

Sadece program kodlarını kopyalayarak bir başka sisteme taşıyabileceğimiz geliştirmeler, teknik anlamda çok basit geliştirmelerdir. Muhtemelen şirket süreçlerini kapsayacak hassasiyette olmayacaklardır.


“NOT EXISTS” Subqueries in ABAP CDS Views

ABAP CDS Views are great and all; however, it doesn’t support subqueries at this time. In this post, I would like to share a workaround which functions similar to “NOT EXISTS”.
The requirement was to exclude material document items (MSEG) which were reverse posted; and the reversal documents themselves.
If I was writing a regular ABAP SQL statement, I could easily achieve this with the help of a NOT EXISTS subquery. Check the code snippet below – I have excluded unrelated WHERE conditions for simplicity.
SELECT mblnr, mjahr, zeile 
  FROM mseg AS mseg1 
    ( sjahr EQ '0000' OR sjahr IS NULL )
    ( NOT EXISTS (
      SELECT mandt FROM mseg AS mseg2 WHERE
        sjahr EQ mseg1.mjahr AND
        smbln EQ mseg1.mblnr AND
        smblp EQ mseg1.zeile
    ) )
  INTO TABLE @DATA(lt_mseg).
This logic doesn’t work in CDS views directly due to lack of subquery support. To get the same result using CDS views, I have split the query into two views. The first one returns a wide list where original and reversal MSEG records are listed side by side.
@AbapCatalog.sqlViewName: 'ZMMV_001'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Original and reversal docs side by side'
  select from
    mseg as mseg1
    left outer join mseg as mseg2 on
      mseg2.sjahr = mseg1.mjahr and
      mseg2.smbln = mseg1.mblnr and
      mseg2.smblp = mseg1.zeile
    mseg1.mblnr as mblnr1,
    mseg1.mjahr as mjahr1,
    mseg1.zeile as zeile1,
    mseg1.sjahr as sjahr1,
    mseg1.smbln as smbln1,
    mseg1.smblp as smblp1,
    mseg2.mblnr as mblnr2,
    mseg2.mjahr as mjahr2,
    mseg2.zeile as zeile2,
    mseg2.sjahr as sjahr2,
    mseg2.smbln as smbln2,
    mseg2.smblp as smblp2
The second view filters out the reversed & reversal documents from the first view, which leaves effective material documents only.
@AbapCatalog.sqlViewName: 'ZMMV_002'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Effective material document items'
  select distinct from ZMMV_MAT_DOC_ITEM_REV_STATUS
    key mblnr1 as mblnr,
    key mjahr1 as mjahr,
    key zeile1 as zeile
    sjahr1 = '0000' and
      mjahr2 = '0000' or
      mjahr2 is null
    ) and
      sjahr2 = '0000' or
      sjahr2 is null
This approach can be implemented to replace NOT EXISTS in many other cases as well.
life, software,

How To Pick A Profession

In this post, I’ll share some hints about picking a profession. This question has been asked me multiple times; therefore, I felt the urge to write a general guidance on the subject.

Basics of Trade

First, we need to focus on the basics. In a primitive community with no monetary system, people would trade goods and services. A hunter would give meat and pelt to a farmer in exchange of fruit and vegetables. Both provide something others need.

In such a community, a painter might find a hard time finding someone to trade because the houses might not have walls at all.

In order to be a part of the trade system and obtain things from others, one needs to provide something that others need.

Today, the same basic principles apply. Although money has become the main media of trading, the basic system of “provide to obtain” is still active. When you provide work, you get money as a symbol that you have provided something. Later on, you can give out this money to obtain another thing you need.

In the light of the basics of trade; one of the first questions that need to be asked is “What can I provide that my community needs?” . If you provide something that no one needs, you can’t expect to obtain anything in exchange.

This question can be broken into a few sub-questions.

What Does Your Community Need?

Analysing the country you plan to live in is an important step.

Different communities have different needs. A painter in an aboriginal tribe might be unemployed, but the same painter can make a living in a modern country. If you studied art history, good luck finding a job in in undeveloped country. You get the idea.

If you are familiar with Maslow’s hierarchy of needs, you can easily relate to the idea that every community has an average place in the needs hierarchy.

An underdeveloped country struggling for nutrition and security has needs on the most basic levels. By default, you would need to focus on those levels.

On the other hand; a well developed country might have diverse needs covering academicians, artists and psychologists. In such a country, you could have a hard time finding a job as a blue collar worker (because production is automated) but might find a place as a shrink.

You need to consider the supply / demand balance of the need as well. You might think that the community needs yoga teachers, but if there are already thousands of yoga teachers seeking students, it means that the market is full and the need is satiated.

Future needs of the community is as important as the needs of today. If you foresee that a profession might be obsolete in 10 years (due to AI, for instance); it makes sense to stay away from it.

What Are You Good At?

Analysing your own strengths is another important step. In my opinion, one should focus on things that he/she does easily and others don’t.

Some tasks can be done easily by anyone because the task is easy. Those can be eliminated.

Some tasks can be done easily by certain people because the tasks comply with his/her strenghts. Those should be inspected as potential professions.

Many people tend to underrate their strenghts because they do it easily. If you do something easily which others don’t; this can lead to your future profession. This doesn’t mean that you aren’t going to work and sweat, but it means that putting the same energy as others will get you farther than others.

Here are some examples.

If you are naturally good at math, you might become an engineer or programmer.

If you feel comfortable with words and are an introvert, you might consider a career in writing or publishing.

If you are a naturally organized extrovert, project management or tourism might be your call.

If you have a strong natural compassion, becoming a social worker might be just the thing for you.

Those over-generalized examples should give you the basic idea.

The school system, or society overall, might have given you the impression that you need to be doing something you don’t like in order to gain something you like. While that might be true in some cases, it is not always true. Be mindful of your pre-learned patterns, and don’t let them make you unconsciously pick a profession where you would struggle for success because it’s requirements are your weaknesses (instead of strengths).

What Do You Love To Do?

Your profession will cover a significant part of your life. If you are not happy on your job, it is improbable to be happy in your overall life.

Confucius said “Choose a job you love, and you will never have to work a day in your life”.

Jessica Hische said “The work you do while you procrastinate is probably the work you should be doing for the rest of your life”.

If you enjoy doing something even without compensation, in your free time, like a game of hobby, turning that thing into a profession might lead you to a happy life.

If you play an instrument in your spare time, you might consider a career on music. If you really enjoy airplanes and heights, why not becoming a pilot? If you create websites and/or small games in your spare time, you might consider a career on programming. If you love animals a lot, how about being a vet? You get the idea.

Realistically consider the future of your beloved hobby though. It would be a good idea to talk to professionals of the field in question to get a better insight about what is involved and expected if your hobby turned into a job.

For example; if you like to drive around and eat donuts in your free time, being a cop may seem appealing to you. However; after talking to a professional and understanding the dynamics of the job, you may start to consider if dealing with criminals is suitable for you or not. So, early reality checks are healthy.

Who Do You Know?

I have seen companies with ~100K employees look for new members through personal reference of the close circle – despite the large CV pool.

Personal reference is a significant factor in many industries. As a fresh graduate, you might get frustrated because your CV is ignored. However, if an influential person provides personal reference, the same company would possibly be willing to meet you.

Industries are actually large communities built of many sub-communities. Just like any community, having someone influential to introduce and initiate you makes your accretion much easier.

Considering your future career, close relations with important people from the industry is a significant advantage.

Bringing It All Together

The answer is to find something that the community needs, which you love doing and have a natural ability for. Knowing some key people from the industry is also important. Those are the basic ingredients you should be looking for.

  • The community always needs doctors and you may love the idea of healing people. But if you are unable to tolerate blood, you would have a hard time keeping up.
  • You may enjoy playing an instrument a lot, but if you fear airplanes and can’t travel, you might not be fit for touring.
  • You may love animals a lot, but you can’t be a competent vet if you have a hard time operating on them.
  • You may be in love with abstract art, but if your community doesn’t care about it, maybe you should keep it as a personal interest and look for a profession somewhere else.
  • You may feel like you would be a talented director, but if you know absolutely no one from the movie industry, you might have a hard time climbing up the career ladder.

You get the idea; the ideal case should mix all the ingredients.

  • If your missing ingredient is the need of the community, you could end up being poor.
  • If your missing ingredient is ability, you could be pigeonholed into a mediocre position.
  • If your missing ingredient is love, you could end up lacking enjoyment and life satisfaction.
  • If your missing ingredient is entourage, you could be left out of the industry altogether.

Find the profession that combines all ingredients, and you are one step closer to ikigai.

Hint: Early internship is a great way to understand if a potential job works for you or not.


A General Purpose ABAP Multiton Class

In this post, I will share a general purpose class covering the multiton design pattern. By implementing a simple interface, you can add multiton functionality to your existing classes.

Multiton is a performance oriented design pattern. It is based on the idea of caching and re-using objects corresponding to the same key. For each object key (such as a vendor number), a static object instance of a class (such as a vendor class) is kept in a central location. Whenever a client requests an object corresponding the key, the existing object is returned instead of creating a new one. This approach reduces the memory footprint due to the decreased number of objects, and avoids the performance cost to re-create objects having the same key.

A typical multiton class would have the following skeleton structure.



    DATA gv_lifnr TYPE lifnr READ-ONLY

    CLASS-METHODS get_instance
      IMPORTING !iv_lifnr TYPE lifnr
      RETURNUNG VALUE(ro_obj) TYPE REF TO zcl_vendor.


      BEGIN OF t_multiton,
        lifnr TYPE lifnr,
        obj TYPE REF TO zcl_vendor,
      END OF t_multiton,

      tt_multiton TYPE HASHED TABLE OF t_multiton
        WITH UNIQUE KEY primary_key COMPONENTS lifnr.

    CLASS-DATA gt_multiton TYPE tt_multiton.

    METHODS constructor
        !iv_lifnr TYPE lifnr.




  METHOD constructor.
    “ Check if IV_LIFNR exists in LFA1 and raise error if not
    gv_lifnr = iv_lifnr.

  METHOD get_instance.

    ASSIGN gt_multiton[ KEY primary_key
      COMPONENTS lifnr = iv_lifnr ]
      TO FIELD-SYMBOL(<ls_multiton>).

    IF sy-subrc NE 0.

      “ Check if IV_LIFNR exists in LFA1 and raise error if not
      DATA(ls_multiton) = VALUE t_multiton( lifnr = iv_lifnr ).
      ls_multiton-obj = NEW #( iv_lifnr ).
      INSERT ls_multiton 
        INTO TABLE gt_multiton
        ASSIGNING <ls_multiton>.


    ro_obj = <ls_multiton>-obj.



When ZCL_VENDOR=>GET_INSTANCE( ‘12345’ ) is called for the first time, a new instance of ZCL_VENOR is created and stored in GT_MULTITON; and that very instance is returned.

When ZCL_VENDOR=>GET_INSTANCE( ‘12345’ ) is called again, the existing instance of ZCL_VENDOR in GT_MULTITON is returned instead of a new instance. That saves memory and runtime.

For more information on multiton, you can refer to my book Design Patterns in ABAP Objects.

Now, what is the value-add of this post?

Instead of creating a specialized multiton implementation into every required class, I have created a general purpose multiton class which does all the hard work of caching objects. All you have to do is to implement an interface into your existing class to add multiton functionality.

Let’s assume that our vanilla class looks like this.

CLASS zcl_bc_multiton_demo DEFINITION


      gv_id    type char15,
      gv_erdat type erdat,
      gv_ernam type ernam.

      constructor importing iv_id type char15.


CLASS zcl_bc_multiton_demo IMPLEMENTATION.

  method constructor.
    gv_id = iv_id.
    gv_erdat = sy-datum.
    gv_Ernam = sy-uname.


Pretty simple, huh? This is the class we presumably need multiton functionality on.

This is the interface we need to implement.

  public .

          !iv_objectid type CDOBJECTV
          value(ro_obj) type ref to ZIF_BC_MULTITON


After implementing the interface, our vanilla class looks like this.

CLASS zcl_bc_multiton_demo DEFINITION


    interfaces ZIF_BC_MULTITON.

      gv_id    type char15,
      gv_erdat type erdat,
      gv_ernam type ernam.

      constructor importing iv_id type char15.


CLASS zcl_bc_multiton_demo IMPLEMENTATION.

  method constructor.
    gv_id = iv_id.
    gv_erdat = sy-datum.
    gv_Ernam = sy-uname.

  METHOD zif_bc_multiton~get_instance.
    ro_obj ?= new zcl_Bc_multiton_demo( conv #( iv_objectid ) ).


And here is the general purpose class that does the caching.

CLASS zcl_bc_multiton DEFINITION
  CREATE public .


          !iv_clsname   TYPE seoclsname
          !iv_objectid  TYPE cdobjectv
          VALUE(ro_obj) TYPE REF TO zif_bc_multiton


      BEGIN OF t_multiton,
        clsname  TYPE seoclsname,
        objectid TYPE cdobjectv,
        cx       TYPE REF TO cx_sy_create_object_error,
        obj      TYPE REF TO zif_bc_multiton,
      END OF t_multiton,

        TYPE HASHED TABLE OF t_multiton
        WITH UNIQUE KEY primary_key COMPONENTS clsname objectid.

      gt_multiton TYPE tt_multiton.



  METHOD get_obj.

    ASSIGN gt_multiton[
        KEY primary_key COMPONENTS
        clsname  = iv_clsname
        objectid = iv_objectid
      ] TO FIELD-SYMBOL(<ls_mt>).

    IF sy-subrc NE 0.

      DATA(ls_mt) = VALUE t_multiton(
        clsname  = iv_clsname
        objectid = iv_objectid


          CALL METHOD (ls_mt-clsname)=>zif_bc_multiton~get_instance
              iv_objectid = ls_mt-objectid
              ro_obj      = ls_mt-obj.

        CATCH cx_sy_create_object_error INTO ls_mt-cx ##no_handler.
        CATCH cx_root INTO DATA(lo_diaper).

          ls_mt-cx = NEW #(
            textid    = cx_sy_create_object_error=>cx_sy_create_object_error
            classname = CONV #( ls_mt-clsname )
            previous  = lo_diaper


      INSERT ls_mt
        INTO TABLE gt_multiton
        ASSIGNING <ls_mt>.


    IF <ls_mt>-cx IS NOT INITIAL.
      RAISE EXCEPTION <ls_mt>-cx.

    ro_obj = <ls_mt>-obj.



Now, if we need to create an instance of ZCL_BC_MULTITON_DEMO bypassing the multiton cache, all we need to do is to create the object regularly as demonstrated below.

DATA(lo_obj) = NEW zcl_bc_multiton_demo( 'DUMMY' ).

If we need to get advantage of multiton, here is what we need to do.

DATA(lo_obj) = CAST zcl_bc_multiton_demo(
    iv_clsname = 'ZCL_BC_MULTITON_DEMO'
    iv_objectid = 'DUMMY'


Pretty neat, eh? Having ZCL_BC_MULTITON_DEMO, we don’t need to deal with caching anywhere else. This class will do the multiton caching for you, and return the cached instance in case you re-call GET_OBJ with the same object id.

In case you need the original source codes of the samples mentioned here, you can visit my GitHub ABAP library.


Eğlencelik SAP Entry’leri

Her seferinde aramak zorunda kalmamak için; Ekşi Sözlük’te yazdığım eğlencelik SAP Entry’lerimi buraya toplamak istedim.