Szivárgó absztrakciók

Joel Spolsky egy 2002-es cikkében ír a “szivárgó absztrakciók törvényéről” (leaky abstractions law). Nagyon helyesen már az elején tisztázza, mi is az az absztrakció:

It is what computer scientists like to call an abstraction: a simplification of something much more complicated that is going on under the covers.

Joel Spolsky: The Law of Leaky Abstractions (https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/)

Kicsit általánosabban – és ez a meghatározás ismerősebb lehet – az absztrakció a lényeges és lényegtelen tulajdonságok szétválasztása, és a lényegtelen figyelmen kívül hagyása. Hétköznapi absztrakció például a számfogalom, nagyszerűen tudunk vele dolgozni, anélkül, hogy tudnánk, hogy hány darab valamiről beszélünk éppen. Nem lényeges. (Lásd bővebben a Wikipedián.)

Joel a TCP/IP protokollt hozza példának: a TCP egy olyan protokoll, ami megbízhatóvá teszi az IP protokoll segítségével történő adattovábbítást. Az IP megbízhatatlan, a rá épülő TCP viszont megbízható. Joel definíciója szerint tehát a TCP olyan absztrakció, amely elrejti előlünk az IP megbízhatatlanságát. Igen ám – érvel Joel – ha azonban elvágjuk a kábelt, vagy egyszerűen csak egy nagyon lassú hálózati szegmensben próbálunk adatot továbbítani, könnyen lehet, hogy az üzenetünk nem érkezik meg. Vagyis megbízható absztrakció ide vagy oda, kikönyököl a “megbízhatatlanság”. Ahogy mondja, “szivárog” az absztrakció. Itt érkezünk el az általa megfogalmazott törvényhez:

All non-trivial abstractions, to some degree, are leaky.

Vagyis, minden nem triviális absztrakció valamilyen szinten szivárog. Az igazi probléma ezzel az, hogy az informatika tele van absztrakciókkal. Sőt, ahogy ez a tudomány fejlődik, egyre több egymásra épülő absztrakcióval dolgozik. Ezzel még nem lenne gond, mivel ezek pont azt célozzák meg, hogy ne kelljen a részletekben elvesznünk, hanem foglalkozhassunk magasabb szintű dolgokkal . Viszont ezen absztrakciók többsége leaky, vagyis szivárog. Ami azt jelenti, hogy hiába rejtette el előlünk a működést, mégis tisztában kell lennünk vele. Vagyis, ahogy egyre magasabb és magasabb szintre lépünk, egyre nehezebb megfelelően jártas szakemberré válnunk. Eddig Joel érvelése.

Személyes megjegyzésem ehhez az, hogy érdekes a felvetés, azonban érdemes lenne tovább kutatni a témában, illetve pontosítani az absztrakciók lehetséges hibáit. Joel példáiból kicsit úgy tűnik, hogy számára bármelyik absztrakció leaky, amit “el lehet rontani”. Nem gondolom, hogy a TCP absztrakciója rossz lenne azért, mert nem kezeli az elszakadt kábel problémáját. Egyébként kezeli: tudjuk, ha nem ért célba az üzenet. A TCP nem állítja, hogy célba fog érni az üzeneted, csak azt, hogy tudjuk, hogy célba ért, és tudjuk, ha nem. Nem attól megbízható, hogy mindig célba ér, hanem attól, hogy tudjuk, mi történik, és erre aztán lehet reagálni. Vagyis az IP protokoll megbízhatatlanságát mindkét esetben sikerrel rejti el. Ilyen értelemben tehát a TCP rossz példa, a TCP egy jó absztrakció. (Egyébként az eredeti cikkben más példákat is hoz, és több jogos észrevétele van, de a TCP-vel kapcsolatban szerintem téved.)

Google Docs számozott címsorok

Egyre többet használom a Google Docs-ot munkára, és bár eléggé korlátozott lehetőségekkel bír, szeretem, nagyon kényelmes. (Bízom benne, hogy gőzerővel fejlesztik!) Számomra a legfájóbb pont a számozott címsorok hiánya. A legjobb megoldás egyelőre Patrick Rebondy szkriptje (itt találjuk).

Használat:

  • A megnyitott dokumentumban a Tools, Script editor menüpontot választva adjuk hozzá a lenti kódot (ezt elegendő egyszer megtenni dokumentumonként).
  • A számozás frissítéséhez a Tools, Script Manager menüben válasszuk az addHeaderNumebering funkciót.

A frissítést minden alkalommal el kell végezni, ha hozzáadtunk/elvettünk címsorokat. Íme a kód:

function addHeaderNumbering () {
  var pars = DocumentApp.getActiveDocument().getBody().getParagraphs();
  var counterHeader = [0, 0, 0, 0, 0, 0];

  for(var i=0; i<pars.length; i++) {
    var par = pars[i];
    var hdg = par.getHeading();
    if (hdg == DocumentApp.ParagraphHeading.HEADING1) {

      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING1, par, 0, counterHeader);
    } else if (hdg == DocumentApp.ParagraphHeading.HEADING2) {
      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING2, par, 1, counterHeader);
    } else if (hdg == DocumentApp.ParagraphHeading.HEADING3) {
      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING3, par, 2, counterHeader);
    } else if (hdg == DocumentApp.ParagraphHeading.HEADING4) {
      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING4, par, 3, counterHeader);
    } else if (hdg == DocumentApp.ParagraphHeading.HEADING5) {
      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING5, par, 4, counterHeader);
    } else if (hdg == DocumentApp.ParagraphHeading.HEADING6) {
      _addNumberingForHeaderType(DocumentApp.ParagraphHeading.HEADING6, par, 5, counterHeader);
    }
  }
}


function _addNumberingForHeaderType(headerType, paragraph, initIndex, counterHeader) {
  counterHeader[initIndex] = counterHeader[initIndex] + 1;
  var currCounter = _getCurrenNumbering(initIndex, counterHeader);
  for(var ii = initIndex + 1; ii < counterHeader.length; ii++) {
    counterHeader[ii] = 0;
  }
  var content = paragraph.getText();
  var chunks = content.split('.\t')

  var result = 'ok'
  if(chunks.length > 1) {

    paragraph.setText(currCounter+'.\t'+chunks[1]); 
  } else { 
    paragraph.setText(currCounter+'.\t'+chunks[0]);
  }
}


function _getCurrenNumbering(initIndex, counterHeader) {
  var value = '';
  for ( var i = 0; i <= initIndex; i++) {
    if (value) {
      value += '.';
    }
    value += counterHeader[i];
  }
  
  return value;
}