<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: koderehan</title>
    <description>The latest articles on DEV Community by koderehan (@koderehan).</description>
    <link>https://dev.to/koderehan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1180913%2Fd0ed31fe-94aa-4254-8341-1b682596ffe8.png</url>
      <title>DEV Community: koderehan</title>
      <link>https://dev.to/koderehan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/koderehan"/>
    <language>en</language>
    <item>
      <title>The Project Remembers, Not the Agent</title>
      <dc:creator>koderehan</dc:creator>
      <pubDate>Thu, 13 Aug 2026 23:19:29 +0000</pubDate>
      <link>https://dev.to/koderehan/the-project-remembers-not-the-agent-3l7d</link>
      <guid>https://dev.to/koderehan/the-project-remembers-not-the-agent-3l7d</guid>
      <description>&lt;p&gt;I did not sit down to invent a framework.&lt;/p&gt;

&lt;p&gt;I was trying to build real software with coding agents, and after a while the same problem kept showing up: the work was bigger than the session.&lt;/p&gt;

&lt;p&gt;That was the actual issue.&lt;/p&gt;

&lt;p&gt;Not “which model is smartest.”&lt;br&gt;&lt;br&gt;
Not “which IDE has the best agent.”&lt;br&gt;&lt;br&gt;
Not even “does RAG help.”&lt;/p&gt;

&lt;p&gt;The issue was continuity.&lt;/p&gt;

&lt;p&gt;A feature would start in one session, continue in another, get interrupted by limits, get resumed in a different tool, and somewhere in the middle I would end up re-explaining the same things again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the feature actually is&lt;/li&gt;
&lt;li&gt;what is already done&lt;/li&gt;
&lt;li&gt;what is not done&lt;/li&gt;
&lt;li&gt;what is intentionally parked&lt;/li&gt;
&lt;li&gt;what rules matter in this repo&lt;/li&gt;
&lt;li&gt;what not to touch casually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gets exhausting fast.&lt;/p&gt;

&lt;p&gt;And it is not just annoying. It affects quality. Every restart adds noise. Every new session risks drift. Every agent handoff creates room for stupid mistakes that have nothing to do with intelligence and everything to do with lost continuity.&lt;/p&gt;

&lt;p&gt;At some point I realized I was relying too much on the chat thread to be the memory.&lt;/p&gt;

&lt;p&gt;That was the mistake.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I changed
&lt;/h2&gt;

&lt;p&gt;I started putting feature trackers in the project root.&lt;/p&gt;

&lt;p&gt;Not motivational docs. Not vague notes. Real trackers.&lt;/p&gt;

&lt;p&gt;What is the current feature?&lt;br&gt;&lt;br&gt;
What is completed?&lt;br&gt;&lt;br&gt;
What is pending?&lt;br&gt;&lt;br&gt;
What is parked?&lt;br&gt;&lt;br&gt;
What was verified?&lt;br&gt;&lt;br&gt;
What decisions were already made?&lt;/p&gt;

&lt;p&gt;That helped immediately.&lt;/p&gt;

&lt;p&gt;A fresh session no longer had to guess the active boundary from code alone.&lt;/p&gt;

&lt;p&gt;Then I hit the next problem: even when the feature state was clear, the agents would still repeat behavioral mistakes.&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wandering into adjacent cleanup&lt;/li&gt;
&lt;li&gt;ignoring existing repo patterns&lt;/li&gt;
&lt;li&gt;jumping into code too early&lt;/li&gt;
&lt;li&gt;needing the same correction more than once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I started externalizing that too.&lt;/p&gt;

&lt;p&gt;I wrote down the recurring rules. Scope rules. Verification rules. Reuse rules. Repo-boundary rules. The practical stuff that normally lives in your head until you are forced to repeat it for the fifth time.&lt;/p&gt;

&lt;p&gt;Then later I added retrieval for some of that memory, because not everything needs to be in the always-loaded layer, but some things absolutely should be recoverable when the work reaches the right point.&lt;/p&gt;

&lt;p&gt;Somewhere in there the whole workflow changed shape.&lt;/p&gt;

