ai

Stencil.js Post-mortem Analysis

Stencil.js Post-mortem Analysis

Stencil.js Post-mortem Analysis คืออะไร

Stencil.js Post-mortem Analysis

Stencil.js เป็น compiler สำหรับสร้าง Web Components จาก Ionic team ช่วยให้เขียน components ด้วย TypeScript + JSX แล้ว compile เป็น standard Web Components ที่ใช้ได้กับทุก framework Post-mortem Analysis คือกระบวนการวิเคราะห์หลังเกิดเหตุการณ์ (incident) เพื่อหาสาเหตุ เรียนรู้ และป้องกันไม่ให้เกิดซ้ำ การรวมสองแนวคิดนี้ช่วยทีม engineering วิเคราะห์ปัญหาที่เกิดกับ Stencil.js projects อย่างเป็นระบบ ทั้ง build failures, performance issues และ production incidents

Stencil.js Overview

// stencil_overview.tsx — Stencil.js component example

import { Component, Prop, State, Event, EventEmitter, h } from '@stencil/core';



@Component({

  tag: 'my-counter',

  styleUrl: 'my-counter.css',

  shadow: true,

})

export class MyCounter {

  @Prop() initialCount: number = 0;

  @Prop() step: number = 1;

  @State() count: number;

  @Event() countChanged: EventEmitter<number>;



  componentWillLoad() {

    this.count = this.initialCount;

  }



  private increment = () => {

    this.count += this.step;

    this.countChanged.emit(this.count);

  };



  private decrement = () => {

    this.count -= this.step;

    this.countChanged.emit(this.count);

  };



  render() {

    return (

      <div class="counter">

        <button onClick={this.decrement}>-</button>

        <span class="count">{this.count}</span>

        <button onClick={this.increment}>+</button>

      </div>

    );

  }

}



// stencil.config.ts

import { Config } from '@stencil/core';

export const config: Config = {

  namespace: 'my-design-system',

  outputTargets: [

    { type: 'dist', esmLoaderPath: '../loader' },

    { type: 'dist-custom-elements' },

    { type: 'docs-readme' },

    { type: 'www', serviceWorker: null },

  ],

};

Post-mortem Analysis Framework

# postmortem.py — Post-mortem analysis framework

import json

from datetime import datetime



class PostMortemTemplate:

    TEMPLATE = {

        "title": "",

        "date": "",

        "severity": "",  # P1-P4

        "duration": "",

        "impact": "",

        "summary": "",

        "timeline": [],

        "root_cause": "",

        "contributing_factors": [],

        "resolution": "",

        "action_items": [],

        "lessons_learned": [],

    }



    SEVERITY_LEVELS = {

        "P1": {"name": "Critical", "description": "Service down, all users affected", "response": "< 15 min"},

        "P2": {"name": "Major", "description": "Service degraded, many users affected", "response": "< 30 min"},

        "P3": {"name": "Minor", "description": "Partial impact, some users affected", "response": "< 2 hours"},

        "P4": {"name": "Low", "description": "Cosmetic/minor, few users affected", "response": "< 1 day"},

    }



    FIVE_WHYS = """

    5 Whys Technique:

    

    Problem: Component library build failed in production

    

    Why 1: Stencil build errored on TypeScript compilation

    Why 2: A new component used a TypeScript 5.x feature

    Why 3: CI/CD pipeline used TypeScript 4.9 (pinned version)

    Why 4: No automated TypeScript version check in CI

    Why 5: Missing version compatibility matrix in docs

    

    Root Cause: TypeScript version mismatch between dev and CI

    Fix: Pin TypeScript version in package.json + add CI version check

    """



    def show_template(self):

        print("=== Post-mortem Template ===\n")

        for key in self.TEMPLATE:

            print(f"  {key}: ...")



    def show_severity(self):

        print(f"\n=== Severity Levels ===")

        for level, info in self.SEVERITY_LEVELS.items():

            print(f"  [{level}] {info['name']} — {info['description']} (Response: {info['response']})")



    def show_five_whys(self):

        print(f"\n=== 5 Whys Example ===")

        print(self.FIVE_WHYS[:500])



pm = PostMortemTemplate()

pm.show_template()

pm.show_severity()

pm.show_five_whys()

Common Stencil.js Incidents

Stencil.js Post-mortem Analysis
# incidents.py — Common Stencil.js incidents

import json



