Abstraction is Expensive

“At companies with huge engineering forces, abstraction management is what a lot of them spend their time on. Often, these engineers are actually the most “productive” in terms of money saved – infrastructure projects tend to result in 8-9 figure savings or unique capabilities, and performance engineering (another form of abstraction alignment) frequently has 8 figure returns per engineer. Another large group of engineers is in charge of making sure that the old abstractions don’t break and crash the entire system.

Conversely, this is where startups can develop technical advantages on big tech despite having much smaller engineering teams, and where bootstrapped companies can out-engineer series-D companies. Given the freedom to align your abstractions to your goals, amazing things are possible.”

https://specbranch.com/posts/expensive-abstraction/

37signals (Basecamp, Hey) – cloud spend in 2022

So that’s how we spent millions on the cloud in 2022!

In 2023, we hope to dramatically cut that bill by moving a lot of services and dependencies out of the cloud and onto our own hardware. We don’t operate our own data centers, but work with our friends at Deft to lease rackspace, bandwidth, power, and white glove service. That isn’t cheap either at our scale, but it’s far, far less than what we spend on the cloud.”

https://dev.37signals.com/our-cloud-spend-in-2022/

Kommentar zu: Harmonisiertes Metadatenschema für die DSpace-Repositorien der Berliner Universitäten

Im folgenden teile ich hier einige Gedanken zu dem Papier:

“Harmonisiertes Metadatenschema für die DSpace-Repositorien der Berliner Universitäten – Ergebnis der Arbeitsgruppe DSpace Metadaten bestehend aus Mitgliedern der Charité – Universitätsmedizin Berlin, der Freien Universität Berlin, der Humboldt-Universität zu Berlin und der Technischen Universität Berlin”

Zu finden hier: https://refubium.fu-berlin.de/handle/fub188/37260

Direktlink zum Datensatz hier:  https://refubium.fu-berlin.de/bitstream/handle/fub188/37260/Berlin_DSpace_MDS.xlsx?sequence=1&isAllowed=y&save=y

Als Entwickler finde ich die im Abstract formulierten Zielsetzungen besonders wichtig und erfreulich:

“Ziel ist, innerhalb der Berliner Universitäten einen einheitlichen
Gebrauch der Metadaten zu gewährleisten. Gleichzeitig wird es bei
Einführung des neuen Modells möglich sein, Mappingtabellen, Schnittstellen
und Programmierarbeiten zwischen den beteiligten Einrichtungen leichter
auszutauschen.”

Trigger

Das Arbeitsergebnis wurde als Excel-Datei veröffentlicht. Dies reicht als Grundlage für einen gelungenen Datenaustausch natürlich noch nicht aus. Typische Folgefragen von Softwareentwicklern sind:

– Wo finde ich die konkreten Schemadateien?

– Gibt es Testsysteme?

– Welche Protokolle/APIs sollen zum Austausch der Daten angeboten und genutzt werden?

– Wie sieht es mit Mehrsprachigkeit in den Metadaten aus?

Aber zurück zum vorliegenden Datensatz:

Beobachtung

An vielen Stellen in der Excel-Datei steht als Datentyp Freitext. Es gibt kaum MetaMetadaten. An einigen Stellen erscheint das Modell zu flach und zu spezifisch. Dies ist in gewisser Weise Schade, da hier die zitierte. Zielsetzung möglicherweise durch “ein paar Handgriffe” optimaler unterstützt werden könnte.

Beispiel aus Zeile 22-24:

Feld Beispielwert
dc.subject open access
dc.subject.ddc 300 Sozialwissenschaften
dc.subject.rvk AK 54355

Ein paar Dinge fallen hier auf:

1. In den Freitextfeldern werden Notationen und Label gemischt

2. Für einzelne Notationssyteme existieren spezielle Unterfelder (ddc,rvk). Dies ist nicht gut erweiterbar. Besser wäre es zu jedem Subject das Notationssystem zu vermerken und für diesen Vermerk seinerseits ein kontrolliertes Vokabular (z.B. basierend auf Wikidata, s.u.) zu definieren.

3. Es wird nicht ganz klar, wie Mehrsprachigkeit realisiert werden soll.

4. Es gibt kein (Sub)Feld indem z.B. URIs auf SKOS-Vokabulare mitgeführt werden könnten.