&lt;p&gt;It stopped being “chat remembers context.”&lt;/p&gt;

&lt;p&gt;It became “project holds continuity.”&lt;/p&gt;

&lt;h2&gt;
  
  
  That is the real idea
&lt;/h2&gt;

&lt;p&gt;The shortest version is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The project remembers, not the agent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is what I started calling ATMAR: Agentic Tracker Memory And Retrieval.&lt;/p&gt;

&lt;p&gt;And to be clear, I am not claiming I invented memory, trackers, or retrieval.&lt;/p&gt;

&lt;p&gt;That would be nonsense.&lt;/p&gt;

&lt;p&gt;What I am saying is that under real delivery pressure, I ended up combining them in a way that made interrupted multi-agent work much more survivable.&lt;/p&gt;

&lt;p&gt;The core pieces are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tracker memory for feature state&lt;/li&gt;
&lt;li&gt;behavioral memory for recurring rules&lt;/li&gt;
&lt;li&gt;retrieval memory for recoverable context&lt;/li&gt;
&lt;li&gt;repo-grounded verification so memory never outranks code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each part already exists in some form.&lt;/p&gt;

&lt;p&gt;But the combination mattered more than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I think this is worth looking at
&lt;/h2&gt;

&lt;p&gt;A lot of discussion around coding agents still feels too chat-centric.&lt;/p&gt;

&lt;p&gt;People ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which model is better&lt;/li&gt;
&lt;li&gt;how much context can fit&lt;/li&gt;
&lt;li&gt;which agent is best at coding&lt;/li&gt;
&lt;li&gt;whether one prompt style beats another&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions are fine. I use those tools too.&lt;/p&gt;

&lt;p&gt;But I think there is a more basic software-engineering question sitting underneath all of that:&lt;/p&gt;

&lt;p&gt;What happens when the work outlives the session?&lt;/p&gt;

&lt;p&gt;Because that is normal. That is not some edge case. Real software work is messy, long, interrupted, and spread across time.&lt;/p&gt;

&lt;p&gt;So if continuity depends mainly on the current thread being alive, then the workflow is fragile by design.&lt;/p&gt;

&lt;p&gt;That is the part I wanted to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am claiming, and what I am not
&lt;/h2&gt;

&lt;p&gt;I am not claiming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a new model architecture&lt;/li&gt;
&lt;li&gt;a new retrieval algorithm&lt;/li&gt;
&lt;li&gt;a universal proof that this beats every workflow&lt;/li&gt;
&lt;li&gt;some dramatic AI breakthrough&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am claiming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this solved a real problem for me&lt;/li&gt;
&lt;li&gt;it emerged while doing substantial actual software work&lt;/li&gt;
&lt;li&gt;it made agent switching less destructive&lt;/li&gt;
&lt;li&gt;it reduced how often I had to reconstruct the same context from scratch&lt;/li&gt;
&lt;li&gt;it is worth testing as a method, not just as a personal habit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Someone will probably say: “this is just disciplined workflow.”&lt;/p&gt;

&lt;p&gt;Fine.&lt;/p&gt;

&lt;p&gt;Maybe it is.&lt;/p&gt;

&lt;p&gt;But that is not a dismissal unless the discipline does nothing.&lt;/p&gt;

&lt;p&gt;The real question is whether this kind of discipline creates a stronger continuity layer for long-horizon AI-assisted software development.&lt;/p&gt;

&lt;p&gt;That is testable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I gave it a name
&lt;/h2&gt;

&lt;p&gt;Because unnamed patterns disappear.&lt;/p&gt;

&lt;p&gt;If you do not name something, people either ignore it, or they copy pieces of it without any shared language for what actually made it useful.&lt;/p&gt;

&lt;p&gt;I wanted this to be inspectable.&lt;/p&gt;

&lt;p&gt;Not glorified. Inspectable.&lt;/p&gt;

