#!/usr/bin/env python3 """Folie 4 (eingehängt nach Folie 3) – Architektur der Modularisierung: Modularer Monolith vs. Microservices, anschaulich im Containerumfeld. Links: 1 Container, Module mit In-Process-Calls, 1 geteilte DB. Rechts: N Container, Services über Netzwerk, DB je Service. Unten: kompakte Gegenüberstellung der wesentlichen Unterschiede.""" import os from pptx import Presentation from pptx.util import Inches, Pt from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN, MSO_ANCHOR from pptx.enum.shapes import MSO_SHAPE from adesso_style import (WHITE, INK, BLUE, TEAL, GREEN, CORAL, LIGHT, MUTE, RECF, F, FC, paint_background, chrome) NAVY = INK ACCENT = CORAL LINEC = LIGHT prs = Presentation() prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) s = prs.slides.add_slide(prs.slide_layouts[6]) paint_background(s, prs.slide_width, prs.slide_height) def shp(kind, x, y, w, h, fill=None, line=None, lw=Pt(1), rot=0): sh = s.shapes.add_shape(kind, x, y, w, h) if fill is None: sh.fill.background() else: sh.fill.solid(); sh.fill.fore_color.rgb = fill if line is None: sh.line.fill.background() else: sh.line.color.rgb = line; sh.line.width = lw if rot: sh.rotation = rot sh.shadow.inherit = False return sh def boxtext(sh, t, size=14, color=INK, bold=False): tf = sh.text_frame; tf.word_wrap = True tf.vertical_anchor = MSO_ANCHOR.MIDDLE tf.margin_left = tf.margin_right = Pt(3); tf.margin_top = tf.margin_bottom = Pt(1) p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER r = p.add_run(); r.text = t r.font.size = Pt(size); r.font.bold = bold; r.font.name = F; r.font.color.rgb = color def txt(x, y, w, h, t, size=14, color=INK, bold=False, italic=False, align=PP_ALIGN.LEFT, spc=None): tb = s.shapes.add_textbox(x, y, w, h); tf = tb.text_frame tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.MIDDLE tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0) p = tf.paragraphs[0]; p.alignment = align r = p.add_run(); r.text = t r.font.size = Pt(size); r.font.bold = bold; r.font.italic = italic r.font.name = F; r.font.color.rgb = color if spc: r.font._rPr.set('spc', str(spc)) return tb def vline(x, y, h, color=LINEC, weight=Pt(1.4)): shp(MSO_SHAPE.RECTANGLE, x - weight / 2, y, weight, h, fill=color) def hline(x, y, w, color=LINEC, weight=Pt(1.4)): shp(MSO_SHAPE.RECTANGLE, x, y - weight / 2, w, weight, fill=color) # ---- Kopf + Kernaussage ---------------------------------------------------- chrome(s, "Architektur der Modularisierung", 4) txt(Inches(1.25), Inches(0.98), Inches(11.6), Inches(0.34), "Gleiche fachlichen Schnitte – der Unterschied ist die Laufzeit- und Deployment-Grenze.", size=14, color=LIGHT, italic=True) DOT = [TEAL, GREEN, BLUE] # gleiche Module/Services beidseitig farblich verankert LET = ["A", "B", "C"] # =========================================================================== # Spalten-Titel # =========================================================================== cL = Inches(3.6) # Mittelpunkt linke Spalte cR = Inches(9.75) # Mittelpunkt rechte Spalte txt(Inches(0.95), Inches(1.5), Inches(5.3), Inches(0.32), "Modularer Monolith", size=18, color=WHITE, bold=True, align=PP_ALIGN.CENTER) txt(Inches(0.95), Inches(1.84), Inches(5.3), Inches(0.26), "1 Deployable · 1 Prozess", size=11.5, color=LIGHT, align=PP_ALIGN.CENTER) txt(Inches(7.0), Inches(1.5), Inches(5.5), Inches(0.32), "Microservices", size=18, color=WHITE, bold=True, align=PP_ALIGN.CENTER) txt(Inches(7.0), Inches(1.84), Inches(5.5), Inches(0.26), "N Deployables · N Prozesse", size=11.5, color=LIGHT, align=PP_ALIGN.CENTER) # =========================================================================== # LINKS – Modularer Monolith: 1 Container, Module, geteilte DB # =========================================================================== cx_x, cx_w, cx_y, cx_h = Inches(0.95), Inches(5.3), Inches(2.2), Inches(1.6) shp(MSO_SHAPE.ROUNDED_RECTANGLE, cx_x, cx_y, cx_w, cx_h, line=WHITE, lw=Pt(1.5)) txt(cx_x + Inches(0.15), cx_y + Inches(0.05), Inches(2.0), Inches(0.26), "1 Container", size=11, color=LIGHT, bold=True) mw, mh, my = Inches(1.35), Inches(0.8), Inches(2.62) mcx = [Inches(2.05), Inches(3.6), Inches(5.15)] for i, mx in enumerate(mcx): sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, mx - mw / 2, my, mw, mh, fill=WHITE, line=LINEC, lw=Pt(1)) boxtext(sh, "Modul " + LET[i], size=13, color=INK, bold=True) shp(MSO_SHAPE.OVAL, mx - Inches(0.07), my + Inches(0.12), Inches(0.14), Inches(0.14), fill=DOT[i]) # In-Process-Pfeile zwischen den Modulen for ax in (Inches(2.725), Inches(4.275)): shp(MSO_SHAPE.RIGHT_ARROW, ax, my + mh / 2 - Inches(0.09), Inches(0.2), Inches(0.18), fill=ACCENT) txt(cx_x, cx_y + cx_h - Inches(0.34), cx_w, Inches(0.26), "In-Process-Aufrufe · Nanosekunden", size=11, color=LIGHT, align=PP_ALIGN.CENTER) # geteilte Datenbank db_w, db_h, db_y = Inches(1.5), Inches(0.95), Inches(4.0) vline(cL, cx_y + cx_h, db_y - (cx_y + cx_h), color=LINEC, weight=Pt(1.4)) sh = shp(MSO_SHAPE.CAN, cL - db_w / 2, db_y, db_w, db_h, fill=WHITE, line=LINEC, lw=Pt(1)) boxtext(sh, "DB", size=14, color=INK, bold=True) txt(cx_x, db_y + db_h + Inches(0.06), cx_w, Inches(0.28), "1 geteilte Datenbank", size=12.5, color=WHITE, bold=True, align=PP_ALIGN.CENTER) # =========================================================================== # RECHTS – Microservices: Netzwerk-Bus, N Container, DB je Service # =========================================================================== bar_x, bar_w, bar_y, bar_h = Inches(7.1), Inches(5.3), Inches(2.2), Inches(0.26) bar = shp(MSO_SHAPE.ROUNDED_RECTANGLE, bar_x, bar_y, bar_w, bar_h, fill=NAVY) boxtext(bar, "Netzwerk-Grenze · HTTP / gRPC / Events", size=11, color=WHITE, bold=True) scx = [Inches(7.95), Inches(9.75), Inches(11.55)] sc_w, sc_h, sc_y = Inches(1.5), Inches(1.2), Inches(2.62) sdb_w, sdb_h, sdb_y = Inches(0.85), Inches(0.7), Inches(3.97) for i, cx in enumerate(scx): vline(cx, bar_y + bar_h, sc_y - (bar_y + bar_h), color=LINEC, weight=Pt(1.1)) shp(MSO_SHAPE.ROUNDED_RECTANGLE, cx - sc_w / 2, sc_y, sc_w, sc_h, line=WHITE, lw=Pt(1.5)) sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, cx - Inches(0.55), sc_y + Inches(0.3), Inches(1.1), Inches(0.62), fill=WHITE, line=LINEC, lw=Pt(1)) boxtext(sh, "Svc " + LET[i], size=12.5, color=INK, bold=True) shp(MSO_SHAPE.OVAL, cx - Inches(0.06), sc_y + Inches(0.4), Inches(0.12), Inches(0.12), fill=DOT[i]) # eigene DB je Service vline(cx, sc_y + sc_h, sdb_y - (sc_y + sc_h), color=LINEC, weight=Pt(1.1)) sh = shp(MSO_SHAPE.CAN, cx - sdb_w / 2, sdb_y, sdb_w, sdb_h, fill=WHITE, line=LINEC, lw=Pt(1)) boxtext(sh, "DB", size=11, color=INK, bold=True) txt(bar_x, sdb_y + sdb_h + Inches(0.06), bar_w, Inches(0.28), "Datenbank je Service", size=12.5, color=WHITE, bold=True, align=PP_ALIGN.CENTER) # =========================================================================== # Trenner + vs. # =========================================================================== vline(Inches(6.65), Inches(1.55), Inches(3.5), color=LINEC, weight=Pt(1)) vs = shp(MSO_SHAPE.OVAL, Inches(6.65) - Inches(0.31), Inches(3.05), Inches(0.62), Inches(0.46), line=WHITE, lw=Pt(1.5)) vs.fill.background() boxtext(vs, "vs.", size=13, color=WHITE, bold=True) # =========================================================================== # Gegenüberstellung – wesentliche Unterschiede # =========================================================================== rows = [ ("Skalierung", "als Ganzes (mehr Replicas)", "je Service gezielt"), ("Datenhaltung", "1 geteilte DB", "DB je Service"), ("Deployment", "gemeinsam, 1 Pipeline", "unabhängig je Service"), ("Konsistenz", "ACID, lokal", "eventual / Saga"), ] ry = Inches(5.5) rh = Inches(0.33) chip_w = Inches(1.95) for i, (dim, mono, ms) in enumerate(rows): y = ry + rh * i chip = shp(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(6.65) - chip_w / 2, y, chip_w, Inches(0.28), line=LINEC, lw=Pt(0.75)) chip.fill.background() boxtext(chip, dim, size=11, color=LIGHT, bold=True) txt(Inches(2.5), y - Inches(0.02), Inches(3.1), Inches(0.32), mono, size=12, color=WHITE, align=PP_ALIGN.RIGHT) txt(Inches(7.72), y - Inches(0.02), Inches(3.1), Inches(0.32), ms, size=12, color=WHITE, align=PP_ALIGN.LEFT) out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Folie3b.pptx") prs.save(out) print("saved", out)