JavaLand4Kids

Zum 10. Male findet die JavaLand-Konferenz bei und wie auch schon in den vergangenen Jahren gibt es am Vortag wieder eine JavaLand4Kids. Mit dabei sind auch wieder meine kleine LEGO WeDo Roboter.

An der Veranstaltung können leider nur geladene Schüler:innen aus der näheren Umgebung des Veranstaltungsortes teilnehmen. Es wird jedoch auch dieses Jahr wieder Workshops in der Bücherhalle Hamburg Volksdorf geben. Der erste findet am kommenden Sonnabend (10. Februar 2024) statt und ist leider schon ausgebucht. Der nächste findet am 16. März 2024 statt und richtet sich erstmals ausschließlich an Mädchen.

Digitaltag 2023

Dieses Jahr findet der bundesweite Digitaltag am 16. Juni 2023 statt. Auf über 2000 Aktionen können Menschen jeden Alters Digitalisierung erleben, Erfahrungen austauschen und auch mitgestalten.

Für junge Ingenieur:innen und Programmier:innen wird es an diesem Tag in der Bücherhalle Hamburg Volksdorf wieder meinen beliebten Workshop „LEGO Roboter bauen und programmieren“ geben. Weitere Informationen und Anmeldung wie gewohnt direkt über die Mitarbeiter:inner der Bücherhalle vor Ort.

6. Hamburger MINT-Tag

Am 17. November findet der sechste Hamburger MINT-Tag statt. Klar, dass es an diesem Aktionstag auch einen Workshop in der Bücherhalle Hamburg Volksdorf zu diesem Thema geben wird.

Kids im Grundschulalter haben die Möglichkeit, mit dem LEGO Education WeDo 2.0 Set kleine Roboter aus Klemmbausteinen zu bauen und diese mit einer einfachen, graphischen Programmiersprache auf einem Tablet zu programmieren.

Der Kurs findet von 15 bis 18 Uhr statt. Anmeldungen wie üblich direkt in der Bücherhalle Volksdorf.

LEGO WeDo und Calliope Workshops auf dem Java Forum Nord

Das Java Forum Nord findet dieses Jahr am 6. Oktober 2022 im Hannover Congress Centrum statt. Neben tollen Vorträgen für Java-Enthusiasten (die Programmiersprache, nicht die Insel) wird es auch eine JFN4Kids geben.

Auf zwei Workshops können Kids aus ausgewählten Schulen einen Einblick in die IT bekommen. Für Grundschüler gibt es meinen klassischen LEGO WeDo 2.0 Workshop, für Gymnasiasten einen Calliope-Workshop.

Migration Kickstart-GraphlQL zu Spring Boot GraphQL

Seit Spring Boot 2.7.0 unterstützt das Framework GraphQL mit einer „nativen“ Integration, die auf GraphQL Java basiert. Wer zuvor die Kickstart-Variante genutzt hat, erfährt hier in knappen Zeilen, wie man seine Anwendung migriert.

Konfiguration

Der einfachste Teil. Die Konfigurationsparameter sind nun Teil des Spring-Namensraums. Die beiden wichtigsten Parameter am Besipiel:

KickstartSpring Boot
graphql.servlet.mappingspring.graphql.path
graphiql.mappingspring.graphql.graphiql.path

QueryResolver

In Spring Boot läuft alles über @Controller statt über Resolver und es kommen vermehrt Annotationen zum Einsatz. Hier ein einfaches Beispiel:

// Kickstart

@Component
public class Query implements GraphQLQueryResolver {

    private final EntityManager entityManager;

    public Marktpartner marktpartner(Long id) {
        return entityManager.find(Marktpartner.class, id);
    }

}
// Spring Boot

@Controller
public class Query {

    private final EntityManager entityManager;

    @QueryMapping
    public Marktpartner marktpartner(@Argument Long id) {
        return entityManager.find(Marktpartner.class, id);
    }

}