&lt;p&gt;If it has a name, then people can do something more useful than vague agreement or vague dismissal. They can compare it.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repo only&lt;/li&gt;
&lt;li&gt;repo plus spec&lt;/li&gt;
&lt;li&gt;repo plus tracker&lt;/li&gt;
&lt;li&gt;repo plus tracker plus rules&lt;/li&gt;
&lt;li&gt;full tracker plus rules plus retrieval workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where I think the discussion should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it is weak
&lt;/h2&gt;

&lt;p&gt;The weak point is obvious.&lt;/p&gt;

&lt;p&gt;I have strong operational evidence and real artifact evidence. I do not yet have clean comparative proof.&lt;/p&gt;

&lt;p&gt;So I am not pretending the argument is finished.&lt;/p&gt;

&lt;p&gt;That is why I published ATMAR as a case-study and evaluation artifact, not as some inflated “future of engineering” pitch.&lt;/p&gt;

&lt;p&gt;I would rather have people test it and tell me where it breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to try it
&lt;/h2&gt;

&lt;p&gt;Try it on one feature.&lt;/p&gt;

&lt;p&gt;Not your entire company.&lt;br&gt;&lt;br&gt;
Not a six-month transformation plan.&lt;br&gt;&lt;br&gt;
One feature.&lt;/p&gt;

&lt;p&gt;Set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a tracker&lt;/li&gt;
&lt;li&gt;a behavior-rules file&lt;/li&gt;
&lt;li&gt;a runtime memory layer&lt;/li&gt;
&lt;li&gt;one explicit rule that the repository outranks memory when they conflict&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then resume the feature from a fresh session or another agent.&lt;/p&gt;

&lt;p&gt;See what happens.&lt;/p&gt;

&lt;p&gt;Did the restart get easier?&lt;br&gt;&lt;br&gt;
Did the agent stay in scope better?&lt;br&gt;&lt;br&gt;
Did handoff improve?&lt;br&gt;&lt;br&gt;
Did you repeat yourself less?&lt;br&gt;&lt;br&gt;
Or was the maintenance overhead not worth it?&lt;/p&gt;

&lt;p&gt;That is the kind of feedback I want.&lt;/p&gt;

&lt;p&gt;I put the repo here:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://github.com/revdfdev/ATMAR&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you test it, I would genuinely rather get a sharp criticism backed by a real attempt than polite praise.&lt;/p&gt;

&lt;p&gt;That would be more useful.&lt;/p&gt;

&lt;p&gt;Maybe this ends up being a niche but solid method.&lt;br&gt;&lt;br&gt;
Maybe it becomes a useful reference point for long-horizon agent continuity.&lt;br&gt;&lt;br&gt;
Maybe people copy the pattern and improve it.&lt;/p&gt;

&lt;p&gt;All of that is fine.&lt;/p&gt;

&lt;p&gt;The key thing for me is simpler than the branding:&lt;/p&gt;

&lt;p&gt;once I stopped depending on the agent to be the memory layer, the work became much less fragile.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>openai</category>
    </item>
    <item>
      <title>Building a Web Application Framework in Go</title>
      <dc:creator>koderehan</dc:creator>
      <pubDate>Mon, 09 Oct 2023 21:24:39 +0000</pubDate>
      <link>https://dev.to/koderehan/building-a-web-application-framework-in-go-3n5m</link>
      <guid>https://dev.to/koderehan/building-a-web-application-framework-in-go-3n5m</guid>
      <description>&lt;p&gt;In this article, I'll walk through the implementation of a simple web application framework in Go. I will go through the code step by step and understand how it works. By the end of this article, you'll have a basic understanding of how to build a web application framework using Go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&amp;nbsp;:- This article assumes that you have a knowledge about goroutines, sync package with ReadAndWrite mutex and channels, This part wont be discussed in this article. I will soon be writing an article explaining the use of context, goroutines, channels in the below code seperately.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Go is a powerful and efficient language for building web applications. It provides a standard library package called &lt;code&gt;net/http&lt;/code&gt; that makes it easy to create web servers. However, building a web application often involves more than just handling HTTP requests and responses. It usually includes routing, middleware, and more.&lt;br&gt;
In this article, we'll create a basic web application framework that includes the following features:&lt;/p&gt;