class StencilIncidents:

    INCIDENTS = {

        "build_failure": {

            "title": "Build Failure: TypeScript/Stencil Version Mismatch",

            "severity": "P2",

            "root_cause": "TypeScript version ใน dev ≠ CI → compiler errors",

            "resolution": "Pin exact TypeScript version, add engine check",

            "prevention": [

                "Lock TypeScript version ใน package.json (exact, ไม่ใช้ ^)",

                "Add engines field ใน package.json",

                "CI ใช้ same Node.js + npm versions as dev",

                "Renovate/Dependabot สำหรับ version updates",

            ],

        },

        "hydration_mismatch": {

            "title": "SSR Hydration Mismatch",

            "severity": "P2",

            "root_cause": "Server-rendered HTML ≠ client-rendered → visual glitch",

            "resolution": "Fix conditional rendering, use componentDidLoad instead of connectedCallback",

            "prevention": [

                "ใช้ componentDidLoad สำหรับ browser-only code",

                "Test SSR output vs client render",

                "Avoid window/document in server context",

                "Add hydration tests to CI",

            ],

        },

        "bundle_size_regression": {

            "title": "Bundle Size Regression (+200KB)",

            "severity": "P3",

            "root_cause": "New dependency imported at top-level → not tree-shaken",

            "resolution": "Dynamic import for heavy dependency",

            "prevention": [

                "Add bundle size check to CI (bundlesize, size-limit)",

                "Review imports in PR — avoid top-level heavy imports",

                "Use Stencil's lazy-loading output target",

                "Monitor bundle size trend dashboard",

            ],

        },

        "memory_leak": {

            "title": "Memory Leak in Component",

            "severity": "P2",

            "root_cause": "Event listener not removed in disconnectedCallback",

            "resolution": "Add cleanup in disconnectedCallback",

            "prevention": [

                "Linting rule: require disconnectedCallback cleanup",

                "Code review checklist: event listener cleanup",

                "Memory profiling in CI (Playwright + Chrome DevTools)",

                "Add leak detection tests",

            ],

        },

        "style_bleeding": {

            "title": "CSS Style Bleeding Between Components",

            "severity": "P3",

            "root_cause": "Component ใช้ shadow: false → global CSS leak",

            "resolution": "Enable Shadow DOM หรือ scope CSS manually",

            "prevention": [

                "Default shadow: true สำหรับทุก components",

                "CSS review: avoid global selectors",

                "Visual regression tests (Chromatic)",

            ],

        },

    }



    def show_incidents(self):

        print("=== Common Stencil.js Incidents ===\n")

        for key, inc in self.INCIDENTS.items():

            print(f"[{inc['severity']}] {inc['title']}")

            print(f"  Root cause: {inc['root_cause']}")

            print(f"  Resolution: {inc['resolution']}")

            print(f"  Prevention:")

            for p in inc["prevention"][:2]:

                print(f"    • {p}")

            print()



incidents = StencilIncidents()

incidents.show_incidents()

Automated Post-mortem Tools

# tools.py — Automated post-mortem tools

import json

import random

from datetime import datetime, timedelta



class PostMortemTools:

    CODE = """

# auto_postmortem.py — Automated post-mortem generator

import json

from datetime import datetime



class AutoPostMortem:

    def __init__(self):

        self.incidents = []

    

    def create_incident(self, title, severity, description):

        incident = {

            "id": f"INC-{len(self.incidents)+1:04d}",

            "title": title,

            "severity": severity,

            "status": "investigating",

            "created_at": datetime.utcnow().isoformat(),

            "timeline": [

                {"time": datetime.utcnow().isoformat(), "event": "Incident created"},

            ],

            "description": description,

        }

        self.incidents.append(incident)

        return incident

    

    def add_timeline(self, incident_id, event):

        for inc in self.incidents:

            if inc["id"] == incident_id:

                inc["timeline"].append({

                    "time": datetime.utcnow().isoformat(),

                    "event": event,

                })

                return True

        return False

    

    def resolve(self, incident_id, root_cause, resolution, action_items):

        for inc in self.incidents:

            if inc["id"] == incident_id:

                inc["status"] = "resolved"

                inc["resolved_at"] = datetime.utcnow().isoformat()

                inc["root_cause"] = root_cause

                inc["resolution"] = resolution

                inc["action_items"] = action_items

                return inc

        return None

    

    def generate_report(self, incident_id):

        for inc in self.incidents:

            if inc["id"] == incident_id:

                report = f"# Post-mortem: {inc['title']}\\n"

                report += f"Severity: {inc['severity']}\\n"

                report += f"Status: {inc['status']}\\n"

                report += f"\\n## Timeline\\n"

                for t in inc["timeline"]:

                    report += f"- {t['time']}: {t['event']}\\n"

                if inc.get("root_cause"):

                    report += f"\\n## Root Cause\\n{inc['root_cause']}\\n"

                if inc.get("action_items"):

                    report += f"\\n## Action Items\\n"

                    for ai in inc["action_items"]:

                        report += f"- [ ] {ai}\\n"

                return report

        return None



pm = AutoPostMortem()

inc = pm.create_incident("Stencil Build Failure", "P2", "Production build failed")

pm.add_timeline(inc["id"], "Root cause identified: TS version mismatch")

pm.resolve(inc["id"], "TypeScript 5.x feature used, CI has TS 4.9",

           "Pinned TS version to 5.3.3",

           ["Add TS version check to CI", "Update docs with compatibility matrix"])

print(pm.generate_report(inc["id"]))

"""



    def show_code(self):

        print("=== Auto Post-mortem Tool ===")

        print(self.CODE[:600])



    def metrics_dashboard(self):

        print(f"\n=== Incident Metrics (Last 90 days) ===")

        print(f"  Total incidents: {random.randint(5, 15)}")

        print(f"  P1: {random.randint(0, 2)} | P2: {random.randint(1, 5)} | P3: {random.randint(2, 8)} | P4: {random.randint(0, 3)}")

        print(f"  MTTR (Mean Time to Resolve): {random.randint(30, 180)} minutes")

        print(f"  MTTD (Mean Time to Detect): {random.randint(5, 30)} minutes")

        print(f"  Repeat incidents: {random.randint(0, 3)}")

        print(f"  Action items completed: {random.randint(70, 95)}%")