Wenn im GraphQL-Schema weitere Attribute definiert waren, die nicht im zurückgegebenen Objekt enthalten waren, oder um Assoziationen aufzulösen, wurden weitere Resolver-Klassen geschrieben. In Spring Boot gibt es hierfür das @SchemaMapping:

// Kickstart

@Component
public class MarktpartnerResolver implements GraphQLResolver<Marktpartner> {

    public String getUri(Marktpartner marktpartner) {
        return String.format(URL_VISITENKARTE, marktpartner.getId());
    }


    public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, MarktrollenFilter filter) {
        return repository.find...
    }
}
@Controller
public class MarktpartnerResolver {

    @SchemaMapping(typeName = "Marktpartner", field = "uri")
    public String getUri(Marktpartner marktpartner) {
        return String.format(URL_VISITENKARTE, marktpartner.getId());
    }


    @SchemaMapping(typeName = "Marktpartner", field = "marktrollen")
    public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, @Argument MarktrollenFilter filter) {
        return repository.find...
    }
}

Wichtig ist hierbei, das nur in @Controller-annotierten Klassen nach @QueryMapping oder @SchemaMapping gesucht wird.

Relay-Unterstützung

In Spring Boot gibt es noch keine Unterstützung für Relay. Deshalb ist es notwendig, das Schema anzupassen. Dies führt nach meinem jetzigen Kenntnisstand leider auch dazu, dass Clients angepasst werden müssen, jedenfalls, wenn man erst einmal den einfachsten Weg geht.

// Kickstart

type Query {

    marktpartner(id: ID!) : Marktpartner!

    marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : MarktpartnerConnection @connection(for: "Marktpartner")

}

# Relay.js types:
# ---------------
interface Node {
    id: ID
}

type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: String
    endCursor: String
}

type Marktpartner implements Node {
    id: ID!

    name: String!

    // ...
}
// Spring Boot

type Query {

    marktpartner(id: ID!) : Marktpartner!

    marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : Connection

}

# Relay.js types:
# ---------------

interface Node {
    id: ID
}

type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: String
    endCursor: String
}

type Connection {
    edges: [Edge]
    pageInfo: PageInfo
}

type Edge {
    cursor: String!
    node: Node!
}

type Marktpartner implements Node {
    id: ID!

    name: String!

    // ...
}

Hinzu gekommen sind also die expliziten Typ-Definitionen für Connection und Edge.

Die obige Lösung führt jedoch dazu, dass Anfragen des Clients angepasst werden müssen:

// Kickstart

query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
    marktpartners(first: $first, filter: $filter) {
        edges {
            cursor
            node {
                id
                name

            }
        }
    }
}
// Spring Boot

query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
    marktpartners(first: $first, filter: $filter) {
        edges {
            cursor
            node {
                id
                ... on Marktpartner {
                    name
                }
            }
        }
    }
}

Außerdem wird noch eine TypeResolver-Implementierung benötigt:

// Spring Boot

public class NodeTypeResolver implements TypeResolver {

    @Override
    public GraphQLObjectType getType(TypeResolutionEnvironment env) {
        Object object = env.getObject();
        if (object instanceof Marktpartner) {
            return env.getSchema().getObjectType("Marktpartner");
        }

        throw new UnsupportedOperationException("NodeTypeResolver unvollständig für das Objekt " + object);
    }

}

Testing

Am längsten hat die Umstellung der integrativen Tests gedauert, da ich dazu bisher nur wenige Beispiele gefunden hatte. Das wichtigste dabei: Es wird spring-webflux benötigt, auch wenn die Anwendung selbst gar nicht fluxig ist:

pom.xml (Spring Boot)

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-graphql</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.graphql</groupId>
      <artifactId>spring-graphql-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <scope>test</scope>
    </dependency>

Für Tests gibt es in Spring Boot die Klasse GraphQlTester und davon diverse Unterklassen für verschiedene Einsatzszenarien. Mein integrativer Test sieht nach der Umstellung wie folgt aus::