&lt;p&gt;1.Routing.&lt;br&gt;
2.Middleware support.&lt;br&gt;
3.Request and Response handling.&lt;br&gt;
4.Graceful server shutdown.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;We'll start by discussing the main components of our web application framework: &lt;code&gt;app.go&lt;/code&gt;, &lt;code&gt;context.go&lt;/code&gt;, &lt;code&gt;handlers.go&lt;/code&gt;, and &lt;code&gt;routes.go&lt;/code&gt;. These files make up the core of our framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.go&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package app

import (
    // Imports omitted for brevity
)

// App represents the web application.
type App struct {
    ServerType  string
    Address     string
    Port        int
    Routes      []Route
    middlewares []MiddlewareFunc
    Server      *http.Server
    context     context.Context
    cancel      context.CancelFunc
}

// NewApp creates a new instance of the App struct with the provided configuration.
func NewApp(serverType, address string, port int, appCtx context.Context, cnl context.CancelFunc) *App {
    return &amp;amp;App{
        ServerType: serverType,
        Address:    address,
        Port:       port,
        context:    appCtx,
        cancel:     cnl,
    }
}

// Use adds middleware functions to the application.
func (app *App) Use(middlewareFunc MiddlewareFunc) {
    app.middlewares = append(app.middlewares, middlewareFunc)
}

// Run starts the HTTP server, registers routes, and handles graceful shutdown.
func (app *App) Run() {
    // Server configuration
    app.Server = &amp;amp;http.Server{
        Addr:    fmt.Sprintf("%s:%d", app.Address, app.Port),
        Handler: app,
    }

    // Start listening for incoming connections
    listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", app.Address, app.Port))
    if err != nil {
        log.Fatalf("Failed to start tcp server %v", err)
    }
    defer listener.Close()

    log.Printf("Server running on port %d\n", app.Port)

    // Start the HTTP server in a goroutine
    go func() {
        if err := app.Server.Serve(listener); err != nil &amp;amp;&amp;amp; err != http.ErrServerClosed {
            log.Fatalf("Server close %v", err)
        }
    }()

    // Register routes
    for _, route := range app.Routes {
        log.Printf("Registered routes with method: %s and path %s\n", route.Method, route.Path)
    }

    // Graceful shutdown handling
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
    &amp;lt;-stop
    app.Shutdown()
}

// Shutdown gracefully shuts down the server.
func (app *App) Shutdown() {
    log.Println("Shutdown gracefully...")
    app.cancel()

    if err := app.Server.Shutdown(app.context); err != nil {
        log.Fatalf("Error during shutdown %v", err)
    }
}

// ServeHTTP handles incoming HTTP requests, routing, and middleware execution.
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    for _, route := range app.Routes {
        if r.Method == route.Method &amp;amp;&amp;amp; r.URL.Path == route.Path {
            if matches, vars := pathMatches(route.Path, r.URL.Path); matches {
                ctx := &amp;amp;Context{
                    Request:        r,
                    ResponseWriter: w,
                    Params:         vars,
                    Context:        app.context,
                }

                // Middleware execution
                finalHandler := route.Handler
                for _, middleware := range app.middlewares {
                    finalHandler = middleware(finalHandler)
                }

                // Additional built-in middleware
                finalHandler = LoggingMiddleware(finalHandler)
                finalHandler = RecoverMiddleware(finalHandler)
                finalHandler = ParseBodyMiddleware(finalHandler)
                finalHandler = DefaultResponseHeaders(finalHandler)
                finalHandler = CompressionMiddleware(finalHandler)

                // Execute the final handler
                finalHandler(ctx)
                return
            }
        }
    }

    // If no route matches, return a 404 response
    http.NotFound(w, r)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;context.go&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package app

import (
    // Imports omitted for brevity
)

// Context represents the request context for each HTTP request.
type Context struct {
    *http.Request
    http.ResponseWriter
    context.Context
    mu          sync.RWMutex
    Key         map[string]interface{}
    Params      map[string]string
    RequestBody interface{}
}

// NewContext creates a new Context instance.
func NewContext() *Context {
    return &amp;amp;Context{}
}