These

Um den Bereich “subject” besser maschinell nachnutzbar zu machen, sollten kontrollierte SKOS-Vokabulare die Regel sein. Wenn möglich sollten URIs zur Identifikation von verwendeten Termen mit im Datensatz gespeichert werden.

In jedem Fall sollten Notationen, Label und IDs im Datenmodell in getrennte Unterfelder laufen. Labels sollten mehrsprachig im Datensatz mitgeführt werden können bzw. über eine URI leicht nachgeladen werden können.

Beispiel und Vorschlag

Das Beispiel zeigt ein Schlagwort im Feld subject mit zusätzlichen Informationen.

"subject":[{
   "id":"http://dewey.info/class/300",
   "notation":"300",
   "prefLabel": "Sozialwissenschaften",
   "label":{
      "de":"Sozialwissenschaften"
      "en": "Social Sciences"
      "fr":"...."
    },
   "source":{
      "id":"https://www.wikidata.org/wiki/Q15222117",
      "label":{
        "en": "Dewey Decimal Classification"
     }
    "similarTo": "https://www.wikidata.org/wiki/Q34749"
   }
}]

Zusätzlich zu dem Schlagwort werden Informationen zur Quelle und zum Notationssystem gegeben. Notation und Schlagwort werden getrennt. Es wird über einen Link auf Wikidata eine Verlinkung in andere Schlagwortsysteme realisiert.

Und was bringt das?

Dies hat vor allem Vorteile auf der maschinellen Konsumentenseite.

  1. Alle subjects, egal aus welchem Vokabular, können zunächst mal leicht verarbeitet werden. Folgendes geht z.B. immer: subject.0.prefLabel, subject.0.label.de . Hierbei ist es egal, aus welchem Notationssystem ein Schlagwort kommt. Dies stellt eine erhebliche Vereinfachung für Aggregatoren dar, die für einfache Anwendungsfälle keine weiteren Informationen über die angebotenen Subfelder eines Quellsystems haben müssen. Siehe Punkt 4.
  2. Über die “source” und die “notation” können einerseits in einer grafischen Oberfläche zusätzliche Hinweise gegegeben werden, andererseits können die nachnutzenden Systeme Verknüpfungen zu anderen Datensätzen herstellen und so sehr effektive Browsingoberflächen oder sonstige Bezugssysteme aufbauen.
  3. Wikidata als ein mögliches Werkzeug um Verknüpfungen herzustellen. Über den Link unter “similarTo” können weitere Vokabulare verknüpft werden. Sehr praktisch wenn man z.B. die Inhalte unterschiedlicher Quellen mit unterschiedlicher Verschlagwortung/Erschließung aggregieren möchte.
  4. Durch den Verzicht auf Unterfelder für spezifische Vokabulare, z.B. .ddc oder .rvk , wird ein einheitlicher Zugriff auf Schlagworte aus unterschiedlichen Vokabularien unterstützt. Dadurch können konsumierende Systeme auch Schlagwortsysteme, die sie nicht vollständig unterstützen einfach zur Anzeige bringen und indexieren, etc..
  5. Anzeige und intellektuelle Erschließung werden separiert. Die Anzeige eines Schlagworts (das Label) wird von der verwendeten Notation getrennt. Dies eröffnet nachnutzenden Systemen die Möglichkeit kontextspezifische Anzeigestrategien zu etablieren ohne die zugrundeliegende intellektuelle Erschließung (in Form der Notation) anpassen zu müssen. Ersteres ist oft gewünscht, letzteres ist oft nicht ohne weiteres möglich.
Das sieht aber total aufwendig aus.
Vielleicht ist es gar nicht so aufwendig. Gerade bei der Erstellung der Metadaten liegen die Infos zu einem Schlagwort oft alle im Erfassungssystem vor. Sie müssten dann nur abgespeichert werden!
Ist das alles?
Ich denke, nein. Die Design-Prinzipien, die ich hier für das Subject Feld beispielhaft ausgeführt habe, können auch für andere Felder sinnvoll zur Anwendung gebracht werden. z.B. für Contributor, Insitutionen etc. Auch in diesen Fällen bietet eine hierarchisierte Form der Speicherung Vorteile gegenüber der Schaffung neuer Felder und vereinfacht die Konsumierbarkeit der Daten.