@Transactional
@SpringBootTest
class QueryIT {


    private WebGraphQlTester tester;

    @Autowired
    private ObjectMapper objectMapper;

    // ...

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    void before() {
        WebTestClient webTestClient = MockMvcWebTestClient.bindToApplicationContext(context)
                .configureClient()
                .baseUrl("/api/graphql")
                .defaultHeaders(headers -> headers.setBasicAuth("test", "test"))
                .build();
        tester = HttpGraphQlTester.create(webTestClient);

        // Testdaten anlegen ...
    }


    @Test
    void findetMarktpartnerUeberNameUndMarktrolle() {
        MarktpartnerFilter filter = MarktpartnerFilter.builder().namensteil("acme").build();
        MarktrollenFilter marktrollenFilter = MarktrollenFilter.builder()
                .marktrollen(List.of(MarktfunktionRolle.LIEFERANT))
                .build();

        ObjectNode variables = objectMapper.createObjectNode();
        variables.set("filter", objectMapper.convertValue(filter, ObjectNode.class));
        variables.set("marktrollen", objectMapper.convertValue(marktrollenFilter, ObjectNode.class));
        variables.put("first", 10L);

        tester.documentName("marktpartners")
                .variable("filter", variables.get("filter"))
                .variable("marktrollen", variables.get("marktrollen"))
                .variable("first", variables.get("first"))
                .execute()
                .path("marktpartners.edges").entityList(EdgeDummy.class).hasSize(1)
                .path("marktpartners.edges[0].node.name").entity(String.class).isEqualTo("ACME Energie GmbH")
        ;
    }
}

Zunächst wird also ein WebTestClient erzeugt und konfiguriert und anschließend ein HttpGraphQlTester. Dieser wird dann im eigentlich Test verwendet, um einen GraphQL-Aufruf durchzuführen. Wird wie oben eine documentName("marktpartners") angegeben, dann sucht das System die Datei resources/graphql-test/marktpartners.graphql. Alternativ kann mit der Methode document die GraphQL-Anfrage als String übergeben werden.

Mit execute wird die Anfrage gesendet und anschließend das Ergebnis geprüft. Hier kommen die path-Aufrufe zum Einsatz und Standardvergleichsmethoden wie hasSize oder isEqualTo.

Stolperfallen und andere Anomalitäten

Kleine Sammlung von Inkompatibilitäten zum Verhalten von Kickstart-GraphQL:

  • Verwende List statt Set (bei Set<Enumtyp> gab es Exeptions, dass auf ein Property nicht zugegriffen werden kann)
  • Bean-Standard für Rückgabe-DTOs einhalten, also Methoden nicht edges() benennen sondern getEdges()

Code Week 2021

Auch in diesem Jahr gibt es wieder die europaweite CodeWeek. Und wie in jedem .Jahr gibt es auch dieses Jahr wieder die Möglichkeit, mit LEGO kleine Roboter zu bauen und zu programmieren. Alles was ihr dafür benötigt ist Spaß an der Technik und ein bischen Kreativität! Alles andere stelle ich als Veranstalter zur Verfügung.

Der Workshop für Mädchen und Jungen im Alter von acht bis zehn Jahren findet (wie auch schon im vorletzten Jahr) in den Räumen der Bücherhalle Hamburg Volksdorf statt. Aufgrund der Hygenieanforderungen leider nur mit halber Teilnehmerzahl, Maske und nur für genesene, geimpfte oder getestet Teilnehmer:innen.

Die Anmeldung erfolgt vor Ort in der Bücherhalle. Bitte kommt nur, wenn ihr auch eine Bestätigung bekommen hat. Beim letzten Mal sind viele ohne Anmeldung gekommen und das gab natürlich viele enttäuschte Kinderaugen…

Fehlt noch etwas wichtiges? Ach ja, der Termin:

Sa. 23. Oktober 2021 von 10 bis 13 Uhr

CodeWeek 2021