// Set stores key-value pairs in the context.
func (context *Context) Set(key string, value interface{}) {
    context.mu.Lock()
    defer context.mu.Unlock()

    if context.Key == nil {
        context.Key = make(map[string]interface{})
    }

    context.Key[key] = value
}

// parseBody parses the request body based on the content type.
func (context *Context) parseBody() error {
    contentType := context.Request.Header.Get("Content-Type")

    var err error
    var body interface{}

    if context.Request.Method == http.MethodPost || context.Request.Method == http.MethodPut {
        switch {
        case strings.HasPrefix(contentType, "application/json"):
            body, err = parseJSON(context.Request)
        case strings.HasPrefix(contentType, "multipart/form-data"):
            body, err = parseForm(context.Request)
        default:
            return errors.New("unsupported media type")
        }

        if err != nil {
            return err
        }

        context.RequestBody = body
        return nil
    }

    return errors.New("method not supported")
}

// Get retrieves values from the context.
func (context *Context) Get(key string) (value interface{}, exists bool) {
    context.mu.RLock()
    defer context.mu.RUnlock()
    value, exists = context.Key[key]
    return
}

// ShouldGet retrieves values from the context or panics if the value doesn't exist.
func (context *Context) ShouldGet(key string) interface{} {
    if value, exists := context.Get(key); exists {
        return value
    }

    panic(fmt.Sprintf("Value for the %s does not exist\n", key))
}