Accessing container environment at startup time with typescript / react / docker

Blogpost for this stackoverflow answer: https://stackoverflow.com/a/74701083/1485527

Get code here

Create example app

npx create-react-app read-env-example --template typescript

Navigate to fresh app

cd read-env-example

Create Dockerfile

mkdir -p docker/build

docker/build/Dockerfile

# build environment
FROM node:19-alpine3.15 as builder
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH

COPY package.json ./
COPY package-lock.json ./
RUN npm ci
RUN npm install react-scripts@5.0.1 -g
COPY . ./
RUN PUBLIC_URL="." npm run build

# production environment
FROM nginx:stable-alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

COPY docker/build/docker-entrypoint.sh /
RUN chmod +x docker-entrypoint.sh

ENTRYPOINT ["/docker-entrypoint.sh"]

Create docker-entrypoint.sh

This script will be executed at container start.
It generates the config.js file containing all environment variables starting with ‘MYAPP’ under window.extended.

docker/build/docker-entrypoint.sh

#!/bin/sh -eu


function generateConfigJs(){
    echo "/*<![CDATA[*/";
    echo "window.extended = window.extended || {};";
    for i in `env | grep '^MYAPP'`
    do
        key=$(echo "$i" | cut -d"=" -f1);
        val=$(echo "$i" | cut -d"=" -f2);
        echo "window.extended.${key}='${val}' ;";
    done
    echo "/*]]>*/";
}
generateConfigJs > /usr/share/nginx/html/config.js

nginx -g "daemon off;"

Create docker-compose.yml

mkdir docker/run

docker/run/docker-compose.yml

version: "3.2"
services:

  read-env-example:
    image: read-env-example:0.1.0
    ports:
      - 80:80
    env_file:
      - myapp.env

Create runtime config for your app

docker/run/myapp.env

MYAPP_API_ENDPOINT='http://elasticsearch:9200'

Create config.js <– this is where .env will be injected.

public/config.js

/*<![CDATA[*/
window.extended = window.extended || {};
window.extended.MYAPP_API_ENDPOINT='http://localhost:9200';
/*]]>*/

Note: This file will be completely overwritten by the docker-entrypoint.sh. For development purposes you can set it to any value that is appropriate, e.g. when used together with npm start.

Include config.js in index.html

public/index.html

   <head>
     ...
    <script type="text/javascript" src="%PUBLIC_URL%/config.js" ></script>
     ...
   </head>
   <body>

Make use of your environment variable

src/App.tsx

declare global {
    interface Window { extended: any; }
}
function App() {
  return (
    <div className="App">
      <header className="App-header">

          You have configured {window.extended.MYAPP_API_ENDPOINT}

      </header>
    </div>
  );
}

Build

npm install

Create docker image

docker build -f docker/build/Dockerfile -t read-env-example:0.1.0 .

Run container

docker-compose -f ./docker/run/docker-compose.yml up

Navigate to your app

Open http://localhost in your browser.
You will see the content of MYAPP_API_ENDPOINT like  provided in your docker/run/myapp.env.

Further usage

You can provide additional variables starting with MYAPP. The docker-entrypoint.sh script will search for all variables starting with MYAPP and make them available through the windows object.

Erweiterung des “RheinEnergieSportparks” in Köln ist unwirksam

“Der 7. Senat des Oberverwaltungsgerichts hat heute über zwei Normenkontrollanträge einer Bürgerinitiative und des Landesverbands NRW des Naturschutzbunds Nabu mündlich verhandelt, die sich gegen den Bebauungsplan der Stadt Köln für die Erweiterung des “RheinEnergieSportparks” in Köln-Sülz richten. Er hat entschieden, dass der Plan unwirksam ist, weil er an einem Abwägungsmangel leidet; der Senat hat zugleich darauf hingewiesen, dass dieser Mangel in einem ergänzenden Planungsverfahren geheilt werden kann und weitere Mängel nicht ersichtlich sind.”

https://www.justiz.nrw/JM/Presse/presse_weitere/PresseOVG/24_11_2022_/index.php

Weitere Einordnungen finden sich u.a. hier: https://unsergruenguertel.de/2022/11/24/ausbauplaene/