<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Fragments</title><description>Stream of consciousness notes that don&apos;t merit a more dedicated write up.</description><link>https://world-rose.vercel.app/</link><item><title>Simulate Tests To Use Real Dependencies</title><link>https://world-rose.vercel.app/fragments/testcontainers</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/testcontainers</guid><description>Tests often execute against an environment that cannot fail in the same ways production can. The difference is usually intentional, but it’s not always obvious which assumptions are being made.</description><pubDate>Fri, 16 Jan 2026 03:06:04 GMT</pubDate><content:encoded>&lt;p&gt;This approach entered my workflow a few weeks ago after a colleague, &lt;a href=&quot;https://www.linkedin.com/in/remedan-ridwan/&quot;&gt;Remedan Ridwan&lt;/a&gt;, pointed me to &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt;. What stood out wasn’t the tooling itself, but how little code was required to run real dependencies in tests. With Docker already becoming standard, it became practical to exercise integration paths against actual services rather than substitutes.&lt;/p&gt;
&lt;p&gt;Most test strategies break down not because individual components are hard to test, but because the &lt;em&gt;environment&lt;/em&gt; they run in is assumed rather than exercised.&lt;/p&gt;
&lt;p&gt;Applications don’t run against a database in isolation. They run inside an environment: databases, message queues, caches, object stores, authentication services, clocks, filesystems, and network boundaries. Bugs tend to emerge at the seams between these pieces, especially where configuration, protocol behavior, or timing is involved.&lt;/p&gt;
&lt;p&gt;Mocks simplify this environment aggressively. That simplification is often intentional, but it also removes entire classes of behavior that only exist when real systems are present.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;What “Mocking the Environment” Usually Means&lt;/h3&gt;
&lt;p&gt;In practice, “mocking the environment” tends to mean one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replacing external services with in-memory implementations&lt;/li&gt;
&lt;li&gt;Mocking interfaces that represent networked systems&lt;/li&gt;
&lt;li&gt;Using lightweight substitutes that approximate behavior (e.g., SQLite for Postgres, localstack-style APIs, fake SMTP servers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These approaches are fast and convenient. They also tend to encode assumptions about how the environment behaves rather than verifying those assumptions.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A mocked queue acknowledges messages immediately, bypassing retry or backoff paths. In a real system like RabbitMQ, a consumer restart triggers redelivery, revealing missing idempotency in message handlers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In-memory databases permit concurrent writes without contention. A real PostgreSQL instance under load introduces blocking transactions, timeouts, or deadlocks that surface only with actual concurrency.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fake caches return values instantly, hiding latency from misses. A real Redis instance introduces spikes that affect downstream logic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mocked services respond synchronously, missing rate limits like 429 errors from real endpoints.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test doubles accept any token, ignoring expiry or clock skew enforced by real auth providers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Local mocks enable atomic writes. Real object stores like S3 show partial or eventual consistency.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mocks never fail DNS, bypassing retry logic in real networks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Using Real Dependencies as Disposable Infrastructure&lt;/h3&gt;
&lt;p&gt;An alternative approach is to run real services with production-grade binaries inside tests, and treat them as disposable infrastructure.&lt;/p&gt;
&lt;p&gt;This is the model &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt; supports.&lt;/p&gt;
&lt;p&gt;Rather than mocking a database client or a queue interface, the test starts an actual instance of the dependency in a container:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The same database engine&lt;/li&gt;
&lt;li&gt;The same message broker&lt;/li&gt;
&lt;li&gt;The same object storage service&lt;/li&gt;
&lt;li&gt;The same auth provider or proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The test code interacts with these services over the same protocols used in production. Configuration, startup behavior, and failure modes are preserved.&lt;/p&gt;
&lt;p&gt;Databases are a common example, but they’re not the point. The point is &lt;strong&gt;environment simulation&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Example: Database as One Dependency Among Many&lt;/h3&gt;
&lt;p&gt;A database example is illustrative because it’s familiar.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Container wraps testcontainers with database and cache connections
type Container struct {
    PostgresContainer *postgres.PostgresContainer
    RedisContainer    *redisContainer.RedisContainer
    DB                *gorm.DB
    Redis             *redis.Client
}

// Terminate gracefully shuts down all containers
func (c *Container) Terminate() error {
    ctx := context.Background()

    if c.PostgresContainer != nil {
        if err := c.PostgresContainer.Terminate(ctx); err != nil {
            return err
        }
    }

    if c.RedisContainer != nil {
        if err := c.RedisContainer.Terminate(ctx); err != nil {
            return err
        }
    }

    return nil
}

// CleanupDatabase cleans all test data from database tables
func (c *Container) CleanupDatabase(t *testing.T) {
    t.Helper()

    if c.DB == nil {
        return
    }

    // Dynamically get all user tables from information_schema
    var tables []string
    err := c.DB.Raw(`
        SELECT table_name
        FROM information_schema.tables
        WHERE table_schema = &apos;public&apos;
        AND table_type = &apos;BASE TABLE&apos;
        AND table_name NOT LIKE &apos;pg_%&apos;
        AND table_name NOT LIKE &apos;sql_%&apos;
    `).Scan(&amp;amp;tables).Error

    if err != nil {
        t.Logf(&quot;failed to get table list: %v&quot;, err)
        return
    }

    // Truncate all found tables
    for _, table := range tables {
        err = c.DB.Exec(&quot;TRUNCATE TABLE &quot; + table + &quot; CASCADE&quot;).Error
        if err != nil {
            t.Logf(&quot;failed to truncate table %s: %v&quot;, table, err)
        }
    }
}

// CleanupCache clears all Redis cache data
func (c *Container) CleanupCache(t *testing.T) {
    t.Helper()

    if c.Redis == nil {
        return
    }

    err := c.Redis.FlushAll(context.Background()).Err()
    if err != nil {
        t.Logf(&quot;failed to flush Redis cache: %v&quot;, err)
    }
}

// CleanupAll cleans both database and cache
func (c *Container) CleanupAll(t *testing.T) {
    c.CleanupDatabase(t)
    c.CleanupCache(t)
}

// SetupTestMain sets up shared containers for a test package
// Should be called from TestMain to initialize containers once per package
func SetupTestMain() (*Container, func() int) {
    ctx := context.Background()

    // Setup PostgreSQL
    postgresContainer, err := postgres.Run(ctx,
        &quot;postgres:15-alpine&quot;,
        postgres.WithDatabase(&quot;testdb&quot;),
        postgres.WithUsername(&quot;testuser&quot;),
        postgres.WithPassword(&quot;testpass&quot;),
        testcontainers.WithWaitStrategy(
            wait.ForLog(&quot;database system is ready to accept connections&quot;).
                WithOccurrence(2).
                WithStartupTimeout(5*time.Minute)),
    )
    if err != nil {
        panic(&quot;failed to start postgres container: &quot; + err.Error())
    }

    host, err := postgresContainer.Host(ctx)
    if err != nil {
        panic(&quot;failed to get postgres host: &quot; + err.Error())
    }

    port, err := postgresContainer.MappedPort(ctx, &quot;5432&quot;)
    if err != nil {
        panic(&quot;failed to get postgres port: &quot; + err.Error())
    }

    cfg := &amp;amp;config.Config{
        Database: config.Database{
            Host:        host,
            Port:        port.Int(),
            User:        &quot;testuser&quot;,
            Password:    &quot;testpass&quot;,
            Name:        &quot;testdb&quot;,
            MaxIdleConn: 10,
            MaxOpenConn: 100,
        },
    }

    dbConn, err := db.NewPostgres(cfg)
    if err != nil {
        panic(&quot;failed to connect to test database: &quot; + err.Error())
    }

    // Setup Redis
    redisContainer, err := redisContainer.Run(ctx,
        &quot;redis:7-alpine&quot;,
        testcontainers.WithWaitStrategy(wait.ForLog(&quot;Ready to accept connections&quot;)),
    )
    if err != nil {
        panic(&quot;failed to start redis container: &quot; + err.Error())
    }

    redisHost, err := redisContainer.Host(ctx)
    if err != nil {
        panic(&quot;failed to get redis host: &quot; + err.Error())
    }

    redisPort, err := redisContainer.MappedPort(ctx, &quot;6379&quot;)
    if err != nil {
        panic(&quot;failed to get redis port: &quot; + err.Error())
    }

    redisClient := redis.NewClient(&amp;amp;redis.Options{
        Addr: redisHost + &quot;:&quot; + redisPort.Port(),
    })

    // Test Redis connection
    err = redisClient.Ping(ctx).Err()
    if err != nil {
        panic(&quot;failed to connect to test redis: &quot; + err.Error())
    }

    container := &amp;amp;Container{
        PostgresContainer: postgresContainer,
        RedisContainer:    redisContainer,
        DB:                dbConn,
        Redis:             redisClient,
    }

    // Return cleanup function for TestMain
    cleanup := func() int {
        if err := container.Terminate(); err != nil {
            println(&quot;failed to terminate containers:&quot;, err.Error())
            return 1
        }
        return 0
    }

    return container, cleanup
}

// RunStandardMigrations runs migrations for common models used across tests
func (c *Container) RunStandardMigrations(t *testing.T) {
    t.Helper()

    err := c.DB.AutoMigrate(&amp;amp;user.User{}, &amp;amp;user.Preference{})
    require.NoError(t, err)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This verifies more than CRUD correctness:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connection negotiation&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Schema compatibility&lt;/li&gt;
&lt;li&gt;Transaction semantics&lt;/li&gt;
&lt;li&gt;Driver behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the same pattern applies elsewhere.&lt;/p&gt;
&lt;p&gt;The same test suite can bring up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Redis instance with real eviction behavior&lt;/li&gt;
&lt;li&gt;A Kafka broker with actual partitioning and offsets&lt;/li&gt;
&lt;li&gt;An S3-compatible object store that enforces request signing&lt;/li&gt;
&lt;li&gt;An SMTP server that accepts and rejects messages based on protocol rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each container adds realism that mocks typically erase.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Why This Is Not “Just Another Mock”&lt;/h3&gt;
&lt;p&gt;It’s tempting to think of containers as “better mocks.” That framing is misleading.&lt;/p&gt;
&lt;p&gt;Mocks &lt;em&gt;simulate behavior&lt;/em&gt;. Containers &lt;em&gt;instantiate systems&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A containerized dependency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Has startup time&lt;/li&gt;
&lt;li&gt;Has configuration errors&lt;/li&gt;
&lt;li&gt;Has resource limits&lt;/li&gt;
&lt;li&gt;Can fail in partial or unexpected ways&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those properties are inconvenient, but they’re also where integration bugs come from.&lt;/p&gt;
&lt;p&gt;When tests exercise real services, failures tend to be less surprising. Not because the code is better, but because the assumptions are weaker.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Cost and Constraints&lt;/h3&gt;
&lt;p&gt;This approach is not free.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests are slower&lt;/li&gt;
&lt;li&gt;Docker becomes a test dependency&lt;/li&gt;
&lt;li&gt;Parallelism must be controlled&lt;/li&gt;
&lt;li&gt;CI resource limits matter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also shifts test failures from “logical mismatch” to “environmental mismatch,” which can be harder to debug if logs and observability aren’t captured.&lt;/p&gt;
&lt;p&gt;Adopting this style of testing usually forces a rethink of the CI process. Cloud CI environments are optimized for fast, isolated test runs, not for standing up short-lived infrastructure. If these bugs are meant to be caught in CI, pipelines need to account for container startup time, resource allocation, and artifact collection.&lt;/p&gt;
&lt;p&gt;That said, many of these issues are often easier to surface locally than in CI. A developer running tests with real dependencies on their machine can reproduce configuration errors, protocol mismatches, and startup failures quickly, without waiting on a constrained CI environment. &lt;/p&gt;
&lt;p&gt;In my small monolithic application, using Testcontainers did not meaningfully affect CI time. Container startup was fast, Docker overhead was negligible, and tests did not introduce noticeable delays. The additional realism came without a proportional cost.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Where This Tends to Pay Off&lt;/h3&gt;
&lt;p&gt;Running real dependencies is most useful where code behavior depends on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Protocol details&lt;/li&gt;
&lt;li&gt;Configuration correctness&lt;/li&gt;
&lt;li&gt;Ordering and timing&lt;/li&gt;
&lt;li&gt;Cross service interactions&lt;/li&gt;
&lt;li&gt;Version specific behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, places where mocks tend to encode guesses.&lt;/p&gt;
&lt;p&gt;Using real services doesn’t eliminate bugs. It mostly eliminates a specific category of bug: &lt;em&gt;the one where the system behaved correctly according to your test, and incorrectly according to reality&lt;/em&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Scope&lt;/h3&gt;
&lt;p&gt;This is not an argument against mocking. It’s an argument against pretending the environment is simpler than it is.&lt;/p&gt;
&lt;p&gt;Testcontainers provides a way to reconstruct small, controlled slices of reality inside tests. Databases are just one visible example.&lt;/p&gt;
&lt;p&gt;Whether that trade-off is worthwhile depends on where failures are expensive and surprises are unacceptable.&lt;/p&gt;
</content:encoded><category>golang</category><category>test-containers</category><author>deamking@icloud.com (Dream king)</author></item><item><title>A Case for Trunk-Based Development</title><link>https://world-rose.vercel.app/fragments/tbd</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/tbd</guid><description>Maybe We’re Making Collaboration Harder Than It Needs to Be</description><pubDate>Mon, 14 Jul 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Why do we hold onto our code for so long before showing it to each other?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most teams I’ve worked with (and most setups I’ve used) default to some version of:
Create a feature branch → Work for a few days → Push a PR → Wait for review → Hope it merges clean.&lt;/p&gt;
&lt;p&gt;It feels normal. Professional, even. But after watching a video by &lt;a href=&quot;https://youtube.com/watch?v=v4Ijkq6Myfc&quot;&gt;Dave Farley&lt;/a&gt;, I started wondering whether that approach, however polished, is fundamentally at odds with what &lt;strong&gt;continuous integration&lt;/strong&gt; was meant to be.&lt;/p&gt;
&lt;p&gt;And if we’re honest, the cost of holding onto code is real:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merge conflicts that eat hours&lt;/li&gt;
&lt;li&gt;Integration bugs that don’t show up until late&lt;/li&gt;
&lt;li&gt;Review cycles that turn into backlogs&lt;/li&gt;
&lt;li&gt;Features that go stale before they ship&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So here’s my proposal:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if we stopped working in isolation and started working in the open, every day?&lt;/strong&gt;
What if the default wasn’t to hide changes, but to integrate them immediately?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;A Simpler Model, Hiding Less&lt;/h2&gt;
&lt;p&gt;Enter: &lt;strong&gt;Trunk-Based Development&lt;/strong&gt; (TBD).&lt;/p&gt;
&lt;p&gt;The idea is disarmingly simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everyone commits to a shared &lt;code&gt;main&lt;/code&gt; (or &lt;code&gt;trunk&lt;/code&gt;) branch&lt;/li&gt;
&lt;li&gt;If you do branch, the branches live for a few hours, max a day&lt;/li&gt;
&lt;li&gt;You commit often (multiple times a day, ideally)&lt;/li&gt;
&lt;li&gt;You use &lt;strong&gt;feature flags&lt;/strong&gt;, &lt;strong&gt;dark launching&lt;/strong&gt;, or &lt;strong&gt;branch by abstraction&lt;/strong&gt; to hide incomplete features, not separate them&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal isn’t just faster merging, it’s &lt;strong&gt;always working on the same “truth” of the codebase&lt;/strong&gt;, together.&lt;/p&gt;
&lt;p&gt;You shrink the distance between your work and everyone else’s.&lt;/p&gt;
&lt;p&gt;You don’t wait to be “done” to integrate. You integrate to help &lt;strong&gt;get&lt;/strong&gt; to “done.”&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why It’s Worth Considering (Even If It Feels Radical)&lt;/h2&gt;
&lt;p&gt;I haven’t rolled out TBD on a team yet, but I want to. Here’s why it’s compelling to me:&lt;/p&gt;
&lt;h3&gt;🧩 It removes the &quot;two truths&quot; problem&lt;/h3&gt;
&lt;p&gt;Every branch is a fork in reality. Testing, debugging, and merging all become harder when you&apos;re working on different timelines. TBD says: stop forking reality.&lt;/p&gt;
&lt;h3&gt;⚡ It tightens feedback loops&lt;/h3&gt;
&lt;p&gt;If your changes break something, you know immediately. If they work well, others can build on them, right now.&lt;/p&gt;
&lt;h3&gt;🤝 It encourages better engineering habits&lt;/h3&gt;
&lt;p&gt;Small, testable commits. Stronger CI/CD. Less cowboy coding. More collaboration. This model nudges you toward sustainable speed.&lt;/p&gt;
&lt;h3&gt;🌱 It helps you grow as a developer&lt;/h3&gt;
&lt;p&gt;When you ship partial features behind flags and test unfinished ideas in production (safely), you start thinking more modularly. You work in smaller steps. You get better at decoupling.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;So, How Do You Work Without Branches?&lt;/h2&gt;
&lt;p&gt;We’d need some process guardrails to make this safe and practical. Based on what I’ve learned, here’s what adopting TBD might look like:&lt;/p&gt;
&lt;h3&gt;✅ Daily-or more frequent-commits to main&lt;/h3&gt;
&lt;p&gt;Work in small, composable chunks. A few lines of logic. A tiny refactor. A test case. Ship that. Move on.&lt;/p&gt;
&lt;h3&gt;✅ Feature flags everywhere&lt;/h3&gt;
&lt;p&gt;Use toggles to control whether a feature is active, not whether the code exists. That means you can commit unfinished work without affecting users.&lt;/p&gt;
&lt;h3&gt;✅ Strong CI/CD pipelines&lt;/h3&gt;
&lt;p&gt;If commits go straight to main, your tests better catch regressions fast. Ideally, your test suite gives you high confidence on every push.&lt;/p&gt;
&lt;h3&gt;✅ Dark launching and branch by abstraction&lt;/h3&gt;
&lt;p&gt;Need to deploy backend logic without exposing a UI? Do it. Want to refactor a critical path gradually? Abstract it, then replace it behind the scenes.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why This Isn’t Just About Speed&lt;/h2&gt;
&lt;p&gt;One of the most surprising things I took away from Dave Farley’s talk was that &lt;strong&gt;trunk-based development isn’t just about faster releases&lt;/strong&gt;. It’s about &lt;strong&gt;trust&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Trust that your teammates won’t break things carelessly.
Trust that your process can catch bugs early.
Trust that your code doesn’t have to be perfect before it’s shared.&lt;/p&gt;
&lt;p&gt;It’s not about being reckless. It’s about choosing visibility over isolation.
And when you do that, something strange happens:
People talk more. Teams align better. Features ship more predictably.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Trade-Off&lt;/h2&gt;
&lt;p&gt;Adopting this would mean letting go of “I’ll push when I’m done.”
It would mean embracing partial work in main.
It would mean making integration a habit, not a milestone.&lt;/p&gt;
&lt;p&gt;But the payoff?
No more last-minute merges.
No more “Oh wait, you changed that too?”
No more testing code that will never actually ship.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Final Thought&lt;/h2&gt;
&lt;p&gt;Git made branching feel cheap. But integration costs? Those are still high, especially when you do them late.&lt;/p&gt;
&lt;p&gt;TBD flips the script: it makes &lt;strong&gt;integration cheap&lt;/strong&gt; and &lt;strong&gt;isolation costly&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That shift, mental, technical, and cultural, is what makes it worth exploring.&lt;/p&gt;
&lt;p&gt;If you’re building something fast-moving and collaborative, I think this approach deserves more attention. I’m still learning, still poking holes, but the direction feels right.&lt;/p&gt;
&lt;p&gt;And maybe, just maybe, it&apos;s time we stop treating integration as the thing we do at the end, and start treating it as the thing we do all the time.&lt;/p&gt;
</content:encoded><category>feature-flags</category><author>deamking@icloud.com (Dream king)</author></item><item><title>The Gold Rush for AI Assistants</title><link>https://world-rose.vercel.app/fragments/mcp</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/mcp</guid><description>Why I’m Betting on Tools</description><pubDate>Fri, 30 May 2025 14:03:01 GMT</pubDate><content:encoded>&lt;figure&gt;
    
    &lt;figcaption&gt;Learning MCP&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There’s a particular feeling I get when the tech world starts buzzing like everyone just heard the same secret at once. Right now, that secret is: &lt;strong&gt;AI assistants are the next big platform&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But beneath the noise, I’ve been wrestling with a quieter question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If everyone’s racing to build the next AI assistant, where does someone like me a developer who’s not at OpenAI or Google actually fit in?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is me talking to my past self, the one who felt both inspired and slightly paralyzed by this wave. I’m writing this because I think the most valuable seat at this table might not be the one building the assistants, but the one forging the tools they use.&lt;/p&gt;
&lt;h3&gt;Assistants Need Tools, Not Just Intelligence&lt;/h3&gt;
&lt;p&gt;Every assistant, no matter how fancy the model, becomes useless the moment it hits a wall. Ask it to book a flight? It needs a travel API. Want it to manage your files? It needs a storage service. Assistants are only as capable as the tools they can call.&lt;/p&gt;
&lt;p&gt;And here’s the thing: &lt;strong&gt;most developers are focusing on the assistant layer&lt;/strong&gt; the chat UIs, the voice apps, the agent runners. But there’s a quieter, more foundational layer underneath all of that: the tools. The APIs. The MCP servers.&lt;/p&gt;
&lt;h3&gt;What is an MCP Server?&lt;/h3&gt;
&lt;p&gt;MCP stands for &lt;strong&gt;Model Context Protocol&lt;/strong&gt;. It’s a standardized way for AI assistants to interact with software. Think of it as a shared grammar that allows an AI to command a wide range of apps without custom code for each.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;MCP server&lt;/strong&gt; acts as a translator sitting beside a particular application. It knows how to take a natural-language request and turn it into something the app understands whether that’s a Python call in Blender or a GitHub API query.&lt;/p&gt;
&lt;p&gt;It handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool discovery&lt;/strong&gt;: What can this app do?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command parsing&lt;/strong&gt;: What is the AI asking for, and how do we do that here?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Response formatting&lt;/strong&gt;: How do we return something meaningful?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error handling&lt;/strong&gt;: What happens when something goes wrong?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the other end, the &lt;strong&gt;MCP client&lt;/strong&gt; lives with the AI assistant. It talks to the MCP server, relays messages, and feeds responses back into the AI. All of this happens via a protocol that’s &lt;strong&gt;transport-agnostic&lt;/strong&gt; (HTTP, WebSocket, even stdin/stdout), and uses &lt;strong&gt;JSON Schema&lt;/strong&gt; to describe capabilities.&lt;/p&gt;
&lt;p&gt;This architecture allows an assistant to use any MCP-compliant tool the same way a GitHub server, a database query engine, or a local file browser. It’s the glue that binds natural language to real action.&lt;/p&gt;
&lt;h3&gt;What That Looks Like for Me&lt;/h3&gt;
&lt;p&gt;I’m starting to shift my mindset from “app developer” to &lt;strong&gt;“toolmaker for assistants.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That means I’m asking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can I build an MCP server around something I already use or maintain?&lt;/li&gt;
&lt;li&gt;Can I turn some internal service like a chunked file uploader or a tagging system into a callable tool for AI?&lt;/li&gt;
&lt;li&gt;Can I write my tools in a way that feels native to this protocol-first world?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re not just building web apps anymore. We’re building AI-accessible utilities.&lt;/p&gt;
&lt;h3&gt;Where I’m Investing My Time&lt;/h3&gt;
&lt;p&gt;Here’s the roadmap I’m following loosely, but intentionally:&lt;/p&gt;
&lt;h4&gt;1. &lt;strong&gt;Master MCP-friendly APIs&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Whether it’s OpenAPI specs or JSON Schema definitions, I want my tools to be discoverable and callable without extra glue code.&lt;/p&gt;
&lt;h4&gt;2. &lt;strong&gt;Wrap Existing Services in MCP Servers&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;That chunked upload system I’ve been building? I’m wrapping it in an MCP server so any AI assistant can manage file uploads through it.&lt;/p&gt;
&lt;h4&gt;3. &lt;strong&gt;Understand Orchestration&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;I’m learning how AI assistants string tools together using orchestration layers like LangChain and AutoGen. This helps me make my tools composable.&lt;/p&gt;
&lt;h4&gt;4. &lt;strong&gt;Go Deep in One Domain&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;My focus is on developer tools and healthcare. I want to create AI-usable services that are actually helpful in these spaces.&lt;/p&gt;
&lt;h4&gt;5. &lt;strong&gt;Keep an Eye on Standards&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The MCP spec is evolving. I’m watching how it handles things like authentication, permissions, and plugin discovery so I can build forward-compatible tools.&lt;/p&gt;
&lt;h3&gt;A Safe Prediction and a Big Shift&lt;/h3&gt;
&lt;p&gt;Here’s the shift I can’t stop thinking about:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In the near future, apps won’t be things people install. They’ll be installing services assistants who know enough tools for the day to day.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead of getting a user to download your app, onboard, understand your UI, sign in, and learn your flow you’ll just have an MCP-compliant server. The user tells their assistant (GPT, Gemini, whoever), “I need this done,” and your tool quietly powers the response.&lt;/p&gt;
&lt;p&gt;There’s no app store. No tutorials. No language barrier or digital literacy hurdle. Whether the user is tech-savvy or not, the assistant becomes the interface and your MCP server becomes the service.&lt;/p&gt;
&lt;p&gt;This changes everything. Customer support, ecommerce, onboarding, payment flows all the traditional barriers of software UX fade into the background. It’s not about building the prettiest UI anymore. It’s about being &lt;em&gt;callable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The moment that clicked for me, I realized: building tools for this world isn’t just a new opportunity. It’s a whole new lens.&lt;/p&gt;
&lt;h3&gt;Why This Matters (Zooming Out)&lt;/h3&gt;
&lt;p&gt;There’s a deeper shift happening here. AI assistants aren’t just a trend they’re a new way of interacting with software. But assistants can’t do anything alone. They need ecosystems. They need &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you’re a developer wondering how to catch this wave, you don’t need to reinvent intelligence. Just build something useful and make it callable.&lt;/p&gt;
&lt;p&gt;I think the next generation of successful devs won’t be the ones who built the assistants. It’ll be the ones who quietly empowered them.&lt;/p&gt;
&lt;p&gt;And if you&apos;re unsure where to start look at the tools you’ve already built. Chances are, one of them just needs a spec and a little polish to become someone else’s missing piece.&lt;/p&gt;
</content:encoded><category>typescript</category><author>deamking@icloud.com (Dream king)</author></item><item><title>First Time at the Booth</title><link>https://world-rose.vercel.app/fragments/etex_2025</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/etex_2025</guid><description>What I Learned Representing YeneHealth at ETEX 2025</description><pubDate>Tue, 20 May 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;I didn’t know how hard it would be to explain YeneHealth until I had to.&lt;/p&gt;
&lt;p&gt;I was at &lt;strong&gt;ETEX 2025&lt;/strong&gt;, Ethiopia’s tech expo showcasing AI, cybersecurity, smart cities, and all the buzzwords that usually sound like they belong to somewhere else. But this time, they didn’t. They belonged here. To us.&lt;/p&gt;
&lt;p&gt;We had a sponsored booth, its not our first time showing up at this scale. I had the chance to represent YeneHealth. My first thought? &lt;em&gt;I hope they don’t ask too many questions.&lt;/em&gt; Because, truthfully, I only had the “About Us” version of YeneHealth in my head. And that version isn’t built for conversations.&lt;/p&gt;
&lt;p&gt;It’s hard to explain YeneHealth because it’s not one thing. We work across so many edges of healthcare, data, community, and technology that trying to condense it into an elevator pitch feels like trying to summarize a whole family history in one sentence. At first, I stumbled. I said the same few phrases, something about “improving access to reproductive healthcare” and “data-driven community engagement” but I could see people nodding politely, not curiously.&lt;/p&gt;
&lt;p&gt;Then something shifted. I started telling stories.&lt;/p&gt;
&lt;p&gt;Not pitch-perfect ones, just real ones. Like how we started by trying to solve a small pain point. Or how we learned from the communities we served. Or how our team wasn’t a bunch of detached techies but people with skin in the game, literally and metaphorically.&lt;/p&gt;
&lt;p&gt;And people leaned in.&lt;/p&gt;
&lt;p&gt;I didn’t have all the history. I still don’t. But the more I talked, the more I understood &lt;em&gt;why&lt;/em&gt; we do what we do, and how much that matters.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;What I Didn’t Expect to Learn&lt;/h3&gt;
&lt;p&gt;Events like ETEX aren’t just for showing off. They’re for sharpening your story.&lt;/p&gt;
&lt;p&gt;When you stand behind the booth, you’re not pitching, you’re pressure-testing your message. Every confused face or curious question forces you to refine. Every person who &lt;em&gt;gets it&lt;/em&gt; becomes a mirror that tells you, “Yes, that landed.”&lt;/p&gt;
&lt;p&gt;It’s also a kind of low-key battlefield. The investors and potential partners? They don’t wear badges that say “VC.” They walk around in simple clothes, ask casual questions, and listen closely. And they &lt;em&gt;love&lt;/em&gt; teams who can explain their product clearly, without the fluff. You’ll only catch them if you show up prepared and present.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;For Any Startup Thinking of Skipping the Booth&lt;/h3&gt;
&lt;p&gt;Don’t.&lt;/p&gt;
&lt;p&gt;Especially if you’re technical. Bring your engineers. Bring your designers. Let the people who &lt;em&gt;build&lt;/em&gt; the product explain it. There’s a magic that happens when someone who’s knee-deep in code explains why they care about what they’re building. People listen differently.&lt;/p&gt;
&lt;p&gt;It’s also one of the rare chances to collect live, honest, unfiltered feedback. Think of it as a &lt;strong&gt;mini focus group&lt;/strong&gt; that actually volunteered to talk to you.&lt;/p&gt;
&lt;p&gt;And for the team? Motivation skyrockets. There’s something energizing about seeing strangers get excited about what you’re building. It reminds you why the long hours and unresolved tickets matter.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Event Review&lt;/h3&gt;
&lt;p&gt;The venue &lt;strong&gt;Addis International Convention Center&lt;/strong&gt; was massive. The kind of space that makes you think, &lt;em&gt;“Wow, this country is dreaming big.”&lt;/em&gt; And it felt good to be part of that dream, even just for a day.&lt;/p&gt;
&lt;p&gt;I walked in nervous and walked out grateful. I thought I was going there to explain what we do. But I ended up understanding it better myself.&lt;/p&gt;
&lt;p&gt;If you ever get the chance to represent your team at an event like this take it. You won’t just represent your product. You’ll rediscover it.&lt;/p&gt;
</content:encoded><category>etex</category><category>event</category><category>reaction</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Chucked Uploads, Persistent Sessions</title><link>https://world-rose.vercel.app/fragments/chunking</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/chunking</guid><description>Added a feature to support Chunked uploads, with persistent and resumable session storage</description><pubDate>Fri, 16 May 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;I was wiring up a file upload system in Node.js, not the flashy, frontend kind with progress bars and drag-and-drop zones, but the backend guts. The part that takes a stream of chunks, holds onto them safely, and eventually stitches them together into the final file.&lt;/p&gt;
&lt;p&gt;I didn’t want to build an HTTP server. I didn’t want a frontend client. I just needed a Node.js class that could handle uploads in pieces, reliably, resumably, and testably.&lt;/p&gt;
&lt;p&gt;Turns out, that second word &lt;em&gt;resumably&lt;/em&gt; is where things got tricky.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Why Chunked Uploads?&lt;/h3&gt;
&lt;p&gt;Let’s set the stage. Chunked uploads matter when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Files are large (video, images, backups)&lt;/li&gt;
&lt;li&gt;Network stability is unreliable&lt;/li&gt;
&lt;li&gt;You want to support pause/resume functionality&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wanted a simple API:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;startUpload(id, filename);
appendChunk(id, chunkIndex, data);
completeUpload(id);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Later, I added a session-based version with metadata and visibility support:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;startSession(id, totalChunks, originalName, targetPath, visibility);
receiveChunk(id, chunkIndex, chunk);
finalizeUpload(id);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two APIs, one underlying system. It worked. Until I restarted the process.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Problem: Memory Is Not Persistence&lt;/h3&gt;
&lt;p&gt;All session state lived in memory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private sessions = new Map&amp;lt;string, UploadSession&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So if the process crashed or restarted, it lost track of what chunks were received. It couldn’t resume an upload. The actual chunk files were still on disk, but without the metadata, they were just orphaned data.&lt;/p&gt;
&lt;p&gt;It hit me: &lt;strong&gt;resumability isn’t just about chunk files, it’s about remembering the upload state.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That meant one thing: I had to persist session metadata to disk.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Fix: Metadata Files&lt;/h3&gt;
&lt;p&gt;Every session now gets a &lt;code&gt;metadata.json&lt;/code&gt; file alongside its chunks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;id&quot;: &quot;upload123&quot;,
  &quot;originalName&quot;: &quot;photo.jpg&quot;,
  &quot;totalChunks&quot;: 3,
  &quot;receivedChunks&quot;: [0, 1],
  &quot;targetPath&quot;: &quot;/storage/uploads/photo.jpg&quot;,
  &quot;visibility&quot;: &quot;public&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the server starts, I call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;loadSessionsFromDisk();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It crawls the upload directory, finds metadata files, and reconstructs the &lt;code&gt;sessions&lt;/code&gt; map. Just like before, but now durable.&lt;/p&gt;
&lt;p&gt;This one change made everything more robust. Unexpected crash? No problem. The next chunk will pick up right where the last one left off.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Logging Progress&lt;/h3&gt;
&lt;p&gt;While I was at it, I added a tiny improvement: log progress.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;getProgress(sessionId); // → 66.6%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was especially helpful in tests (and will be even more useful in real UIs). It&apos;s based on the &lt;code&gt;receivedChunks.size / totalChunks&lt;/code&gt; ratio.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Testing the Whole Flow&lt;/h3&gt;
&lt;p&gt;I didn&apos;t want to trust myself to remember how this worked in 6 months. So I wrote unit tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Session creation&lt;/li&gt;
&lt;li&gt;✅ Chunk appending&lt;/li&gt;
&lt;li&gt;✅ Upload completion&lt;/li&gt;
&lt;li&gt;✅ Progress tracking&lt;/li&gt;
&lt;li&gt;✅ Session recovery after restart&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One test even manually simulates a restart:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Start session, write chunks
// Simulate restart: new ChunkManager()
// Call loadSessionsFromDisk()
// Finalize and assert output file exists
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;What I Learned&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;State is the hard part.&lt;/strong&gt; Writing files is easy. Remembering what&apos;s been written and why, is where the real design lives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests give you courage.&lt;/strong&gt; I could refactor, extend, and restart with confidence because tests had my back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resumability isn’t magic.&lt;/strong&gt; It’s just careful persistence, plus a willingness to think through failure modes.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3&gt;What’s Next?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt; Support for retrying failed chunks&lt;/li&gt;
&lt;li&gt; Expiring old sessions&lt;/li&gt;
&lt;li&gt; Moving files to cloud storage after finalization&lt;/li&gt;
&lt;li&gt; Exposing this to a real client or CLI&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;If you&apos;re building file upload systems in Node, I hope this helps you skip the mental potholes I hit. And if you&apos;re like me, building to understand, I hope this gave you a little more clarity than you had before.&lt;/p&gt;
&lt;p&gt;As always, I’m still learning. If you’ve built something like this before, I’d love to hear how you approached it.&lt;/p&gt;
</content:encoded><category>typescript</category><category>better-storage</category><author>deamking@icloud.com (Dream king)</author></item><item><title>When Values Are Sold for Dreams</title><link>https://world-rose.vercel.app/fragments/selling-children</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/selling-children</guid><description>On Worshipping the West and Losing Ourselves</description><pubDate>Sun, 04 May 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;I watched something today that I can’t unsee.&lt;/strong&gt; &lt;a href=&quot;https://www.youtube.com/shorts/aFdRyfFjCgk&quot;&gt;Link&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/shorts/OQ09GvOPdi8&quot;&gt;Similar Video&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A man asking for a daughter’s hand in marriage. An Ethiopian family. A Chinese groom. A bride far too young. The kind of young that makes you stop and ask: &lt;em&gt;how did we get here?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;They didn’t speak the same language. A translator stood between them like an uneasy bridge, and yet no one seemed to acknowledge the absurdity of it. Not once did someone ask the obvious question: &lt;em&gt;how do you build a life with someone when you can’t even understand each other’s words?&lt;/em&gt; Instead, the focus was on logistics. His salary, 92,000 a month. His marital status, divorced, with two daughters. Then the bidding began. And I don’t say that metaphorically. It was a negotiation cloaked in ceremony.&lt;/p&gt;
&lt;p&gt;I wish I could say it was an outlier. But this is becoming disturbingly common: daughters sent off to foreign men under the label of marriage and opportunity. It’s easy to call it cultural. It’s harder to call it what it really is: &lt;em&gt;transactional&lt;/em&gt;. Daughters traded for stability. Futures sold for the promise of prosperity. And in some cases, trafficked, under the illusion of consent.&lt;/p&gt;
&lt;p&gt;Some might argue the girl knew what she was doing. Maybe she even wanted it. Maybe she dreamed of a better life, of escape. But I doubt it. When you can’t speak the same language as your future husband, when you’re too young to understand what marriage even means, can we really call that a choice? And this is where the responsibility falls, on the parents, on the elders. These are people who understand what life outside your home, your language, your people really costs. They know what it means to raise children in a culture that may never fully accept them. Where the mother might never belong. Where she will have no voice and no one in her corner. They know all this, and still, they send her off.&lt;/p&gt;
&lt;p&gt;How do you justify shipping your daughter to a man you don’t know, in a country you don’t understand, where she won’t be able to speak for herself? How does that feel okay? More disturbingly, how are there still no policies, no protections, no systems in place to name this for what it is?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It’s human trafficking, dressed up as marriage.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And yet we rarely say those words out loud. Because to say them would mean asking harder questions. About who benefits. About why entire communities stand by as this happens in broad daylight. About the quiet complicity of those who should know better. About the shame we hide behind tradition. And maybe the hardest truth: we’ve normalized it. We’ve let it blend into the background noise of poverty and ambition. So much so that when someone calls it trafficking, people flinch, not because it’s wrong, but because they know it’s true. We tell ourselves it’s about opportunity. About love. About progress. But what I saw wasn’t love. It wasn’t opportunity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It was a negotiation.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A family selling their daughter for a chance at a life they’ll never live themselves. And I’m not blaming the girl, she’s too young to know what’s being taken from her. What disappoints me most is the elders. The ones who should’ve known better. The ones who chose silence.&lt;/p&gt;
&lt;h3&gt;The Dangerous Fantasy of Western Worship&lt;/h3&gt;
&lt;p&gt;There’s a sickness in our culture, and I don’t say that lightly. We’ve wrapped the Western world, and anything foreign, really, in this glossy fantasy. As if proximity to whiteness or wealth is salvation.&lt;/p&gt;
&lt;p&gt;We’ve confused escape with empowerment. Let me be clear: I’m not against intercultural love. Real love crosses borders, learns languages, builds bridges. But that’s not what this was. This was grooming, facilitated by family, celebrated by community, and ignored by the state.&lt;/p&gt;
&lt;h3&gt;Poverty Is Not a Permission Slip&lt;/h3&gt;
&lt;p&gt;Yes, we live in poverty. Yes, we are struggling. But poverty doesn’t excuse the erosion of values. It doesn’t make it acceptable to sell your child, literally or metaphorically, for the illusion of escape. Values are what shape societies. And when the elders, the supposed guardians of those values, begin to trade them for short-term gain, what hope do we have?&lt;/p&gt;
&lt;p&gt;What scares me most is that society didn’t condemn what happened in that video. It &lt;em&gt;celebrated&lt;/em&gt; it. Comment after comment praising the union, the “luck,” the opportunity. Not one person seemed to ask: how can a marriage work without communication? What does it say about us that this kind of transaction is even possible?&lt;/p&gt;
&lt;h3&gt;A Broken Mirror&lt;/h3&gt;
&lt;p&gt;When a society rewards the sacrifice of its own daughters, we are no longer talking about isolated incidents. We are staring into the face of systemic failure.&lt;/p&gt;
&lt;p&gt;Governments love to talk about economic growth. But what about moral collapse? What happens when a generation grows up believing their worth is measured in dollars and passports? What does that do to their identity? Their sense of possibility?&lt;/p&gt;
&lt;p&gt;We’ve replaced values with fantasies. We’ve confused imitation with aspiration. We think the only way forward is out.&lt;/p&gt;
&lt;p&gt;But a culture that abandons its foundation can only fall.&lt;/p&gt;
&lt;h3&gt;Rebuild From Within&lt;/h3&gt;
&lt;p&gt;Here’s what I’m still wrestling with: &lt;em&gt;how do we begin to rebuild?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We can’t undo that girl’s story. But maybe we can learn from it. Maybe we can start asking better questions.&lt;/p&gt;
&lt;p&gt;Not “how do we escape poverty?”
But “how do we rise with dignity?”&lt;/p&gt;
&lt;p&gt;Not “how do we get out?”
But “what can we build right here?”&lt;/p&gt;
&lt;p&gt;If this post feels angry, it’s because it is. If it feels unfinished, that’s because it is. I don’t have neat answers.&lt;/p&gt;
&lt;p&gt;But I do know this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We cannot afford to sell our future for the illusion of someone else’s dream.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Especially not when the price is our values.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Would you like to publish this as a standalone post or part of a series exploring culture, values, and development?&lt;/p&gt;
</content:encoded><category>awareness</category><category>reaction</category><author>deamking@icloud.com (Dream king)</author></item><item><title>The Strength to Not Take Sides</title><link>https://world-rose.vercel.app/fragments/integrity</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/integrity</guid><description>Most people think strength is about standing your ground. But what if real strength is refusing to take a side even when it’s your own?</description><pubDate>Sun, 13 Apr 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Sometimes, Sticking to What&apos;s Right Means Not Taking Sides&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Living in Addis, you know how tough dealing with landlords can be. It often feels unfair, and arguments happen. Today, I saw one get pretty heated in my neighborhood.&lt;/p&gt;
&lt;p&gt;A landlord was fighting with his tenant over a small thing – a broken socket worth maybe 200 birr. But it was clear the anger was about more than that. They both started shouting insults. It was ugly, but the kind of thing you unfortunately see sometimes.&lt;/p&gt;
&lt;p&gt;Here’s what got me thinking: The tenant&apos;s wife was there. She&apos;d been quiet while the landlord insulted them. But when her &lt;em&gt;own husband&lt;/em&gt; started firing back with nasty insults, she told him repeatedly, &quot;Stop. Stop insulting him.&quot; He was too angry to listen.&lt;/p&gt;
&lt;p&gt;So, she picked up a stick and actually hit her husband – hard, broke the stick, enough to get his attention and make him stop the insults.&lt;/p&gt;
&lt;p&gt;Honestly, I was surprised. My first thought was, &quot;Shouldn&apos;t she be on his side?&quot; Usually, you back up your family, right? Especially when they&apos;re fighting someone else.&lt;/p&gt;
&lt;p&gt;But she didn&apos;t. It wasn&apos;t that she agreed with the landlord. It seemed like she just believed that insulting people was wrong, period. Even if &lt;em&gt;her&lt;/em&gt; husband was doing it. Even if he was angry for a good reason. She wanted them to leave with respect, not by sinking to the same level of insults.&lt;/p&gt;
&lt;p&gt;I understood why the husband was mad. He felt disrespected just for being a tenant. His anger made sense.&lt;/p&gt;
&lt;p&gt;But his wife showed a different kind of strength. It wasn&apos;t about fighting back louder. It was about sticking to her own rule: &lt;em&gt;We don&apos;t act ugly, even when we&apos;re treated badly.&lt;/em&gt; That takes real discipline, especially when it means going against your own loved one in the heat of the moment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I Took Away:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It made me think. Maybe being strong isn&apos;t always about blindly supporting &quot;your side.&quot; Sometimes, real strength is sticking to what you believe is right, even if it&apos;s uncomfortable or means telling your own people they&apos;re wrong. It&apos;s easy to just jump in and fight with your group. It’s much harder to hold onto your own principles.&lt;/p&gt;
&lt;p&gt;Seeing that wife choose her principle (no insults) over just backing up her husband really stuck with me. It showed a quiet, powerful kind of strength. It&apos;s definitely something worth thinking about.&lt;/p&gt;
</content:encoded><category>typescript</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Thinking About File Storage</title><link>https://world-rose.vercel.app/fragments/saving_files</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/saving_files</guid><description>Notes on Rebuilding Laravel’s Storage System in TypeScript (Week 2). The way you present content changes the way it’s perceived.</description><pubDate>Sat, 12 Apr 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;There’s a funny thing that happens when you try to rebuild a system you thought you understood.&lt;/p&gt;
&lt;p&gt;You start with confidence, convinced you’re just a few lines of code away from &quot;solving&quot; the problem. Then, somewhere along the way, the code teaches you that the problem was never what you thought it was.&lt;/p&gt;
&lt;p&gt;That’s exactly what happened to me this week.&lt;/p&gt;
&lt;p&gt;I set out to build a clean, Laravel-inspired file storage system in TypeScript. The kind of thing you’d package, publish, and forget about. But somewhere between implementing visibility handling, path generators, and file streams, the work stopped being about &quot;files&quot;, and started being about &lt;strong&gt;designing for reality&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🪵 The Illusion of Just &quot;Saving Files&quot;&lt;/h2&gt;
&lt;p&gt;When I first wrote:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fs.writeFileSync(path, contents);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I felt like the job was done. Simple, right? Write the file, return the path. On to the next feature.&lt;/p&gt;
&lt;p&gt;Except real systems don’t work that way.&lt;/p&gt;
&lt;p&gt;In the real world, &quot;saving a file&quot; has baggage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Where does it live? (Path logic.)&lt;/li&gt;
&lt;li&gt;Who can access it? (Visibility rules.)&lt;/li&gt;
&lt;li&gt;What happens when storage moves to S3? (Abstraction.)&lt;/li&gt;
&lt;li&gt;What happens when the upload is slow, or interrupted? (Resilience.)&lt;/li&gt;
&lt;li&gt;How do you test it all without hardcoding assumptions? (Flexibility.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Laravel doesn’t hide these problems. It just makes them composable. That’s the genius. And that’s the part I’ve been chasing in this rewrite.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🗂 Paths Are Strategies, Not Strings&lt;/h2&gt;
&lt;p&gt;One of the first design dead ends I hit was &lt;strong&gt;hardcoded file paths&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You upload an avatar? You might write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const path = `users/${userId}/avatar.png`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this kind of logic spreads like weeds. Before long, it’s tangled across your codebase. Worse, it ties your logic to a single assumption: that file paths are static.&lt;/p&gt;
&lt;p&gt;Laravel’s model taught me something smarter: treat paths as a &lt;strong&gt;strategy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So I wrote:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface PathGenerator {
  generatePath(originalName: string): string;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And suddenly, my logic stopped caring about hardcoded assumptions.&lt;/p&gt;
&lt;p&gt;Now I could swap strategies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DatePathGenerator&lt;/code&gt;: store files by upload date.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserPathGenerator&lt;/code&gt;: store files under user directories.&lt;/li&gt;
&lt;li&gt;Future-proof: write a &lt;code&gt;SlugPathGenerator&lt;/code&gt;, a &lt;code&gt;UUIDPathGenerator&lt;/code&gt;, whatever.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The shift is small on the surface. But underneath, it turns your storage system into something that can adapt as requirements evolve, without rewriting business logic.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔐 Visibility Isn’t a Folder Name, It’s a Policy&lt;/h2&gt;
&lt;p&gt;The next trap I walked into was treating &lt;code&gt;public&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; as if they were just folders.&lt;/p&gt;
&lt;p&gt;But that’s not how Laravel thinks about it.&lt;/p&gt;
&lt;p&gt;When you save a file in Laravel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Storage::put(&apos;photos/cat.png&apos;, $contents, &apos;public&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you’re not just writing to a path. You’re setting an intent: this file can be shared. The implementation decides &lt;em&gt;how&lt;/em&gt; that’s enforced, locally it might be folder-based, on S3 it might be ACLs.&lt;/p&gt;
&lt;p&gt;So in my system, I updated my path resolver to reflect that intent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const targetVisibility = visibility ?? this.defaultVisibility;
return path.join(this.root, targetVisibility, filePath);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now visibility isn’t an afterthought. It’s baked into the path, enforced by design.&lt;/p&gt;
&lt;p&gt;That might seem small. But small design decisions like this prevent big security mistakes later.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🌊 Streams: Where Happy Path Code Goes to Die&lt;/h2&gt;
&lt;p&gt;And then came the humbling part: testing file streams.&lt;/p&gt;
&lt;p&gt;It’s easy to write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await storage.writeStream(&apos;file.txt&apos;, readableStream);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and call it a day. But streams don’t always behave. If you don’t handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;slow streams,&lt;/li&gt;
&lt;li&gt;interrupted streams,&lt;/li&gt;
&lt;li&gt;unclosed streams,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;your tests will hang. Your production code will too.&lt;/p&gt;
&lt;p&gt;I wrote tests that simulated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;normal uploads,&lt;/li&gt;
&lt;li&gt;network-like latency,&lt;/li&gt;
&lt;li&gt;interrupted connections.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And every time the test failed, the design got better. I added proper &lt;code&gt;end&lt;/code&gt; and &lt;code&gt;destroy&lt;/code&gt; calls. I added error listeners. I added timeouts.&lt;/p&gt;
&lt;p&gt;You don’t really &quot;get&quot; streams until you see one hang your test suite at 2AM.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;💡 The Shift: Laravel’s Storage Model Is a Way of Thinking&lt;/h2&gt;
&lt;p&gt;When I started this project, I thought I was building a file storage system.&lt;br /&gt;What I’ve realized is: I’m actually building a mental model.&lt;/p&gt;
&lt;p&gt;Laravel’s storage isn’t just about reading and writing files, it’s about designing for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;change,&lt;/li&gt;
&lt;li&gt;failure,&lt;/li&gt;
&lt;li&gt;policy,&lt;/li&gt;
&lt;li&gt;and most of all: clarity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Week 2 wasn’t about finishing features. It was about learning to ask better questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What does the code assume?&lt;/li&gt;
&lt;li&gt;What happens when those assumptions break?&lt;/li&gt;
&lt;li&gt;How can design prevent human error, not just handle it?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The code will change. The model will stay.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔥 What’s Next&lt;/h2&gt;
&lt;p&gt;This week was all about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Path strategies.&lt;/li&gt;
&lt;li&gt;Visibility policies.&lt;/li&gt;
&lt;li&gt;Testing for real-world file behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next week?&lt;br /&gt;We’ll dig into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Signed URLs.&lt;/li&gt;
&lt;li&gt;Slow and interrupted uploads.&lt;/li&gt;
&lt;li&gt;Custom path generators.&lt;/li&gt;
&lt;li&gt;Edge cases that I nearly skipped, but I’m glad I didn’t.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the more I work on this, the more I realize:&lt;br /&gt;It was never about the files.&lt;/p&gt;
&lt;p&gt;It was always about designing for the real world.&lt;/p&gt;
</content:encoded><category>typescript</category><category>better-storage</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Transform your Articles</title><link>https://world-rose.vercel.app/fragments/yhblogs</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/yhblogs</guid><description>Interfaces are not neutral. The way you present content changes the way it’s perceived.</description><pubDate>Thu, 10 Apr 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;For a while, reading blog posts on the YeneHealth app felt like squinting through fog.  &lt;/p&gt;
&lt;p&gt;Text was jammed up against the screen edges. Fonts were tiny and inconsistent. Paragraphs melted together without spacing, hierarchy, or structure. It felt like someone had dumped raw HTML into the app and called it a day.&lt;/p&gt;
&lt;p&gt;And that’s exactly what happened.&lt;/p&gt;
&lt;p&gt;The app’s mobile blog reader used the &lt;a href=&quot;https://pub.dev/packages/flutter_html&quot;&gt;&lt;code&gt;flutter_html&lt;/code&gt;&lt;/a&gt; package to render HTML content, but we never styled it. No typographic rhythm, no responsive spacing, no attention to how it &lt;em&gt;felt&lt;/em&gt; to actually read. The content was there, sure. But it looked like it didn’t want to be read.&lt;/p&gt;
&lt;p&gt;The Web had horrible styles. Telegram had web styles and mobile just got left behind.&lt;/p&gt;
&lt;p&gt;HTML by itself doesn’t care about how it looks. That’s CSS’s job. And in the browser, that’s easy: you set a &lt;code&gt;style&lt;/code&gt; tag or load a stylesheet, and you’re off to the races.&lt;/p&gt;
&lt;p&gt;But in Flutter? Rendering HTML is just a starting point. The &lt;code&gt;flutter_html&lt;/code&gt; package maps HTML elements to Flutter widgets, and &lt;strong&gt;if you don’t tell it how things should look&lt;/strong&gt;, it just… doesn’t.&lt;/p&gt;
&lt;p&gt;So when we pulled blog content from our CMS and rendered it using &lt;code&gt;flutter_html&lt;/code&gt;, we ended up with this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags with no margin.&lt;/li&gt;
&lt;li&gt;Lists (&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;) with weird indentation and default bullets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; elements that looked like normal text.&lt;/li&gt;
&lt;li&gt;Zero spacing between headers and paragraphs.&lt;/li&gt;
&lt;li&gt;No readable font, no consistent font sizes, no zoom.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was readable the way a wall of raw Markdown is readable, technically possible, but practically painful.&lt;/p&gt;
&lt;h3&gt;Rebuilding the Reading Experience&lt;/h3&gt;
&lt;p&gt;I didn’t want to rebuild a full HTML layout engine. I just wanted to give the content room to breathe. So I started with the web styles that had been working well:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; body {
  font-family: Georgia, serif;
  font-size: 1.1rem;
  line-height: 1.8;
  color: #333;
  background: #fff;
  padding: 2rem 1rem;
}

 p {
  margin: 1em 0;
  line-height: 1.5;
  font-size: 1.1rem;
  margin-bottom: 1.5rem;
}

 h1, h2, h3, h4 {
  font-size: x-large;
  margin: 2.5rem 0 1.5rem 0;
  line-height: 1.25;
  color: #333;
}

 ul {
  list-style-type: circle;
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}

 li {
  font-size: 1.1rem;
  margin-left: 2em;
  margin-bottom: 0.5em;
}

 blockquote {
  font-style: italic;
  border-left: 4px solid #ccc;
  padding-left: 1rem;
  margin: 1.5rem 0;
  background: #f9f9f9;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I translated those into Flutter styles using the &lt;code&gt;flutter_html&lt;/code&gt; styling system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Html(
  data: htmlContent,
  style: {
    &quot;body&quot;: Style(
      fontFamily: &apos;Georgia&apos;,
      fontSize: FontSize(18.0),
      lineHeight: LineHeight.number(1.8),
      padding: HtmlPaddings.symmetric(horizontal: 16.0),
      backgroundColor: Colors.white,
      color: Colors.black87,
    ),
    &quot;p&quot;: Style(
      fontSize: FontSize(16.0),
      margin: Margins.only(bottom: 20),
      lineHeight: LineHeight.number(1.6),
    ),
    &quot;ul&quot;: Style(
      listStyleType: ListStyleType.DISC,
      margin: Margins.symmetric(vertical: 16),
      padding: HtmlPaddings.zero,
    ),
    &quot;li&quot;: Style(
      fontSize: FontSize(16.0),
      margin: Margins.only(bottom: 8, left: 24),
    ),
    &quot;blockquote&quot;: Style(
      fontStyle: FontStyle.italic,
      padding: HtmlPaddings.only(left: 16),
      border: Border(left: BorderSide(color: Colors.orange, width: 4)),
      backgroundColor: Color(0xfff9f9f9),
      margin: Margins.symmetric(vertical: 24),
    ),
    &quot;h1&quot;: Style.fromTextStyle(headerStyle),
    &quot;h2&quot;: Style.fromTextStyle(headerStyle),
    &quot;h3&quot;: Style.fromTextStyle(headerStyle),
    &quot;strong&quot;: Style(
      fontWeight: FontWeight.bold,
      color: Colors.black87,
    ),
    // Add more tag styles as needed
  },
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each element got just enough care to read clearly. Paragraphs had room. Lists were indented and styled. Quotes were visually distinct. And above all: &lt;strong&gt;it looked intentional.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not flashy. Just thoughtful.&lt;/p&gt;
&lt;h3&gt;Why It Matters&lt;/h3&gt;
&lt;p&gt;In the end, this wasn’t about style, it was about respect.  &lt;/p&gt;
&lt;p&gt;Respect for the reader’s attention.&lt;br /&gt;Respect for the writer’s voice.&lt;br /&gt;Respect for the medium.&lt;/p&gt;
&lt;p&gt;What frustrated me most about the original mobile blog experience wasn’t just that it was unreadable. It’s that it &lt;em&gt;had&lt;/em&gt; been left that way. It didn’t feel like anyone cared enough to ask: &lt;em&gt;is this comfortable to read?&lt;/em&gt; And when something is hard to read, it might as well not exist.&lt;/p&gt;
&lt;p&gt;All that effort from our content team? Ghosted by a UI that didn’t care to carry it well. This wasn’t just a design oversight. It was a failure of storytelling. And that’s what finally pushed me to fix it not because I had the time, but because I was tired of watching good writing go unseen.&lt;/p&gt;
&lt;p&gt;So I made the effort to bring typographic care to Flutter and React. I recreated line heights. I tuned font sizes. I gave margins the room they deserved. I stopped treating HTML as data and started treating it as &lt;em&gt;literature&lt;/em&gt;. It still isn’t perfect. I’m still tweaking line spacing and wondering if &lt;code&gt;1.5&lt;/code&gt; is too loose or just right. But that’s the work. You keep adjusting the margins until the story breathes again.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Deeper Lesson&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interfaces are not neutral.&lt;/strong&gt;&lt;br /&gt;The way you present content &lt;em&gt;changes&lt;/em&gt; the way it’s perceived.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This wasn’t just about making it “pretty.” It was about making it &lt;em&gt;possible to engage&lt;/em&gt;. Because no matter how good your ideas are, if your reader has to pinch, squint, and scroll sideways to reach them… they won’t.&lt;/p&gt;
&lt;p&gt;And honestly? Neither would I.&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><category>yenehealth</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Local File Storage with TypeScript</title><link>https://world-rose.vercel.app/fragments/storage</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/storage</guid><description>Building a Laravel inspired Local File Driver in TypeScript with Metadata, Testing, and Error Handling</description><pubDate>Tue, 08 Apr 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;There’s this silent moment that always comes when you’re abstracting infrastructure, storage, queues, databases. It’s the moment right after you get the first thing working, and you ask yourself: &lt;em&gt;What’s this really going to grow into?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That moment hit me like a freight train after I wrote the first few lines of my TypeScript version of Laravel’s file storage system. I had the interface, a &lt;code&gt;LocalStorageDriver&lt;/code&gt;, and a &lt;code&gt;Storage&lt;/code&gt; registry in place. You could &lt;code&gt;.put()&lt;/code&gt; and &lt;code&gt;.get()&lt;/code&gt; files. It worked. But I realized I wasn’t building this for now, I was building it for the next hundred features. And that meant it couldn’t just work; it had to be built to &lt;strong&gt;grow&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And that’s where metadata, testing, and error handling came in.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Why Metadata Isn’t Optional&lt;/h3&gt;
&lt;p&gt;The past version of me didn’t think about file metadata. If a file was there and I could read it, that was good enough. But that version of me had never tried to build a media library, generate signed URLs, or organize files by type.&lt;/p&gt;
&lt;p&gt;Metadata isn’t just nice-to-have, it’s the &lt;strong&gt;foundation&lt;/strong&gt; of a real file management system. You need to know what a file is, not just whether it exists.&lt;/p&gt;
&lt;p&gt;So I designed a shape:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface FileMetadata {
  path: string;
  size: number;
  mimeType: string;
  visibility: &apos;public&apos; | &apos;private&apos;;
  lastModified: Date;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This became the backbone of how I understood files. And it forced my local driver to become smarter. I pulled in &lt;code&gt;fs-extra&lt;/code&gt; for filesystem access, and &lt;code&gt;mime-types&lt;/code&gt; to infer MIME type based on file extension. Then I wrote a &lt;code&gt;getMetadata()&lt;/code&gt; method that pulled it all together.&lt;/p&gt;
&lt;p&gt;What changed for me here was realizing that this structure wasn’t just a utility. It was a &lt;strong&gt;contract&lt;/strong&gt;, one that all future drivers (S3, GCS, Azure) would have to honor.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Testing Like the System Depends on It (Because It Does)&lt;/h3&gt;
&lt;p&gt;Here’s the truth: I don’t write tests because I love writing tests. I write tests because Future Me is a chaotic gremlin who will absolutely break things.&lt;/p&gt;
&lt;p&gt;So I wrote a suite of integration tests for the local driver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can it write and read files?&lt;/li&gt;
&lt;li&gt;Does it report the right metadata?&lt;/li&gt;
&lt;li&gt;Does &lt;code&gt;exists()&lt;/code&gt; behave sensibly?&lt;/li&gt;
&lt;li&gt;What happens when the file doesn’t exist?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used Vitest, but any modern framework will do. What mattered wasn’t the tool, it was the intention:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If this was the only thing I could read about the system in 6 months, would I understand how it’s supposed to behave?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s my bar now.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Error Handling That Isn’t an Afterthought&lt;/h3&gt;
&lt;p&gt;The filesystem is a messy place. Files vanish. Paths are wrong. Disks fill up. If you pretend that won’t happen, your app will crash the first time reality says otherwise.&lt;/p&gt;
&lt;p&gt;So I wrapped my reads in &lt;code&gt;try/catch&lt;/code&gt;, and made sure errors came with meaningful messages:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  const data = await fs.readFile(fullPath);
} catch (err: any) {
  if (err.code === &apos;ENOENT&apos;) {
    throw new Error(`File not found: ${path}`);
  }
  throw err;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No vague &quot;Something went wrong.&quot; Give me &lt;strong&gt;context&lt;/strong&gt;. And while we’re at it, I added optional logging, so I could debug without digging into stack traces.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Takeaway: Make the Boring Parts Boring&lt;/h3&gt;
&lt;p&gt;I don’t want file storage to be exciting. If I’m thinking about it, something probably went wrong. So my goal is to make this whole system &lt;strong&gt;predictable&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Metadata lets me make smart decisions about files&lt;/li&gt;
&lt;li&gt;Testing protects me from my own future recklessness&lt;/li&gt;
&lt;li&gt;Error handling ensures I hear the crash before it becomes a crater&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you’re building abstractions, the goal isn’t cleverness. It’s trust. I want to trust that &lt;code&gt;.put()&lt;/code&gt; will work the same on local or S3. I want to trust that &lt;code&gt;getMetadata()&lt;/code&gt; gives me the same shape every time.&lt;/p&gt;
&lt;p&gt;That trust starts with being just a little obsessive right now.&lt;/p&gt;
&lt;p&gt;If you&apos;re building something similar, my advice is: don’t skip this step. Make the boring parts boring. You’ll thank yourself later.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next up? Cloud drivers. Let’s make this thing fly.&lt;/p&gt;
</content:encoded><category>project</category><category>better-storage</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Respect for Teachers</title><link>https://world-rose.vercel.app/fragments/teachers</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/teachers</guid><description>A world without teachers is a world without wisdom. Will we cherish those who shape minds, or will we let an entire generation forget the value of learning beyond information?</description><pubDate>Sun, 30 Mar 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;Today, as I scrolled through LinkedIn, I came across a &lt;a href=&quot;https://www.linkedin.com/posts/dereje-moges-tadesse-aa479036_behindthesceneshero-powercouple-teacherlife-ugcPost-7312020451780665345-zGk6?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAADyjXZIBKygIkaPqOuUowWeXGI5hveFuN5E&quot;&gt;video&lt;/a&gt; that truly moved me. A teacher was sharing a heartfelt tribute to his hero,his wife. In the video, she stood holding their child in one arm while skillfully managing a video camera with the other, capturing her husband&apos;s online course lectures. It was a beautiful, selfless act, a reminder of the silent sacrifices made behind the scenes. His public acknowledgment of her support was touching, and it made me think about the dedication of teachers in general, especially in the digital age.&lt;/p&gt;
&lt;p&gt;The way education is evolving, with teachers adapting to online courses and new modes of learning, is commendable. More than ever, they are required to be content creators, communicators, and mentors in ways previous generations never imagined. This shift should be encouraged and supported. But as I reflected on the honor this teacher gave to his wife, I was struck by another post,a stark contrast to this moment of gratitude and respect.&lt;/p&gt;
&lt;p&gt;A student had openly insulted his teacher, boasting that he could get the entire course material from an AI model. What troubled me even more was not just the comment itself, but the overwhelming agreement from others in the replies. The casual dismissal of teachers, the idea that they are obsolete in a world of abundant information, was both disturbing and disappointing.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Respect is Not Optional&lt;/h3&gt;
&lt;p&gt;There was a time when respect for teachers was a given. You could disagree with their methods, you could challenge their perspectives, but the fundamental principle remained,teachers deserved respect. Not because they were flawless, but because they carried the responsibility of shaping generations. Respecting elders, mentors, and those who dedicate their lives to education is not something they should have to earn. It is a principle.&lt;/p&gt;
&lt;p&gt;In many countries, including mine, teachers are not paid well. The profession is not seen as a lucrative or prestigious career path, and that reality deters many brilliant minds from pursuing it. Teaching, once considered one of the most honorable professions, is now often met with indifference or even disdain. If only we treated teachers as champions,if only we recognized their immense contributions and rewarded them accordingly,we could cultivate a generation rooted in strength, wisdom, and wealth, not just in material terms but in intellectual and moral prosperity.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Lessons That Stay With Us&lt;/h3&gt;
&lt;p&gt;Thinking back to my own years as a student, I don’t just remember classroom discussions or lecture notes. I remember the teachers who stood out, the ones who disciplined me, the ones who praised me, the ones who argued with me, and the ones who encouraged me. The ones who challenged my thinking and, in doing so, shaped who I am today.&lt;/p&gt;
&lt;p&gt;A teacher may believe their primary role is to deliver subject material, but their impact goes far beyond that. As students, we absorb everything, from the way they speak to how they carry themselves. A single word from a teacher can stay with a student for life. A moment of kindness, a lesson in patience, a display of ambition, or even a firm reprimand,all of these contribute to shaping identities. True teachers don’t just deliver content; they ignite curiosity, challenge assumptions, and inspire growth. They don’t dictate destinies, but they open doors to possibilities.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;A Generation at Risk&lt;/h3&gt;
&lt;p&gt;What happens when an entire generation grows up without these lessons? When they fail to understand the value of history, culture, and principles? When learning becomes transactional rather than transformational? When experience is dismissed as irrelevant in the face of instant information?&lt;/p&gt;
&lt;p&gt;The thought is unsettling. Knowledge without wisdom is dangerous. A world that does not value teachers is a world that does not value learning in its truest sense.&lt;/p&gt;
&lt;p&gt;Technology is an incredible tool, but it cannot replace mentorship. AI can provide answers, but it cannot challenge perspectives. The future must not be one where we trade the depth of human teaching for the convenience of machine-generated knowledge.&lt;/p&gt;
&lt;p&gt;Teachers matter. Their work matters. And our respect for them should not waver, no matter how much the world changes.&lt;/p&gt;
</content:encoded><category>inspire&quot;</category><author>deamking@icloud.com (Dream king)</author><source url="https://www.linkedin.com/posts/dereje-moges-tadesse-aa479036_behindthesceneshero-powercouple-teacherlife-ugcPost-7312020451780665345-zGk6?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAADyjXZIBKygIkaPqOuUowWeXGI5hveFuN5E">Dereje Moges Tadesse</source></item><item><title>The Hidden Cost of Speedy Fixes</title><link>https://world-rose.vercel.app/fragments/quick-fix</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/quick-fix</guid><description>I thought I was solving problems quickly, until my boss pointed out I was creating more of them.</description><pubDate>Tue, 18 Mar 2025 07:51:04 GMT</pubDate><content:encoded>&lt;figure&gt;
    
    &lt;figcaption&gt;Rabbit hole of problems&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;For a long time, I took pride in solving problems fast. A bug popped up? Fixed in minutes. A deployment issue? Quick patch. A failing test? Just tweak the conditions. It felt good to move quickly, to be the person who could handle things under pressure. But then my boss pointed something out:&lt;/p&gt;
&lt;p&gt;&quot;You&apos;re solving the same problems over and over. Why do they keep coming back?&quot;&lt;/p&gt;
&lt;p&gt;I hadn’t noticed it before, but he was right. The fixes weren’t really fixes, they were patches. I was treating symptoms, not causes. And worse, I was making future work harder for myself and my team. That’s when I started looking into why quick fixes are so tempting and so dangerous.&lt;/p&gt;
&lt;br /&gt;

&lt;h2&gt;The Quick Fix Mindset: Why We Do It&lt;/h2&gt;
&lt;p&gt;This mindset, prioritizing immediate solutions over sustainable ones, doesn’t come from laziness. It’s usually the result of external pressures and ingrained habits. Here are some key factors that drive it:&lt;/p&gt;
&lt;h2&gt;1. Pressure to Deliver Fast&lt;/h2&gt;
&lt;p&gt;Deadlines are tight, production issues need immediate attention, and there&apos;s an unspoken expectation that developers should always be shipping. Under this pressure, investing time in a well-thought-out solution feels like a luxury.&lt;/p&gt;
&lt;h2&gt;2. Technical Debt Becomes Normalized&lt;/h2&gt;
&lt;p&gt;When teams regularly push out quick fixes, technical debt piles up. But because it accumulates slowly, it becomes the default way of working. It’s like living with a messy desk, you stop noticing how much it slows you down.&lt;/p&gt;
&lt;h2&gt;3. Lack of Long-Term Thinking&lt;/h2&gt;
&lt;p&gt;If the goal is just to make it through the next sprint or the next release, long-term sustainability gets ignored. The future-you (or worse, your teammates) will have to deal with the consequences.&lt;/p&gt;
&lt;h2&gt;4. Resource Constraints&lt;/h2&gt;
&lt;p&gt;Not enough time, not enough people, not enough budget, these constraints force teams to take the easiest route to getting things done. But quick fixes often cost more in the long run.&lt;/p&gt;
&lt;h2&gt;5. Reinforcement of Bad Habits&lt;/h2&gt;
&lt;p&gt;If quick fixes are rewarded, if they lead to praise, promotions, or just surviving another deadline, developers keep using them. But success in firefighting doesn’t mean the fire isn’t still spreading.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Hidden Costs of Quick Fixes&lt;/h2&gt;
&lt;p&gt;While quick fixes might feel like wins in the moment, they come with serious downsides:&lt;/p&gt;
&lt;h2&gt;1. Accumulating Technical Debt&lt;/h2&gt;
&lt;p&gt;Shortcuts add up. That function you copied and pasted instead of refactoring? Now there are five versions of it across the codebase. That hardcoded config? It’s breaking in production because no one knew to change it. Every quick fix compounds the complexity of future work.&lt;/p&gt;
&lt;h2&gt;2. Decreased Product Quality&lt;/h2&gt;
&lt;p&gt;Patching instead of solving leads to fragile systems. One fix breaks another part of the app. Edge cases go unhandled. The user experience degrades. Eventually, the product becomes unreliable, slow, and frustrating.&lt;/p&gt;
&lt;h2&gt;3. Developer Burnout&lt;/h2&gt;
&lt;p&gt;Constantly fixing the same types of issues is exhausting. Developers feel like they’re always putting out fires instead of building something meaningful. This can lead to frustration, disengagement, and ultimately burnout.&lt;/p&gt;
&lt;h2&gt;4. Missed Opportunities for Real Innovation&lt;/h2&gt;
&lt;p&gt;If all the energy goes into maintaining a broken system, there’s little time left for improving it. The team stays stuck in a cycle of reactivity rather than proactively creating better solutions.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Breaking the Cycle: Moving Beyond Quick Fixes&lt;/h2&gt;
&lt;p&gt;Shifting away from a quick-fix mindset takes effort, but it’s worth it. Here are some strategies that have helped me (and my team) focus on long-term sustainability:&lt;/p&gt;
&lt;h2&gt;1. Slow Down to Speed Up&lt;/h2&gt;
&lt;p&gt;It feels counterintuitive, but taking the time to do things right the first time saves more time later. Instead of immediately jumping to a quick fix, step back and ask: &lt;em&gt;What’s actually causing this issue?&lt;/em&gt;  &lt;/p&gt;
&lt;h2&gt;2. Refactor Regularly&lt;/h2&gt;
&lt;p&gt;Schedule time for refactoring and technical debt cleanup. It’s like servicing a car, skip it too long, and things start breaking down.&lt;/p&gt;
&lt;h2&gt;3. Make Technical Debt Visible&lt;/h2&gt;
&lt;p&gt;Keep track of where debt is accumulating. Add tickets for refactoring. Document workarounds so they don’t become permanent hacks.&lt;/p&gt;
&lt;h2&gt;4. Push for Sustainable Practices&lt;/h2&gt;
&lt;p&gt;Advocate for better testing, code reviews, and automation. Make the case to stakeholders that solid engineering saves money and time in the long run.&lt;/p&gt;
&lt;h2&gt;5. Shift the Culture&lt;/h2&gt;
&lt;p&gt;Encourage a team mindset where quality is valued over speed. Recognize and reward well-thought-out solutions, not just quick turnarounds.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Takeaway&lt;/h2&gt;
&lt;p&gt;Quick fixes can feel like victories, but they often create more problems than they solve. I learned this the hard way, by repeating the same fixes over and over until someone pointed it out. The shift away from patching toward sustainable problem-solving isn’t easy, but it makes for a stronger team, a healthier codebase, and a better product.&lt;/p&gt;
&lt;p&gt;Next time you’re about to reach for the fastest fix, ask yourself: &lt;em&gt;Is this really solving the problem? Or just delaying it?&lt;/em&gt; The answer might change the way you code.&lt;/p&gt;
</content:encoded><category>lessons</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Our Voices, Our Stories, Our Future</title><link>https://world-rose.vercel.app/fragments/podcasts</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/podcasts</guid><description>Explore the impact of audio storytelling and check out must-listen Ethiopian podcasts that inspire, educate, and connect us all. From tech discussions to cultural storytelling, podcasts are empowering the next generation of Ethiopian creators, entrepreneurs, and change-makers.</description><pubDate>Sun, 16 Mar 2025 14:01:28 GMT</pubDate><content:encoded>&lt;figure&gt;
    
    &lt;figcaption&gt;Our Voices, Our Stories, Our Future&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Growing up, technology wasn’t just about gadgets for me, it was about &lt;strong&gt;curiosity&lt;/strong&gt; and &lt;strong&gt;inspiration&lt;/strong&gt;. Even with limited access to cutting-edge tech in Ethiopia, I was fascinated by how the world was changing. But more than what I saw, it was what I heard that shaped my perspective.&lt;/p&gt;
&lt;p&gt;Two shows, &lt;em&gt;Tech and Tunes Radio Show&lt;/em&gt; and &lt;em&gt;TechTalk with Solomon&lt;/em&gt;, were more than just programs. They made complex topics feel personal, relevant, and exciting. They didn’t just report on technology; they sparked &lt;strong&gt;ambition&lt;/strong&gt; and built a &lt;strong&gt;community&lt;/strong&gt; of tech enthusiasts.&lt;/p&gt;
&lt;p&gt;Looking back, I see how these shows laid the foundation for a generation of innovators. Many of Ethiopia’s young developers, engineers, and entrepreneurs found inspiration through voices like these, voices that told our &lt;strong&gt;stories&lt;/strong&gt;, shared our &lt;strong&gt;challenges&lt;/strong&gt;, and celebrated our &lt;strong&gt;progress&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now, podcasts are carrying that legacy forward, giving this generation a platform to &lt;strong&gt;connect&lt;/strong&gt;, &lt;strong&gt;learn&lt;/strong&gt;, and &lt;strong&gt;create&lt;/strong&gt; the future. Just as those early shows shaped my dreams in technology, today’s podcasts are doing the same for countless young Ethiopians.&lt;/p&gt;
&lt;h1&gt;Building Community Through Podcasts&lt;/h1&gt;
&lt;p&gt;Life in Ethiopia comes with challenges, whether it’s navigating school, work, or personal growth. But podcasts remind us that we’re not alone. They create spaces where we can share struggles, celebrate wins, and uplift each other.&lt;/p&gt;
&lt;p&gt;Hearing someone talk about the same problems you’ve faced is powerful. It builds a sense of connection and shows that, together, we can find solutions, support one another, and create real change.&lt;/p&gt;
&lt;h1&gt;The Power of Ethiopian Role Models&lt;/h1&gt;
&lt;p&gt;Podcasts go beyond entertainment, they inspire and empower. They connect us with remarkable individuals from all walks of life: entrepreneurs, artists, scientists, and activists. Through these conversations, we learn about perseverance, passion, and the incredible potential within us.&lt;/p&gt;
&lt;p&gt;These voices make success feel attainable. They remind us that Ethiopian innovation isn’t just a dream, it’s happening right now.&lt;/p&gt;
&lt;h1&gt;A Bright Future for Podcasting&lt;/h1&gt;
&lt;p&gt;As the digital landscape evolves, Ethiopian podcasts are becoming a powerful force for change. Their accessibility and personal connection make them ideal for empowering young people, fostering innovation, and preserving our rich cultural heritage.&lt;/p&gt;
&lt;p&gt;Yet, many of our innovators remain unseen. Our sense of community is still too small. We don’t always recognize the dreamers and builders shaping Ethiopia’s future. But podcasts are changing that. They bring us closer, amplify voices that deserve to be heard, and remind us that greatness exists in each of us.&lt;/p&gt;
&lt;h1&gt;Check These Out, You Won’t Regret It!&lt;/h1&gt;
&lt;p&gt;If you haven’t explored Ethiopian podcasts yet, now is the time! Here are some incredible shows that will make you think, laugh, and inspire you to take action:&lt;/p&gt;
&lt;p&gt;🎙️ Dejaf Podcast - Unfiltered conversations on real life issues.&lt;/p&gt;
&lt;p&gt;🎙️ Gugut Podcast - Fun and deep discussions with fresh voices.&lt;/p&gt;
&lt;p&gt;🎙️ Devtopia - Tech, innovation, and how the youth are shaping the future.&lt;/p&gt;
&lt;p&gt;🎙️ Meri Podcast - Eye-opening talks on social issues, personal growth, and empowerment.&lt;/p&gt;
&lt;p&gt;Podcasts aren’t just background noise, they’re like sitting in on the most interesting discussions you wish you could be part of. The question is, are we ready to listen?&lt;/p&gt;
</content:encoded><category>golang</category><category>stdlib</category><author>deamking@icloud.com (Dream king)</author><enclosure url="https://world-rose.vercel.app/assets/articles/podcast_2x.jpeg" length="1235" type="image/jpeg"/></item><item><title>The Trap of Stability</title><link>https://world-rose.vercel.app/fragments/status</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/status</guid><description>How Your Ego and Self-Worth Are Holding You Back.</description><pubDate>Mon, 03 Mar 2025 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;When you were younger, you weren’t afraid to take risks. You built things just to see if they would work, spoke up without overthinking, and threw yourself into challenges because failure didn’t seem like a big deal.  &lt;/p&gt;
&lt;p&gt;But over time, something shifted. You earned a title, built a reputation, and found a place in the world. Stability became the goal. And with it came an unspoken fear what if taking a risk now means losing everything you’ve built?  &lt;/p&gt;
&lt;h2&gt;How Status Makes Us Play It Safe&lt;/h2&gt;
&lt;p&gt;In the beginning, the goal was to get better, to grow, to prove yourself. But at a certain point, the focus shifts from growth to preservation. You start making safer choices, avoiding anything that could shake the foundation you’ve built.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You hesitate before taking on ambitious projects because failure would be too public.  &lt;/li&gt;
&lt;li&gt;You stop learning new skills because you don’t want to be bad at something again.  &lt;/li&gt;
&lt;li&gt;You say less in meetings because you’d rather protect your reputation than risk being wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ironically, the very thing that once drove your learning, experimenting, improving is now the thing you avoid. You don’t want to start over. You don’t want to look foolish. So, you trade curiosity for certainty, and in doing so, you stop moving forward.  &lt;/p&gt;
&lt;h2&gt;The Slow Fade Into Stagnation&lt;/h2&gt;
&lt;p&gt;This mindset doesn’t hit all at once. It happens gradually, in small, justifiable steps.  &lt;/p&gt;
&lt;p&gt;At first, you avoid unnecessary risks. That makes sense. But soon, you start avoiding necessary risks, too. The risks that could push you further, expand your perspective, or help you grow. Before you know it, you’re not evolving, you’re just maintaining.  &lt;/p&gt;
&lt;p&gt;And that’s the real danger: not failure, but stagnation.  &lt;/p&gt;
&lt;h2&gt;Breaking the Cycle&lt;/h2&gt;
&lt;p&gt;So what’s the way out? It’s not about recklessness. It’s about remembering that growth doesn’t stop just because you’ve “made it.”  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stay a beginner in something.&lt;/strong&gt; Whether it’s a new skill, a new industry, or just a new way of thinking, keep yourself uncomfortable.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redefine success.&lt;/strong&gt; If success only means maintaining what you have, you’ll always be stuck. Instead, let it mean learning, experimenting, and evolving.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Take small risks.&lt;/strong&gt; You don’t have to bet everything, but you do have to bet something. Speak up. Try something new. Do the thing that makes you nervous.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of the day, the question isn’t whether you’ll fail. The question is: will you let the fear of failure stop you from growing?  &lt;/p&gt;
&lt;p&gt;Because the most dangerous thing isn’t losing what you have, it’s never becoming more than what you are now.  &lt;/p&gt;
</content:encoded><category>motivate</category><author>deamking@icloud.com (Dream king)</author></item><item><title>A Deep Dive into os/exec Package</title><link>https://world-rose.vercel.app/fragments/exec</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/exec</guid><description>Unlock the Power of Your Operating System: Command Execution in Go</description><pubDate>Sat, 11 Jan 2025 14:01:28 GMT</pubDate><content:encoded>&lt;p&gt;At the heart of this city is the kernel, the all-powerful manager that directs traffic, ensures smooth communication, and enforces the rules. Just as a city&apos;s mayor coordinates activities through various departments, the kernel executes commands that keep your computer running efficiently. Every time you launch an application, run a script, or perform a system task, the kernel is hard at work, processing your requests and executing commands to get the job done.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;os/exec&lt;/strong&gt; package in Go is your toolkit for interacting with the kernel, allowing you to run external commands from within your Go programs. It&apos;s like having a direct line to the city&apos;s command center, giving you the power to execute tasks with precision and efficiency.&lt;/p&gt;
&lt;h2&gt;Customizing Command Execution&lt;/h2&gt;
&lt;p&gt;When it comes to interacting with the operating system in Go, the standard library provides a straightforward way to execute external processes. The &lt;strong&gt;os/exec&lt;/strong&gt; package is the key to unlocking this functionality. In this blog post, we&apos;ll explore how to use it to call external commands and tools.&lt;/p&gt;
&lt;h2&gt;Using the Cmd Struct and Run Method&lt;/h2&gt;
&lt;p&gt;The most straightforward way to execute an external process is by creating a &lt;strong&gt;Cmd&lt;/strong&gt; struct and calling its &lt;strong&gt;Run&lt;/strong&gt; method. This approach is perfect for calling OS utilities and tools, ensuring that your program doesn&apos;t hang indefinitely waiting for the process to complete.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
  prc := exec.Command(&quot;ls&quot;, &quot;-l&quot;)
  err := prc.Run()
  if err != nil {
    panic(err) 
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;Run&lt;/strong&gt; method executes the command and waits until it completes. If the command exits with an error, the &lt;code&gt;err&lt;/code&gt; value will not be nil, allowing you to handle errors accordingly.&lt;/p&gt;
&lt;p&gt;If you run this command and nothing seems to happen, don&apos;t worry, the command has been executed. In subsequent sections, we will look at how to capture the output of execution as well as how to manage user input from commands. &lt;/p&gt;
&lt;p&gt;In case a command is not found in the OS binary registry, you can locate it using &lt;code&gt;exec.LookPath(&quot;ls&quot;)&lt;/code&gt;, which helps ensure that your system functions as expected.&lt;/p&gt;
&lt;h2&gt;Handling Input/Output Streams&lt;/h2&gt;
&lt;p&gt;The output from executed commands is crucial and can be bound to any writer, be it Standard Output, a file, or any other writer implementing the &lt;code&gt;io.Writer&lt;/code&gt; interface.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
 &quot;bytes&quot;
 &quot;fmt&quot;
 &quot;os/exec&quot;
)

func main() {
 prc := exec.Command(&quot;ls&quot;, &quot;-a&quot;)
 out := bytes.NewBuffer([]byte{})
 prc.Stdout = out
 err := prc.Run()
 if err != nil {
   fmt.Println(err)
 }
 if prc.ProcessState.Success() {
   fmt.Println(&quot;Process run successfully with output:&quot;)
   fmt.Println(out.String())
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code snippet, we create a new &lt;code&gt;exec.Command&lt;/code&gt; object representing the &lt;code&gt;ls&lt;/code&gt; command process. We then use a &lt;code&gt;bytes.Buffer&lt;/code&gt; object to capture the output of the command. The &lt;code&gt;prc.Stdout&lt;/code&gt; field is set to &lt;code&gt;out&lt;/code&gt;, meaning that any output from the command will be written there.&lt;/p&gt;
&lt;p&gt;After running the command using &lt;code&gt;prc.Run()&lt;/code&gt;, we check for errors. If there are none, we verify if the command ran successfully using &lt;code&gt;prc.ProcessState.Success()&lt;/code&gt;, printing both a success message and the output.&lt;/p&gt;
&lt;h2&gt;Combined Output&lt;/h2&gt;
&lt;p&gt;You can also use a command&apos;s &lt;strong&gt;CombinedOutput&lt;/strong&gt; method, which assigns both standard output and standard error to a buffer.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
    cmd := exec.Command(&quot;ls&quot;, &quot;-a&quot;)
    out, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatalf(&quot;cmd.Run() failed with %s\n&quot;, err)
    }
    fmt.Printf(&quot;combined out:\n%s\n&quot;, string(out))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method simplifies capturing all output types from a command into one variable.&lt;/p&gt;
&lt;h2&gt;Interacting with External Bash Shells&lt;/h2&gt;
&lt;p&gt;The following program demonstrates how to interact with an external Bash shell using command execution and buffered I/O:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import ( 
  &quot;bufio&quot;
  &quot;fmt&quot; 
  &quot;os&quot; 
  &quot;log&quot;
  &quot;os/exec&quot;
  &quot;strings&quot; 
  &quot;errors&quot;
) 

type Shell struct{} 

func (Shell) CmdFromString(p []string) (cmd *exec.Cmd, err error) {
 if len(p) == 0 { return nil, errors.New(&quot;endline clicked&quot;) }
 if len(p) == 1 { return exec.Command(p[0]), nil }
 return exec.Command(p[0], p[1:]...), nil 
} 

func main() {
 input := bufio.NewScanner(os.Stdin)
 shell := Shell{}
 for input.Scan() {
  cmd, err := shell.CmdFromString(strings.Fields(input.Text()))
  if err != nil { continue }
  
  out, err := cmd.CombinedOutput()
  if err != nil { log.Panic(err) }
  fmt.Printf(&quot;Output \n%s&quot;, out)
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This program allows users to enter commands interactively; as they type commands, it relays them to Bash and captures their outputs.&lt;/p&gt;
&lt;h2&gt;Error Handling and Exit Status&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;os/exec&lt;/strong&gt; package includes two primary error types: &lt;strong&gt;exec.Error&lt;/strong&gt; and &lt;strong&gt;exec.ExitError&lt;/strong&gt;. It&apos;s essential to check for both types of errors and handle them accordingly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Handling exec.Error&lt;/strong&gt;: This error occurs when a command cannot be executed due to issues like being not found or not executable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling exec.ExitError&lt;/strong&gt;: This error arises when a command executes but returns a non-zero exit status indicating failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By understanding these concepts within Go&apos;s &lt;strong&gt;os/exec&lt;/strong&gt; package, you can effectively manage external command execution in your applications. Happy coding!&lt;/p&gt;
</content:encoded><category>golang</category><category>stdlib</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Error Handling Demystified</title><link>https://world-rose.vercel.app/fragments/error-handling</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/error-handling</guid><description>Dive into the world of error handling with this comprehensive overview of best practices from multiple programming languages. Learn how to implement effective strategies that enhance application stability and improve user experience.</description><pubDate>Sat, 26 Oct 2024 03:06:04 GMT</pubDate><content:encoded>&lt;p&gt;In an era where user expectations are high, implementing proper error handling mechanisms is not just a best practice; it’s a necessity. Just as we strive for balanced nutrition to support our well-being, prioritizing error management is crucial for the health of our applications.&lt;/p&gt;
&lt;p&gt;The approach to error handling varies significantly between testing environments and production settings. This distinction is crucial for ensuring both the reliability of applications and the overall user experience.&lt;/p&gt;
&lt;p&gt;During the &lt;strong&gt;testing phase&lt;/strong&gt;, error handling serves as a critical tool for developers to identify and rectify issues before deployment. In this controlled environment, developers can simulate various scenarios, allowing them to observe how their application responds to unexpected inputs or failures. The primary aim here is to uncover bugs and ensure that all potential errors are addressed. &lt;strong&gt;Comprehensive logging&lt;/strong&gt; and &lt;strong&gt;detailed error messages&lt;/strong&gt; are often employed to facilitate debugging, providing developers with insights that can lead to improvements in the codebase.&lt;/p&gt;
&lt;p&gt;Error handling in a &lt;strong&gt;production environment&lt;/strong&gt; focuses on maintaining application stability and user satisfaction. Once an application is live, it is essential that it operates smoothly for end-users, even when unforeseen errors occur. In this context, error handling mechanisms must be robust yet discreet. This often involves implementing &lt;strong&gt;user-friendly error messages&lt;/strong&gt; that guide users without exposing them to technical jargon. Additionally, &lt;strong&gt;logging errors for later analysis&lt;/strong&gt; becomes paramount, enabling developers to monitor application health and address issues proactively.&lt;/p&gt;
&lt;p&gt;By implementing a variety of error handling approaches, you can proactively address potential issues, enhance application reliability, and maintain user trust. Below are some widely recognized error handling techniques employed across different programming languages.&lt;/p&gt;
&lt;figure&gt;
  &lt;div&gt;
    &lt;table&gt;
      &lt;caption&gt;Error Handling Approaches&lt;/caption&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Error Handling Approach&lt;/th&gt;
          &lt;th&gt;Best Practiced Language&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Try-Catch Blocks&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Java, Python, C#, JavaScript&lt;/td&gt;
          &lt;td&gt;Allows developers to wrap potentially error-prone code in a &lt;code&gt;try&lt;/code&gt; block and handle exceptions in a &lt;code&gt;catch&lt;/code&gt; block.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Return Values for Error Indication&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;C, Go&lt;/td&gt;
          &lt;td&gt;Functions return specific values to indicate success or failure, requiring the caller to check these values.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Custom Exception Classes&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Java, Python&lt;/td&gt;
          &lt;td&gt;Developers create their own exception classes to provide more context about errors that occur within applications.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Logging and Monitoring&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Python, JavaScript, Ruby&lt;/td&gt;
          &lt;td&gt;Implementing logging mechanisms to track errors and monitor application health in real-time.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Type System Approaches&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Rust, Haskell, Elm&lt;/td&gt;
          &lt;td&gt;Utilizing the type system to encode possible failures and ensure proper handling of error states through constructs like &lt;code&gt;Option&lt;/code&gt; or &lt;code&gt;Result&lt;/code&gt;.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Defensive Programming&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;C++, Java&lt;/td&gt;
          &lt;td&gt;Anticipating potential errors and implementing safeguards within the code to handle unexpected situations gracefully.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Graceful Degradation&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;JavaScript&lt;/td&gt;
          &lt;td&gt;Ensuring that applications can continue to function in a limited capacity even when errors occur.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Fail-Fast Principle&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Go, Java&lt;/td&gt;
          &lt;td&gt;Designing systems to fail immediately upon encountering an error, preventing further propagation of issues.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Asynchronous Error Handling&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;JavaScript&lt;/td&gt;
          &lt;td&gt;Managing errors that occur in asynchronous operations effectively without blocking the main execution thread.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Checked Exceptions&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Java&lt;/td&gt;
          &lt;td&gt;Enforcing compile-time checks for certain exceptions that must be either caught or declared in the method signature.&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;

  &lt;figcaption&gt;Effective strategies for managing errors in software applications.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;hr /&gt;
&lt;h1&gt;1. Error handling, &quot;try...catch&quot;&lt;/h1&gt;
&lt;p&gt;In languages that utilize try-catch blocks, errors are treated as side effects of execution rather than as values, emphasizing the need for recovery and separation of error handling from normal program logic. This approach involves wrap potentially error-prone code in a &lt;code&gt;try&lt;/code&gt; block and handle exceptions in a &lt;code&gt;catch&lt;/code&gt; block.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  // code...
} catch (err) {
  // error handling
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create robust &lt;code&gt;try...catch&lt;/code&gt; error handling, one should employ &lt;strong&gt;specific exception types&lt;/strong&gt; that &lt;strong&gt;accurately reflect&lt;/strong&gt; the nature of errors within your application. This enables &lt;strong&gt;targeted debugging&lt;/strong&gt; and error resolution. Additionally, provide &lt;strong&gt;clear and informative error messages&lt;/strong&gt; that &lt;strong&gt;convey the root cause&lt;/strong&gt; of the issue, aiding in swift problem identification and resolution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overreliance&lt;/strong&gt; on try-catch blocks can be a &lt;strong&gt;dangerous habit&lt;/strong&gt;. By catching generic exceptions without specific handling, developers can easily &lt;strong&gt;ignore underlying issues&lt;/strong&gt;, leading to a &lt;strong&gt;false sense of security&lt;/strong&gt;. It&apos;s like using a blanket solution to a complex problem. While it might temporarily silence the error, it doesn&apos;t address the root cause. This can result in &lt;strong&gt;delayed bug detection&lt;/strong&gt;, &lt;strong&gt;increased maintenance costs&lt;/strong&gt;, and &lt;strong&gt;potential system failures&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;2. Return Values for Error Indication&lt;/h1&gt;
&lt;p&gt;Functions can signal errors by returning specific &lt;strong&gt;values&lt;/strong&gt;, often distinct from the regular return type. In &lt;code&gt;Golang&lt;/code&gt; functions can return multiple values, one of which can be an error value. The &lt;strong&gt;error&lt;/strong&gt; type is commonly used for this purpose. Returning specific values to indicate error conditions can lead to more explicit and controlled error handling. By carefully examining the return value, developers can make informed decisions about how to proceed. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func OpenFile(filename string) (*os.File, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    return file, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach feels right. That&apos;s because errors are usually of immediate interest; the error is either actionable (and &lt;strong&gt;must&lt;/strong&gt; be handled) or there&apos;s some important context that needs to be captured (local variables). Errors as values result in both &lt;strong&gt;compact&lt;/strong&gt; and &lt;strong&gt;readable&lt;/strong&gt; code. Although having to explicitly handle &lt;strong&gt;errors&lt;/strong&gt; every time can sometimes be a bit challenging.&lt;/p&gt;
</content:encoded><category>js</category><category>cleancode</category><author>deamking@icloud.com (Dream king)</author></item><item><title>New Year at Yenehealth</title><link>https://world-rose.vercel.app/fragments/ethipian-newyear</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/ethipian-newyear</guid><description>Enkutatash</description><pubDate>Mon, 09 Sep 2024 07:51:04 GMT</pubDate><content:encoded>&lt;figure&gt;
    
    &lt;figcaption&gt;Enkutatash, at yenehealth&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;Enkutatash, the Ethiopian New Year, was more than just a celebration, it was a time for family, thanks, and looking back. My mother, glowing with excitement, was busy spreading &lt;strong&gt;kettema&lt;/strong&gt; around the house, making it smell comforting and familiar.&lt;/p&gt;
&lt;p&gt;Even though it was raining heavily outside, which didn’t match the new year&apos;s promise of spring, the festive mood was strong. At work, everyone was buzzing with energy. People were dressed up, their faces full of joy. I felt a bit awkward in my casual clothes, but my colleagues were too wrapped up in the celebration to care.&lt;/p&gt;
&lt;p&gt;Lunch was a treat. The food from a popular restaurant was delicious, but the real highlight was sharing it with the team. It was the first time we all ate together, and it was nice to see my colleagues enjoy a tradition I knew very well.&lt;/p&gt;
&lt;p&gt;The day was packed with coffee, dancing, and laughter. We even invited our neighbors to join in. As the day ended, we gave Beza a pair of earbuds for finding the last googly eyes.&lt;/p&gt;
&lt;p&gt;The day showed me how important workplace culture is. In a world focused on speed and technology, it can be tough to build a sense of community. But at Yenehealth, I saw how a positive, supportive culture makes a difference. It’s a place where people feel valued, inspired, and connected.&lt;/p&gt;
</content:encoded><category>holiday</category><category>new_year</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Fun and Effective Commit Messages</title><link>https://world-rose.vercel.app/fragments/commit-conventions</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/commit-conventions</guid><description>Commit are breadcrumbs that guide you through the forest of your code. They help you remember what you did, why you did it, and how it all fits together.</description><pubDate>Mon, 26 Aug 2024 07:51:04 GMT</pubDate><content:encoded>&lt;p&gt;Conventional Commits is a set of rules. These rules help you write clear and consistent commit messages. Think of it like a secret code. It helps you and your teammates talk better about code changes. Here are some of the most common types of commit messages you&apos;ll encounter:&lt;/p&gt;
&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;New Feature!&lt;/h2&gt;
&lt;p&gt;When you add something exciting to your application, like a shiny new button or a cool new page, you use feat. This tells everyone, “Hey, check out this awesome new feature!”&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;feat: add a dark mode toggle&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Squash Bugs!&lt;/h2&gt;
&lt;p&gt;If you find and fix a pesky bug that’s been causing trouble, you’ll want to use fix. This shows that you’ve solved a problem, making the app better for everyone.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;fix: correct typo in the login error message&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Little Things&lt;/h2&gt;
&lt;p&gt;Sometimes, you need to make changes that don’t change how the app works. This could be updating a library or cleaning up the code. You call these chores. They keep everything tidy without changing any features.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;chore: update README with installation instructions&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Document the Journey&lt;/h2&gt;
&lt;p&gt;When you make changes to the documentation, like fixing a typo or adding new instructions, you’ll use docs. This is important because it helps everyone understand how to use the app.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;docs: update API documentation for new endpoints&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Make It Pretty&lt;/h2&gt;
&lt;p&gt;If you change how the code looks without changing what it does, use style. This includes fixing indentation or removing extra spaces. This keeps the code looking sharp!&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;style: format code to follow style guide&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Improve the Code&lt;/h2&gt;
&lt;p&gt;When you change the code to make it better, but you don’t add features or fix bugs, you use refactor. This is all about improving the structure of the code.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;refactor: simplify user authentication logic&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Speed Things Up&lt;/h2&gt;
&lt;p&gt;If you make changes that make the app faster or more efficient, you’ll want to use perf. Everyone loves a speedy app!&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;perf: optimize image loading for faster page rendering&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Ensure Quality&lt;/h2&gt;
&lt;p&gt;When you add tests to check that your code works or fix existing tests, you use test. This helps keep the code reliable.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;test: add unit tests for user login functionality&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Foundation&lt;/h2&gt;
&lt;p&gt;You mark changes that affect the build system or external dependencies with build. This includes things like updating a package. This ensures your project runs efficiently.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;build: upgrade to latest version of Node.js&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Continuous Integration&lt;/h2&gt;
&lt;p&gt;If you make changes related to continuous integration configurations, you’ll use ci. This helps automate the testing and deployment process.&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;ci: update GitHub Actions workflow for deployment&lt;/code&gt;&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Going Back in Time&lt;/h2&gt;
&lt;p&gt;When you need to undo a previous change, you use revert. It’s like hitting the rewind button!&lt;/p&gt;
&lt;p&gt;Example:  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;revert: remove feature that caused crashes&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Why?&lt;/h2&gt;
&lt;p&gt;Using these conventions helps keep your commit history clear and organized. It’s like having a well-labeled filing cabinet for all your code changes. When everyone follows the same rules, understanding the project becomes easier. This is especially helpful when you look back at your work months later.&lt;/p&gt;
</content:encoded><category>git</category><author>deamking@icloud.com (Dream king)</author><source url="https://www.conventionalcommits.org/">Conventional Commits</source></item><item><title>Flags 2.0 Making Use of Runner</title><link>https://world-rose.vercel.app/fragments/flags_2</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/flags_2</guid><description>The flag package reigns supreme when it comes to wielding command-line arguments. It empowers you to gracefully accept user-specified instructions, tailoring your program&apos;s behavior on the fly.</description><pubDate>Fri, 01 Mar 2024 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;Let&apos;s walk through a simple command-line tool that greets a user by name. We&apos;ll enhance this tool by incorporating the flag package to personalize the greeting based on user input. Here we will be looking at the NewFlagSet method in the flags package&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Runner interface {
    Init([]string) error
    Run() error
    Name() string
}

type GreetCommand struct {
    fs *flag.FlagSet

    name string
}

func NewGreetCommand() *GreetCommand {
    gc := &amp;amp;GreetCommand{
        fs: flag.NewFlagSet(&quot;greet&quot;, flag.ContinueOnError),
    }

    gc.fs.StringVar(&amp;amp;gc.name, &quot;name&quot;, &quot;World&quot;, &quot;name of the person to be greeted&quot;) // -name
    gc.fs.StringVar(&amp;amp;gc.name, &quot;n&quot;, &quot;World&quot;, &quot;name of the person to be greeted&quot;)    // -n
    return gc
}

func (g *GreetCommand) Name() string {
    return g.fs.Name()
}

func (g *GreetCommand) Init(args []string) error {
    return g.fs.Parse(args)
}

func (g *GreetCommand) Run() error {
    fmt.Println(&quot;Hello&quot;, g.name, &quot;!&quot;)
    return nil
}

func root(args []string) error {
    if len(args) &amp;lt; 1 {
        return errors.New(&quot;you must pass a sub-command&quot;)
    }

    cmds := []Runner{
        NewGreetCommand(),
    }

    subcommand := os.Args[1]

    for _, cmd := range cmds {
        if cmd.Name() == subcommand {
            cmd.Init(os.Args[2:]) // parse the flags
            return cmd.Run()
        }
    }

    return fmt.Errorf(&quot;unknown subcommand: %s&quot;, subcommand)
}

func main() {
    if err := root(os.Args[1:]); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running the Program with Flags&lt;/p&gt;
&lt;p&gt;Let&apos;s see how this code works in action. To greet someone named &lt;code&gt;dre&lt;/code&gt; we can run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go greet -name dre
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello dre !
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-name&lt;/code&gt; flag allows us to override the default name (&quot;World&quot;) and personalize the greeting.&lt;/p&gt;
&lt;h2&gt;Expanding on the Runner Interface for Composable Commands&lt;/h2&gt;
&lt;p&gt;Let&apos;s delve deeper into its purpose and how it facilitates composability for various command types.&lt;/p&gt;
&lt;h3&gt;The Power of Interfaces: Defining Common Behavior&lt;/h3&gt;
&lt;p&gt;The Runner interface defines a contract for different sub-commands within our program. It outlines three essential methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Init([]string) error&lt;/code&gt;: This method handles initialization tasks for the command, typically involving parsing flags using the flag package.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Run() error&lt;/code&gt;: This method executes the core functionality of the command.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Name() string&lt;/code&gt;: This method returns the unique name of the command, used for identification during sub-command selection.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By defining these methods in an interface, we create a blueprint for any sub-command within our application. Any struct implementing this interface automatically becomes a valid sub-command.&lt;/p&gt;
&lt;h3&gt;Composability in Action: Adding a New Command&lt;/h3&gt;
&lt;p&gt;Let&apos;s illustrate this concept by introducing a new command: stats. This command might retrieve and display program usage statistics. Here&apos;s a simplified example of the stats command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type StatsCommand struct {
  // ... relevant fields for stats command
}

func (s *StatsCommand) Init([]string) error {
  // Handle any initialization specific to stats command (e.g., no flags)
  return nil
}

func (s *StatsCommand) Run() error {
  // Implement logic to retrieve and display stats
  fmt.Println(&quot;Program Usage Statistics...&quot;)
  // ...
  return nil
}

func (s *StatsCommand) Name() string {
  return &quot;stats&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This StatsCommand struct implements the Runner interface, making it a valid sub-command. We can now add it to the list of available commands in the root function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func root(args []string) error {
  // ... existing code
  
  cmds := []Runner{
      NewGreetCommand(),
      &amp;amp;StatsCommand{}, // Add StatsCommand to the list
  }
  
  // ... remaining code
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this modification, users can now execute the &lt;code&gt;stats&lt;/code&gt; command alongside the existing greet command.&lt;/p&gt;
&lt;h3&gt;Benefits of Composable Commands&lt;/h3&gt;
&lt;p&gt;The Runner interface promotes code reusability and simplifies adding new functionalities. By adhering to this interface, developers can create various sub-commands with unique purposes while maintaining a consistent structure within the program. This modular approach makes the codebase cleaner and easier to maintain as the number of commands grows.&lt;/p&gt;
&lt;h3&gt;Further Enhancements&lt;/h3&gt;
&lt;p&gt;The Runner interface can be further extended to include additional methods specific to command management, such as providing help messages or handling errors specific to each command type. Explore these possibilities to create a more robust and flexible command-line application framework in Go.&lt;/p&gt;
</content:encoded><category>golang</category><category>std</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Flags in Go</title><link>https://world-rose.vercel.app/fragments/flags_1</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/flags_1</guid><description>The flag package reigns supreme when it comes to wielding command-line arguments. It empowers you to gracefully accept user-specified instructions, tailoring your program&apos;s behavior on the fly.</description><pubDate>Thu, 29 Feb 2024 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the realm of Go applications, the flag package reigns supreme when it comes to wielding command-line arguments. It empowers you to gracefully accept user-specified instructions, tailoring your program&apos;s behavior on the fly.&lt;/p&gt;
&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Key Functionalities:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Defining Flags: Craft flags using functions like String, Int, Bool, Var and more. Each flag carries a name (short and long versions), a default value, and a usage description.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;var name string
var verbose bool

func init() {
  flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;&quot;, &quot;Your name (default: empty)&quot;)
  flag.BoolVar(&amp;amp;verbose, &quot;verbose&quot;, false, &quot;Enable verbose output&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Parsing Arguments: When your program launches, unleash the flag.Parse() function. It meticulously dissects the command-line arguments, matching them to the meticulously defined flags and assigning the extracted values to their designated variables.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;flag.Parse() 
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Accessing Values: Once parsing is complete, the flag variables hold the user-provided values, ready to be employed within your program&apos;s logic.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;Hello,&quot;, name)
if verbose {
 fmt.Println(&quot;Verbose mode enabled!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Making Connections Flexible with Go&apos;s flag Package: A Real-World Example&lt;/h3&gt;
&lt;p&gt;The flag package empowers you to create command-line programs with dynamic configurations through user-defined flags. We&apos;ll delve into how this code leverages flags to control retry attempts and data for an HTTP request.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type ArrayValue []string

func (s *ArrayValue) String() string {
    return fmt.Sprintf(&quot;%v&quot;, *s)
}

func (a *ArrayValue) Set(s string) error {
    *a = strings.Split(s, &quot;,&quot;)
    return nil
}

func main() {
    retry := flag.Int(&quot;retry&quot;, -1, &quot;Defines the max retry count&quot;)

    var logPrefix string
    flag.StringVar(&amp;amp;logPrefix, &quot;prefix&quot;, &quot;&quot;, &quot;Logging prefix&quot;)

    var arr ArrayValue
    flag.Var(&amp;amp;arr, &quot;array&quot;, &quot;Input array to iterate through. &quot;)

    flag.Parse() // required for assigning values

    logger := log.New(os.Stdout, logPrefix, log.Ldate)
    retryCount := 0
    for retryCount &amp;lt; *retry {
        logger.Println(&quot;*Retrying connection&quot;)
        post()
        logger.Printf(&quot;Sending array %v\n&quot;, arr)
        retryCount++
    }
}

func makePostRequest(data []byte) ([]byte, error) {
    url := &quot;http://localhost:8080&quot; // Target URL
    req, err := http.NewRequest(&quot;POST&quot;, url, bytes.NewBuffer(data))
    if err != nil {
        return nil, err
    }
  
    req.Header.Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
    client := &amp;amp;http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    return body, nil
}

func post() {
    data := []byte(`{&quot;message&quot;: &quot;Hello from Go!&quot;}`)
    responseBody, err := makePostRequest(data)
    if err != nil {
        fmt.Println(&quot;Error:&quot;, err)
    } else {
        fmt.Println(&quot;Response:&quot;, string(responseBody))
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Running the Program with Flags&lt;/h3&gt;
&lt;p&gt;Let&apos;s see how this code works in action. To retry this request twice we give an integer of 2 and prefix the logs we named &quot;dre,&quot; we can run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go -retry 2 -prefix dre
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dre2024/03/02 *Retrying connection
Response: {&quot;message&quot;: &quot;Hello from Go!&quot;}
dre2024/03/02 Sending array []
dre2024/03/02 *Retrying connection
Response: {&quot;message&quot;: &quot;Hello from Go!&quot;}
dre2024/03/02 Sending array []
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s break down the code&apos;s flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flag Parsing:&lt;/strong&gt; The program starts by parsing the command-line arguments using flag.Parse(). This allows users to control retry count, logging prefix, and the input array via flags.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logging Setup:&lt;/strong&gt; Based on the -prefix flag, a logger object is created using the log package. This ensures informative logs with user-defined prefixes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retry Loop:&lt;/strong&gt; The program enters a loop that continues until the maximum retry count (retry) is reached. Inside the loop:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Making the Request:&lt;/strong&gt; The post function constructs a POST request to a designated URL (&lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt;). It utilizes a helper function, makePostRequest, which is responsible for building and executing the request.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;This example explores a practical example of using the flag package in Go. The &lt;code&gt;flag&lt;/code&gt; package empowers you to create command-line programs with dynamic configurations through user-defined flags. We&apos;ll delve into how this code leverages flags to control retry attempts and data for an HTTP request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Understanding the Code&lt;/h3&gt;
&lt;p&gt;The code defines a program that attempts to send data via a POST request. However, the magic lies in its configurability through flags.&lt;/p&gt;
&lt;p&gt;The ArrayValue struct tackles a specific challenge: handling comma-separated lists of strings from the &lt;code&gt;-array&lt;/code&gt; flag. Standard flag functions don&apos;t handle this natively.&lt;/p&gt;
&lt;p&gt;The Set method parses the user&apos;s input, splitting the comma-separated string into individual values stored within the ArrayValue slice. The String method provides a user-friendly way to represent the array content when needed (e.g., during logging).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;flag.Var&lt;/code&gt; function accepts a value with the following interface, &lt;code&gt;ArrayValue&lt;/code&gt; implements this inteface&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Value interface {
    String() string
    Set(string) error
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;retry: This flag, defined with &lt;code&gt;flag.Int&lt;/code&gt;, allows users to specify the maximum number of retry attempts before giving up. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;prefix: Defined with &lt;code&gt;flag.StringVar&lt;/code&gt;, this flag lets users set a prefix for log messages, adding context to their output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;array: This custom flag utilizes &lt;code&gt;flag.Var&lt;/code&gt; and a &lt;code&gt;ArrayValue&lt;/code&gt; struct to accept a comma-separated list of strings as input.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;flag.Parse()&lt;/code&gt; function is crucial, as it interprets command-line arguments and assigns them to the corresponding flags.&lt;/p&gt;
</content:encoded><category>golang</category><category>std</category><author>deamking@icloud.com (Dream king)</author></item><item><title>Stop Fighting Go and Started Listening</title><link>https://world-rose.vercel.app/fragments/standard_library</link><guid isPermaLink="true">https://world-rose.vercel.app/fragments/standard_library</guid><description>Discovering the Hidden Power of Go&apos;s Standard Library</description><pubDate>Thu, 02 Mar 2023 14:03:01 GMT</pubDate><content:encoded>&lt;p&gt;For a long time, I wrote Go the way I wrote other languages: by instinct, by habit, and, honestly, by muscle memory from years of reaching for dependencies to solve my problems.  &lt;/p&gt;
&lt;p&gt;It wasn’t that I didn’t trust Go’s standard library. I just didn’t think about it. Need logging? Grab a package. Need an HTTP client? Surely, there’s a better one than the built-in &lt;code&gt;net/http&lt;/code&gt;. I treated the standard library like a set of training wheels, something to outgrow once I needed “real” functionality.  &lt;/p&gt;
&lt;p&gt;But Go had other plans for me.  &lt;/p&gt;
&lt;h2&gt;The Moment It Clicked&lt;/h2&gt;
&lt;p&gt;It started with a simple problem: logging.  &lt;/p&gt;
&lt;p&gt;I needed to log messages to a file. Easy enough. I wrote a function like this:  &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func logMessage(message string, file *os.File) {
    timestamp := time.Now().Format(&quot;2006-01-02 15:04:05&quot;)
    logLine := fmt.Sprintf(&quot;%s %s\n&quot;, timestamp, message)
    file.Write([]byte(logLine))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It worked. But something about it felt… brittle. What if I wanted to log to the console instead? Or store logs in memory for testing? Or send them to a remote service? Each new destination meant rewriting this function.  &lt;/p&gt;
&lt;p&gt;That’s when I noticed something about &lt;code&gt;os.File&lt;/code&gt;. It implemented &lt;code&gt;io.Writer&lt;/code&gt;. And &lt;code&gt;io.Writer&lt;/code&gt; wasn’t just for files, it was for &lt;em&gt;anything&lt;/em&gt; that could accept a stream of bytes.  &lt;/p&gt;
&lt;p&gt;So I rewrote the function:  &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func logMessage(message string, writer io.Writer) {
    timestamp := time.Now().Format(&quot;2006-01-02 15:04:05&quot;)
    logLine := fmt.Sprintf(&quot;%s %s\n&quot;, timestamp, message)
    writer.Write([]byte(logLine))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And just like that, my little function transformed.  &lt;/p&gt;
&lt;p&gt;Now, it didn’t care where the logs went. It could write to a file, sure, but also to &lt;code&gt;os.Stdout&lt;/code&gt;, a &lt;code&gt;bytes.Buffer&lt;/code&gt;, or even a network connection. I hadn’t added complexity. I had removed assumptions and in doing so, I had made my code far more powerful.  &lt;/p&gt;
&lt;h2&gt;Go Was Trying to Teach Me Something&lt;/h2&gt;
&lt;p&gt;I had spent so much time trying to make Go work the way I wanted that I had ignored the patterns it was trying to show me.  &lt;/p&gt;
&lt;p&gt;Interfaces like &lt;code&gt;io.Writer&lt;/code&gt; weren’t just there for convenience; they were a &lt;em&gt;way of thinking&lt;/em&gt;. A way to decouple code, to make it composable, to let it flow.  &lt;/p&gt;
&lt;p&gt;I started seeing the same lesson everywhere:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;http.Handler&lt;/code&gt; interface made middleware trivial.  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;io.Reader&lt;/code&gt; and &lt;code&gt;io.Writer&lt;/code&gt; allowed me to compose data transformations like UNIX pipes.  &lt;/li&gt;
&lt;li&gt;The built-in &lt;code&gt;context&lt;/code&gt; package helped me control timeouts and cancellations without bolting on extra dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go’s standard library wasn’t just a set of tools, it was a philosophy. One built around simplicity, composability, and minimal assumptions.  &lt;/p&gt;
&lt;h2&gt;The Shift in Mindset&lt;/h2&gt;
&lt;p&gt;I used to reach for dependencies first. Now, I pause. I look at the standard library. I ask myself, &lt;em&gt;What is Go trying to show me here?&lt;/em&gt;  &lt;/p&gt;
&lt;p&gt;Most of the time, the answer is already there, I just wasn’t listening.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; The real power isn’t in external libraries; it’s in understanding the language’s own patterns. Once you stop fighting Go and start listening to it, everything changes.&lt;/p&gt;
</content:encoded><category>golang</category><category>std</category><author>deamking@icloud.com (Dream king)</author></item></channel></rss>