// SendResponse sends an HTTP response with the given data and status code.
func (context *Context) SendResponse(token string, data interface{}, statusCode int) {
    w := context.ResponseWriter

    if token != "" {
        w.Header().Set("Authorization", "Bearer "+token)
    }

    w.WriteHeader(statusCode)

    responseBytes, err := json.Marshal(data)

    if err != nil {
        log.Fatalf("Error while converting to bytes %v", err)
    }

    if _, err := w.Write(responseBytes); err != nil {
        log.Fatalf("Error while writing response %v", err)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;handlers.go&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package app

// Handler represents a function that can handle an HTTP request within a specific route.
type Handler func(context *Context)

// MiddlewareFunc represents a function that wraps and enhances the behavior of a Handler.
type MiddlewareFunc func(handler Handler) Handler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;routes.go&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package app

// Route represents an HTTP route, including the HTTP method, path, and associated Handler.
type Route struct {
    Method  string
    Path    string
    Handler Handler
}

// AddRoutes adds routes to the application.
func (app *App) AddRoutes(method string, path string, handler Handler) {
    app.Routes = append(app.Routes, Route{
        Method:  method,
        Path:    path,
        Handler: handler,
    })
}

// Group allows grouping routes with a common prefix.
func (app *App) Group(prefix string) *RouteGroup {
    return &amp;amp;RouteGroup{
        prefix: prefix,
        app:    app,
    }
}

// RouteGroup represents a group of routes with a common prefix.
type RouteGroup struct {
    prefix string
    app    *App
}

// Group allows further grouping of routes within a RouteGroup.
func (group *RouteGroup) Group(prefix string) *RouteGroup {
    return &amp;amp;RouteGroup{
        prefix: group.prefix + prefix,
        app:    group.app,
    }
}

// AddRoutes adds routes to the RouteGroup.
func (group *RouteGroup) AddRoutes(method string, path string, handler Handler) {
    fullpath := group.prefix + path
    group.app.AddRoutes(method, fullpath, handler)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explaining the&amp;nbsp;Code
&lt;/h2&gt;

&lt;p&gt;Now that we've seen the code, let's dive deeper into each component and understand its role in building our web application framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.go&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this file, we define the main structure of our web application, App. It includes fields for server configuration, such as ServerType, Address, Port, and more. The NewApp function is responsible for creating a new instance of App with the provided configuration. We also have methods for starting the server, registering routes, and handling graceful shutdown.&lt;br&gt;
One important aspect of our App structure is the inclusion of middleware support. Middleware functions are essential for adding features like logging, error handling, and request/response modification. By allowing users to add middleware functions, we make our framework highly extensible and customizable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;context.go&lt;/strong&gt;&lt;br&gt;
The Context struct represents the request context for each HTTP request. It contains fields for the HTTP request, response writer, and additional data. The parseBody method is used to parse the request body based on the content type, and the SendResponse method sends HTTP responses.&lt;br&gt;
The Context struct simplifies the handling of request-specific data and the parsing of request bodies. This makes it easier for developers to access and manipulate request data within their route handlers. The parseBody will automatically parse the incoming request wether form data on json data and automatically map it to a map[string ]interface{}.&lt;br&gt;
On the other hand we have the context.Set and Get methods set and retrieve instances of some variables we want to set to the context's instance, so we can retrieve it when we require it in the application lifecycle.&lt;br&gt;
I use the store based pattern for my business logics i.e. I mostly bind my strores to the context.&lt;br&gt;
for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func (stores *Stores) BindStore(next app.Handler) app.Handler {
 return func(context *app.Context) {
  context.Set("notification_store", stores.NotificationStore)
  context.Set("email_store", stores.EmailStore)
  next(context)
 }
}

func GetStore(ctx *app.Context) *Stores {
 notificationStore, nOk := ctx.ShouldGet("notification_store").(*NotificationStore)

 if !nOk {
  ctx.SendResponse("", customerror.NewError(errors.New("notification store not bound")), http.StatusInternalServerError)
 }

 emailStore, eOk := ctx.ShouldGet("email_store").(*EmailStore)

 if !eOk {
  ctx.SendResponse("", customerror.NewError(errors.New("email store not bound")), http.StatusInternalServerError)
 }

 return &amp;amp;Stores{
  NotificationStore: notificationStore,
  EmailStore:        emailStore,
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above the BindStore method will act as a Middleware function for the app instance and GetStore with be called in the Endpoint handler to access the store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;handlers.go&lt;/strong&gt;&lt;br&gt;
This file defines the Handler and MiddlewareFunc types, which are fundamental to the middleware and routing mechanisms. A Handler is a function that handles an HTTP request, and MiddlewareFunc represents a function that enhances the behavior of a Handler.&lt;br&gt;
These types are the building blocks of our middleware and routing system. Middleware functions can be used to perform tasks before or after request handling, such as authentication, logging, or data transformation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;routes.go&lt;/strong&gt;&lt;br&gt;
Here, we define the Route struct, which represents an HTTP route, including the HTTP method, path, and associated Handler. The AddRoutes method allows us to add routes to the application, and we can group routes with a common prefix using the Group method.&lt;br&gt;
The ability to group routes is valuable for organizing the application's endpoints, especially when building larger web applications with many routes.&lt;/p&gt;

&lt;p&gt;for example&amp;nbsp;:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func ProjectModules(a *app.App) {
 api := a.Group("/api")
 {
  notificationmodule.Routes(api)
  emailmodule.Routes(api)
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func Routes(g *app.RouteGroup) {

 notifications := g.Group("/notifications")
 {
  notifications.AddRoutes("POST", "/send", SendNotifications)
  notifications.AddRoutes("POST", "/ack", AcknowledgeNotification)
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example you can see that I would have router file that will have the ProjectModules function, that will import all the routes from the required modules.&lt;br&gt;
In the modules directory I would have all the directories of the modules I have as the business logic inside my application and use the api group logics as shown above in the code. This helps in versioning and seperately your business logic throughout your application.&lt;br&gt;
The app instance also have the instance of router group predefined inside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this detailed exploration of our web application framework's code, we've uncovered the key components and their roles in creating a functional framework. Each file - app.go, context.go, handlers.go, and routes.go-plays a vital role in handling HTTP requests, managing routes, and executing middleware.&lt;br&gt;
Building a web application framework from scratch not only helps you understand the inner workings of web applications but also gives you the flexibility to tailor the framework to your specific project needs. Whether you choose to use an established framework or build your own, this knowledge of the underlying code and concepts is invaluable in your journey as a Go developer.&lt;br&gt;
Now, armed with a deeper understanding of this code, you have the foundation to explore further and build more advanced features and enhancements for your web application framework in Go.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>restapi</category>
      <category>web</category>
    </item>
  </channel>
</rss>