Ich baue, er programmiert. Ich bin der Ingenieur, er ist der Informatiker.

Vom 5. bis 20. Oktober 2019 fand die europaweite Code Week statt. Die Code Week richtet sich an Kinder und Jugendliche und will das Interesse am Fach Informatik und der digitalen Welt im allgemeinen wecken und erklären. Diverse Firmen, Organisationen und Einzelpersonen bieten dazu Workshops an, meist kostenfrei.

Wie schon in den vergangenen drei Jahren war ich für Kids4IT auf der Auftaktveranstaltung in der Zentralbibliothek der Hamburger Öffentlichen Bücherhallen am Hühnerposten mit dabei. An den beiden folgenden Dienstagen fanden darüberhinaus die von mir organisierten Workshops in der Bücherhalle Hamburg Volksdorf statt, in denen wieder fleißig Roboter mit LEGO WeDo 2.0 gebaut und programmiert wurden.

Zauberschule Informatik

Los ging es am Samstag mit drei ca. 45 minütigen „Vorlesungen“ der Zauberschule Informatik. Nach einer kurzen Einführung, was Informatik eigentlich ist, lernten die Kinder im ersten Zaubertrick wie ein Computer zu zählen: 0, 1, 10, 11, 101, 110, 111, 1000, …

0 und 1 ist für den Computer die Sprache, entspricht es doch aus/an, nein/ja, kein Strom/Strom. Man braucht nur zwei klar von einander getrennte Werte und schon sieht man die binäre Welt mit ganz anderen Augen. Binär kann man mit einer Hand bis 31 zählen und mit beiden Händen gar bis 1023. Nehmen wir dann noch die Zehen der Füsse dazu, sind wir bei 220-1, also 1.048.575!

Die Binärdarstellung von Zahlen wurde im zweiten Zaubertrick genutzt, um Gedanken zu lesen und Zahlen zu erraten. Mit 100 %er Treffsichheit konnte meine Zauberschülerin die richtigen Zahlen nennen. Wegen der vielen Besucher war dazu nur eine kleine Hilfe nötig: Die Zuschauer mussten sagen, auf welcher der ausgehängten Karten ihre gedachte Zahl stand.

Gedankenlesen auf der Code Week 2019 (CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink
Staunendes Publikum in der Zauberschule Informatik (CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink)

Bilder lassen sich auch mit 0 und 1 darstellen: weiß und schwarz. Im Bilderzauber wurde so ein 5×5 Bildpunkte (Pixel) großes Bild über das Internet übertragen. Dazu brauchte es fünf Kinder: Ein Kind-Computer, der das Bild digitalisiert und in 0 und 1 wandelt, ein Kind-Modem, das ein Seil (= Internet) zum Schwingen brachte, ein zweites Kind-Modem am anderen Ende des „Internets“ um daraus wieder 0 und 1 zu wandeln und einen Kind-Bildschirm, das aus 0 und 1 wieder Bildpunkte aufmalte. Dazu noch einen Kind-Taktgeber, über den sich die beiden Modems abstimmten, um auf einander folgende Nullen und Einsen zu unterscheiden.

Das es dabei Übertragungsfehler gab, war nicht weiter schlimm, denn der vierte Zaubertrick basierte auf Prüfsummen. 16 rot-grüne Karten durften zufällig in einem 4×4 Raster von den Kindern aufgehängt werden. Der Zauberlehrer hat dann treffsicher auf die Karte gezeigt, die – ohne das es der Zauberer sehen – konnte, umgedreht wurde. Um die Sache schwieriger zu machen, hatte der Zauberer zuvor das Ganze auf 5×5 Karten erweitert (die Prüfsummen…).

Zum Abschluss gab es schließlich noch Kuchen für alle Teilnehmer. Ganz informatisch, wurde das eine Stück Kuchen geteilt, eine Hälfte einem Teilnehmen übergeben und damit die Lösungsmenge verkleinert. Dann wieder halbieren, abgeben, halbieren, …

LEGO Roboter bauen im Rahmen der Auftaktveranstaltung zur Code Week 2019 (CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink)
LEGO Roboter bauen im Rahmen der Auftaktveranstaltung zur Code Week 2019 (CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink)

Am Nachmittag gab es dann wieder den Klassiker: In 4×45 Minuten haben jeweils 20 Kinder mit LEGO Education WeDo 2.0 die Forschungssonde Milo gebaut und per Tablet programmiert.

Workshops am 8. und 15. Oktober

An den beiden folgenden Dienstagen konnten jeweils 14 Kinder in dreistündigen Workshops in aller Ruhe diverse Modelle mit LEGO Education WeDo 2.0 bauen und programmieren. Wie beliebt dieser Workshop ist, hat sich insbesondere am ersten Dienstag gezeigt: Aufgrund von Kommunikationsschwierigkeiten bzgl. der Verfügbarkeit freier Plätze kamen ca. dreimal so viele Kinder wie Plätze vorhanden waren. Mein Dank an die Mitarbeiter der Bücherhalle Volksdorf, die die teilweise erhitzen Gemüter beruhigen mussten.

Jetzt wird Milo programmiert (Foto: Fin Labusch)

Nach dem gemeinsamen Bau des Einstiegsmodells (Forschungssonde Milo) konnte die Kinder selbst entscheiden, welches Modell sie als nächstes Bauen wollten. Klassischerweise bauen Jungs das Rennauto und Mädchen lieber den Hubschrauber (der muss ein Pandabärchen vor den Fluten retten). Erstaunlicherweise gab es diesmal in keinen der beiden Kurse ein Wettkampf, wer denn den stärkeren Roboter baut. Dafür die Erkenntnis eines 11jährigen:

Ich baue, er programmiert. Ich bin der Ingenieur, er ist der Informatiker.

Das macht dann auch den Veranstalter sprachlos. Sollte sich ähnliches im zweiten Kurs wiederholen?

Auch am zweiten Dienstag war das Verhältnis Mädchen:Jungs leider nur bei 1:13 und damit deutlich geringer als während der Schnupperrunden auf der Auftaktveranstaltung. Das bleibende Erlebnis kam aber von der Schülerin (4. Klasse):

Das kannst du doch einfacher machen, wenn du eine Programmschleife nimmst.

Ada, Grace, Christiane und Jade lassen Grüßen und Charles, Konrad und Alan nicken achtungsvoll… (dies sind die Bluetooth-IDs der LEGO SmartHubs benannt nach Ada Lovelace, Grace Hopper, Christiane Floyd, Jade Raymond, Charles Babbage, Konrad Zuse und Alan Turing).

Der Erdbebensimulator in Aktion. Eins von ca. 30 Modellen, die sich mit LEGO WeDo 2.0 bauen lassen (Video: Fin Labusch)

Code Week 2019 After-Afterglow

Noch läuft die Code Week, in Hamburg gibt es aufgrund der Schulferien auch in der kommenden Woche noch Angebote im Rahmen der Code Week Afterglow.

Auch meine Workshops „Roboter bauen mit LEGO WeDo 2.0“ waren so gut besucht, dass sich lange Wartelisten gebildet haben. Und aufgrund dieser hohen Nachfrage wird es für alle Nachzügler am 2. November einen Zusatzworkshop geben. Die 14 Plätze werden bevorzugt an die Teilnehmer auf den Wartelisten vergeben.

Zauberschule Informatik im Rahmen der Auftaktveranstaltung der Code Week 2019 (CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink)

Und wem die „Zauberschule Informatik“ im Rahmen der Auftaktveranstaltung gefallen hat (oder wer nicht konnte), kann sich demnächst über das Meetup-Forum der Kids4IT für vollständigen Workshop anmelden (15 Teilnehmer).

Ein kurzer Bericht zur Auftaktveranstaltung ist auf der Kids4IT Homepage zu finden. Einen ausführlichen Bericht demnächst hier.