tools = PostMortemTools()

tools.show_code()

tools.metrics_dashboard()

Prevention & Best Practices

# prevention.py — Prevention best practices

import json



class Prevention:

    CI_CHECKS = {

        "build": "Stencil build ต้อง pass ทุก PR",

        "test": "Unit tests + visual regression tests",

        "bundle_size": "Bundle size limit check (size-limit)",

        "a11y": "Accessibility audit (axe-core)",

        "type_check": "TypeScript strict mode check",

        "lint": "ESLint + Stylelint",

        "version_check": "Node.js + TypeScript version compatibility",

    }



    MONITORING = {

        "error_tracking": "Sentry — track runtime errors ใน Web Components",

        "performance": "Web Vitals — LCP, FID, CLS ของ pages ที่ใช้ components",

        "bundle_trend": "Bundle size trend — track regression over time",

        "usage_analytics": "Component usage analytics — ใครใช้ component ไหน",

    }



    BLAMELESS_CULTURE = [

        "Focus on systems ไม่ใช่ individuals",

        "ทุกคนทำผิดได้ — ระบบต้องป้องกัน",

        "Post-mortem = learning opportunity ไม่ใช่ blame session",

        "Share post-mortems openly — ทั้งองค์กรเรียนรู้",

        "Action items ต้องมี owner + deadline",

        "Review action items ทุกสัปดาห์ — ไม่ปล่อยค้าง",

    ]



    def show_ci(self):

        print("=== CI/CD Checks ===\n")

        for check, desc in self.CI_CHECKS.items():

            print(f"  [{check}] {desc}")



    def show_monitoring(self):

        print(f"\n=== Monitoring ===")

        for key, desc in self.MONITORING.items():

            print(f"  [{key}] {desc}")



    def show_culture(self):

        print(f"\n=== Blameless Culture ===")

        for principle in self.BLAMELESS_CULTURE[:4]:

            print(f"  • {principle}")



prev = Prevention()

prev.show_ci()

prev.show_monitoring()

prev.show_culture()

FAQ - คำถามที่พบบ่อย

Q: Stencil.js กับ Lit อันไหนดี?

A: Stencil: compiler-based, TypeScript + JSX, lazy-loading built-in, Ionic ecosystem Lit: runtime library (~5KB), simpler, Google-backed, larger community ใช้ Stencil: Ionic projects, ต้องการ TypeScript + JSX, lazy-loading ใช้ Lit: lightweight, ไม่ต้องการ build step, simpler API ทั้งคู่ output standard Web Components — เลือกตาม team preference

เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง SigNoz Observability Scaling Strategy วิธี Scale

Q: Post-mortem ต้องทำทุก incident ไหม?

แนะนำเพิ่มเติม — คอร์สเทรด Forex ที่ iCafeForex

A: P1-P2: ต้องทำทุกครั้ง (within 48 hours) P3: ทำเมื่อมี lessons สำคัญ หรือ repeat incident P4: ไม่จำเป็น — track ใน issue tracker Format: สั้น กระชับ — ไม่ต้องยาวเป็นหน้าๆ สำคัญ: action items ต้องมี owner + deadline + follow-up

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน Qwik Resumability Scaling Strategy วิธี Scale

Q: 5 Whys ใช้ยังไง?

A: ถาม "ทำไม" ซ้ำๆ จนถึง root cause (ปกติ 3-5 ครั้ง) เริ่มจาก symptom → drill down จนถึงสิ่งที่ fix ได้ อย่าหยุดที่ "human error" — ถามต่อว่าทำไมระบบไม่ป้องกัน ตัวอย่าง: Build failed → TS version mismatch → ไม่มี version pin → ไม่มี policy → สร้าง policy + CI check

แนะนำเพิ่มเติม — SiamCafeBook

เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง LLM Quantization GGUF Observability Stack — คู่มือฉบับสมบูรณ์ 2026

Q: Blameless post-mortem สำคัญอย่างไร?

A: ถ้า blame คน → คนซ่อนปัญหา → ปัญหาไม่ถูกแก้ → เกิดซ้ำ ถ้า blameless → คนกล้าพูด → เรียนรู้จากปัญหา → ป้องกันได้ Focus: ระบบ + process ต้องดีพอที่จะป้องกัน human error วัฒนธรรม: "ทำไมระบบยอมให้สิ่งนี้เกิด?" ไม่ใช่ "ใครทำ?"

เนื้อหาเกี่ยวข้อง — Prometheus Alertmanager MLOps Workflow

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง