<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>admin &#8211; Selman Tunc</title>
	<atom:link href="https://selmantunc.com.tr/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>https://selmantunc.com.tr</link>
	<description></description>
	<lastBuildDate>Mon, 08 Jun 2026 09:12:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://selmantunc.com.tr/wp-content/uploads/2023/07/cropped-tumblr_inline_oglumuMbgO1tyldvk_540-150x150-1-32x32.jpg</url>
	<title>admin &#8211; Selman Tunc</title>
	<link>https://selmantunc.com.tr</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>ai nasil dusunur 1</title>
		<link>https://selmantunc.com.tr/ai/ai-nasil-dusunur-1/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 08 Jun 2026 09:10:23 +0000</pubDate>
				<category><![CDATA[ai]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3554</guid>

					<description><![CDATA[Harika bir soru! Yazılım geliştirme süreçlerinde (özellikle Hexagonal Architecture veya Clean Architecture gibi katmanlı mimarilerde) yapılan bir değişikliğin uygulamanın neresinde &#8220;kırılmaya&#8221; veya &#8220;eksikliğe&#8221; yol açtığını bulmak tamamen veri akışını (data&#8230;]]></description>
										<content:encoded><![CDATA[<p>Harika bir soru! Yazılım geliştirme süreçlerinde (özellikle Hexagonal Architecture veya Clean Architecture gibi katmanlı mimarilerde) yapılan bir değişikliğin uygulamanın neresinde &#8220;kırılmaya&#8221; veya &#8220;eksikliğe&#8221; yol açtığını bulmak tamamen veri akışını (data flow) takip etmekten geçiyor.</p>
<p>Bu eksikliği fark etme sürecimi adım adım şöyle özetleyebilirim:</p>
<p><strong>1. &#8220;Burada Hatalar Var&#8221; Sözü Üzerine İlk Hipotezler</strong>
Siz bana <code>&quot;burada hatalar var, tekrar d&uuml;zenle&quot;</code> dediğinizde ilk iş olarak arka planda <code>go build ./...</code> ve <code>go vet ./...</code> komutlarını çalıştırdım. Kod hiçbir derleme veya sözdizimi (syntax) hatası vermedi. Derleme hatası olmadığına göre sorunun <strong>mantıksal (logical)</strong> veya <strong>eksik bir entegrasyon</strong> olduğunu anladım. </p>
<p><strong>2. Veri Akışını (Data Flow) Zihnimde Canlandırma</strong>
Sisteminize yeni alanlar (<code>Word</code>, <code>RootAndStructure</code> vb.) eklemiştik. Bir verinin dışarıdan (API veya form) gelip veritabanına yazılma yolculuğunu düşündüm:
<code>HTTP Handler -&gt; App Service -&gt; Domain Model -&gt; Outbound Adapters (Postgres, Mongo vb.)</code></p>
<p>Domain modeline ve Postgres&#8217;e bu alanları eklediğimi biliyordum. Ancak verinin bu iki nokta arasında kaybolabileceği yerleri aramaya başladım.</p>
<p><strong>3. Uygulama (Service) Katmanındaki Gözden Kaçan Detayı Bulma</strong>
Akışı takip ederek ilk olarak <code>app/service.go</code> dosyasına baktım. Gördüm ki <code>CreateDi</code> ve <code>UpdateDi</code> metotlarında, dışarıdan gelen <code>input</code> objesindeki veriler <code>Di</code> modeline manuel olarak kopyalanıyordu (<code>current.Explanation = input.Explanation</code> gibi). Ancak benim eklediğim yeni alanların hiçbiri burada atanmıyordu! Yani siz formu doldurup göndersiniz bile, Service katmanı bu yeni alanları umursamayıp çöpe atıyordu. </p>
<p><strong>4. &#8220;Service Katmanını Unuttuysam, Başka Neyi Unutmuş Olabilirim?&#8221; Sorusu</strong>
Service katmanındaki bu eşleştirmeyi atladığımı fark edince, kendi kendime <em>&#8220;Domain&#8217;i ve Postgres&#8217;i güncelledim ama demek ki bu modülün dışarıya bağlandığı diğer portları kontrol etmedim&#8221;</em> dedim. </p>
<p>Hemen <code>adapters/outbound</code> dizininin içine baktım. Orada sadece <code>postgres</code> olmadığını, bir de <code>mongodb</code> klasörü bulunduğunu gördüm. </p>
<p><strong>5. MongoDB&#8217;nin Yapısal Farklılığını Hatırlama ve Kontrol</strong>
Golang&#8217;de Postgres için <code>gorm</code> etiketleri kullanılır ve biz bunu <code>postgres/repository.go</code> içinde halletmiştik. Ancak MongoDB tamamen farklı bir NoSQL veritabanıdır ve verileri BSON formatında dökümanlar (documents) olarak tutar. Bu yüzden MongoDB&#8217;nin kendi struct&#8217;ları (genelde <code>bson</code> etiketlerine sahip) ve kendi Mapping (eşleştirme) fonksiyonları (<code>toDocument</code>, <code>toDomain</code>, <code>Upsert</code> işlemleri içindeki <code>bson.M{}</code>) olmak zorundaydı.</p>
<p>Hemen <code>adapters/outbound/mongodb/repository.go</code> dosyasını açıp okudum ve teorimin doğru olduğunu gördüm: Oradaki <code>DiDocument</code> struct&#8217;ında ve MongoDB&#8217;ye kayıt atan <code>Upsert</code> sorgusunda yeni alanların hiçbiri yoktu. </p>
<p><strong>Özetle:</strong>
Sizin &#8220;hata var&#8221; uyarınız derleme hatası üretmeyince, dedektif gibi verinin yaşam döngüsünü (Handler -&gt; Service -&gt; Database) adım adım izledim. Service katmanındaki kopukluğu bulunca, mimarinin diğer uç noktalarına da (MongoDB gibi) şüpheyle yaklaştım ve hatanın kök nedenini bu sistematik takip sayesinde fark ettim.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>git &#8211; Local’deki tüm tag’leri silmek için:</title>
		<link>https://selmantunc.com.tr/git/git-localdeki-tum-tagleri-silmek-icin/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 27 May 2026 21:50:52 +0000</pubDate>
				<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3551</guid>

					<description><![CDATA[Local’deki tüm tag’leri silmek için: git tag -d $(git tag) Bu komut, yerel repodaki bütün tag’leri tek seferde siler. git-scm İstersen önce hangi tag’ler olduğunu görmek için: git tag Bir&#8230;]]></description>
										<content:encoded><![CDATA[<p>Local’deki tüm tag’leri silmek için:</p>
<pre><code class="lang-bash language-bash bash">git tag -d $(git tag)</code></pre>
<p>Bu komut, yerel repodaki bütün tag’leri tek seferde siler. <a href="https://git-scm.com/docs/git-commit">git-scm</a>
İstersen önce hangi tag’ler olduğunu görmek için:</p>
<pre><code class="lang-bash language-bash bash">git tag</code></pre>
<p>Bir remote’daki tag’leri silmek farklı bir işlemdir; bu komut sadece <strong>local</strong> tag’leri kaldırır. <a href="https://git-scm.com/docs/git-commit">git-scm</a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>git commit geri al</title>
		<link>https://selmantunc.com.tr/git/git-commit-geri-al/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 27 May 2026 21:50:38 +0000</pubDate>
				<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3549</guid>

					<description><![CDATA[Son commit’i geri almak için birkaç seçenek var: Commit’i geri al, değişiklikleri stage’de tut: git reset --soft HEAD~1 Commit’i geri al, değişiklikleri working tree’de tut: git reset --mixed HEAD~1 Commit’i&#8230;]]></description>
										<content:encoded><![CDATA[<p>Son commit’i geri almak için birkaç seçenek var:</p>
<ul>
<li>
<p>Commit’i geri al, değişiklikleri stage’de tut:</p>
<pre><code class="lang-bash language-bash bash">git reset --soft HEAD~1</code></pre>
</li>
<li>
<p>Commit’i geri al, değişiklikleri working tree’de tut:</p>
<pre><code class="lang-bash language-bash bash">git reset --mixed HEAD~1</code></pre>
</li>
<li>
<p>Commit’i tamamen sil, değişiklikleri de at:</p>
<pre><code class="lang-bash language-bash bash">git reset --hard HEAD~1</code></pre>
</li>
</ul>
<p>Eğer commit’i remote’a push ettiysen, <code>reset --hard</code> yerine çoğu zaman şu daha güvenlidir:</p>
<pre><code class="lang-bash language-bash bash">git revert HEAD</code></pre>
<p><code>git commit --amend</code> ise son commit’i silmez; son commit’i düzeltmek için kullanılır. <a href="https://www.atlassian.com/git/tutorials/saving-changes/git-commit">atlassian</a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>git tag push</title>
		<link>https://selmantunc.com.tr/git/git-tag-push/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 27 May 2026 21:50:03 +0000</pubDate>
				<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3547</guid>

					<description><![CDATA[Tüm yerel tag’leri remote’a göndermek için: git push --tags Belirli bir remote’a göndermek istersen: git push origin --tags Sadece tek bir tag göndermek için: git push origin &#60;tag-adi&#62; --tags tüm&#8230;]]></description>
										<content:encoded><![CDATA[<p>Tüm yerel tag’leri remote’a göndermek için:</p>
<pre><code class="lang-bash language-bash bash">git push --tags</code></pre>
<p>Belirli bir remote’a göndermek istersen:</p>
<pre><code class="lang-bash language-bash bash">git push origin --tags</code></pre>
<p>Sadece tek bir tag göndermek için:</p>
<pre><code class="lang-bash language-bash bash">git push origin &lt;tag-adi&gt;</code></pre>
<p><code>--tags</code> tüm local tag’leri yollar; <code>--follow-tags</code> ise yalnızca commit’lerle ilişkili annotated tag’leri gönderir. <a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging">git-scm</a></p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The Domain Concept for Hexagonal Architecture in Go (Golang)</title>
		<link>https://selmantunc.com.tr/golang/the-domain-concept-for-hexagonal-architecture-in-go-golang/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 04:19:43 +0000</pubDate>
				<category><![CDATA[english]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3541</guid>

					<description><![CDATA[Here is the English version of the Go (Golang) Hexagonal Architecture example, with the same structure and explanations. 📁 Folder Structure hexagonal-go/ ├── go.mod ├── cmd/ │ └── api/ │&#8230;]]></description>
										<content:encoded><![CDATA[<p>Here is the <strong>English version</strong> of the Go (Golang) Hexagonal Architecture example, with the same structure and explanations.</p>
<hr />
<h1>📁 Folder Structure</h1>
<pre><code class="lang-text language-text text">hexagonal-go/
├── go.mod
├── cmd/
│   └── api/
│       └── main.go
└── internal/
    ├── domain/
    │   └── order/
    │       ├── money.go
    │       ├── order.go
    │       ├── order_id.go
    │       ├── order_status.go
    │       └── repository.go
    ├── application/
    │   └── order_service.go
    └── adapters/
        ├── http/
        │   └── order_handler.go
        └── persistence/
            └── memory/
                └── order_repository.go</code></pre>
<hr />
<h1>1) <code>go.mod</code></h1>
<pre><code class="lang-go language-go go">module example.com/hexagonal-go

go 1.22</code></pre>
<hr />
<h1>2) Domain Layer</h1>
<h3><code>internal/domain/order/order_id.go</code></h3>
<pre><code class="lang-go language-go go">package order

type OrderID string</code></pre>
<h3><code>internal/domain/order/order_status.go</code></h3>
<pre><code class="lang-go language-go go">package order

type OrderStatus string

const (
    OrderStatusCreated   OrderStatus = &quot;CREATED&quot;
    OrderStatusCompleted OrderStatus = &quot;COMPLETED&quot;
)</code></pre>
<h3><code>internal/domain/order/money.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;fmt&quot;

type Money struct {
    Cents int64
}

func NewMoney(cents int64) (Money, error) {
    if cents &lt; 0 {
        return Money{}, fmt.Errorf(&quot;money cannot be negative&quot;)
    }
    return Money{Cents: cents}, nil
}

func (m Money) Add(other Money) Money {
    return Money{Cents: m.Cents + other.Cents}
}</code></pre>
<h3><code>internal/domain/order/order.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;fmt&quot;

type OrderItem struct {
    ProductID string
    Quantity  int
    UnitPrice Money
}

type Order struct {
    id     OrderID
    items  []OrderItem
    status OrderStatus
}

func NewOrder(id OrderID) *Order {
    return &amp;Order{
        id:     id,
        items:  make([]OrderItem, 0),
        status: OrderStatusCreated,
    }
}

func (o *Order) ID() OrderID {
    return o.id
}

func (o *Order) Status() OrderStatus {
    return o.status
}

func (o *Order) Items() []OrderItem {
    copied := make([]OrderItem, len(o.items))
    copy(copied, o.items)
    return copied
}

func (o *Order) AddItem(productID string, quantity int, unitPrice Money) error {
    if o.status != OrderStatusCreated {
        return fmt.Errorf(&quot;order cannot be modified after completion&quot;)
    }
    if productID == &quot;&quot; {
        return fmt.Errorf(&quot;product id cannot be empty&quot;)
    }
    if quantity &lt;= 0 {
        return fmt.Errorf(&quot;quantity must be greater than zero&quot;)
    }

    o.items = append(o.items, OrderItem{
        ProductID: productID,
        Quantity:  quantity,
        UnitPrice: unitPrice,
    })

    return nil
}

func (o *Order) Complete() error {
    if len(o.items) == 0 {
        return fmt.Errorf(&quot;order must have at least one item&quot;)
    }
    o.status = OrderStatusCompleted
    return nil
}

func (o *Order) Total() Money {
    total := Money{Cents: 0}
    for _, item := range o.items {
        total = total.Add(Money{Cents: item.UnitPrice.Cents * int64(item.Quantity)})
    }
    return total
}</code></pre>
<h3><code>internal/domain/order/repository.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;context&quot;

type Repository interface {
    Save(ctx context.Context, order *Order) error
    FindByID(ctx context.Context, id OrderID) (*Order, error)
}</code></pre>
<hr />
<h1>3) Application Layer</h1>
<h3><code>internal/application/order_service.go</code></h3>
<pre><code class="lang-go language-go go">package application

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;time&quot;

    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderService struct {
    repo order.Repository
}

func NewOrderService(repo order.Repository) *OrderService {
    return &amp;OrderService{repo: repo}
}

func (s *OrderService) CreateOrder(ctx context.Context) (*order.Order, error) {
    id := order.OrderID(fmt.Sprintf(&quot;ord_%d&quot;, time.Now().UnixNano()))
    newOrder := order.NewOrder(id)

    if err := s.repo.Save(ctx, newOrder); err != nil {
        return nil, err
    }

    return newOrder, nil
}

func (s *OrderService) AddItem(ctx context.Context, orderID order.OrderID, productID string, quantity int, priceCents int64) (*order.Order, error) {
    o, err := s.repo.FindByID(ctx, orderID)
    if err != nil {
        return nil, err
    }

    price, err := order.NewMoney(priceCents)
    if err != nil {
        return nil, err
    }

    if err := o.AddItem(productID, quantity, price); err != nil {
        return nil, err
    }

    if err := s.repo.Save(ctx, o); err != nil {
        return nil, err
    }

    return o, nil
}

func (s *OrderService) CompleteOrder(ctx context.Context, orderID order.OrderID) (*order.Order, error) {
    o, err := s.repo.FindByID(ctx, orderID)
    if err != nil {
        return nil, err
    }

    if err := o.Complete(); err != nil {
        return nil, err
    }

    if err := s.repo.Save(ctx, o); err != nil {
        return nil, err
    }

    return o, nil
}

func (s *OrderService) GetOrder(ctx context.Context, orderID order.OrderID) (*order.Order, error) {
    return s.repo.FindByID(ctx, orderID)
}</code></pre>
<hr />
<h1>4) Persistence Adapter (In-Memory)</h1>
<h3><code>internal/adapters/persistence/memory/order_repository.go</code></h3>
<pre><code class="lang-go language-go go">package memory

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;sync&quot;

    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderRepository struct {
    mu     sync.RWMutex
    orders map[order.OrderID]*order.Order
}

func NewOrderRepository() *OrderRepository {
    return &amp;OrderRepository{
        orders: make(map[order.OrderID]*order.Order),
    }
}

func (r *OrderRepository) Save(ctx context.Context, o *order.Order) error {
    r.mu.Lock()
    defer r.mu.Unlock()

    r.orders[o.ID()] = o
    return nil
}

func (r *OrderRepository) FindByID(ctx context.Context, id order.OrderID) (*order.Order, error) {
    r.mu.RLock()
    defer r.mu.RUnlock()

    o, ok := r.orders[id]
    if !ok {
        return nil, fmt.Errorf(&quot;order not found: %s&quot;, id)
    }

    return o, nil
}</code></pre>
<hr />
<h1>5) HTTP Adapter</h1>
<h3><code>internal/adapters/http/order_handler.go</code></h3>
<pre><code class="lang-go language-go go">package httpadapter

import (
    &quot;encoding/json&quot;
    &quot;net/http&quot;
    &quot;strings&quot;

    &quot;example.com/hexagonal-go/internal/application&quot;
    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderHandler struct {
    service *application.OrderService
}

func NewOrderHandler(service *application.OrderService) *OrderHandler {
    return &amp;OrderHandler{service: service}
}

func (h *OrderHandler) RegisterRoutes(mux *http.ServeMux) {
    mux.HandleFunc(&quot;POST /orders&quot;, h.createOrder)
    mux.HandleFunc(&quot;GET /orders/&quot;, h.getOrder)
    mux.HandleFunc(&quot;POST /orders/{id}/items&quot;, h.addItem)
    mux.HandleFunc(&quot;POST /orders/{id}/complete&quot;, h.completeOrder)
}

func (h *OrderHandler) createOrder(w http.ResponseWriter, r *http.Request) {
    o, err := h.service.CreateOrder(r.Context())
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    respondJSON(w, http.StatusCreated, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) getOrder(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)
    o, err := h.service.GetOrder(r.Context(), order.OrderID(id))
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;items&quot;:  o.Items(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) addItem(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)

    var req struct {
        ProductID string `json:&quot;product_id&quot;`
        Quantity  int    `json:&quot;quantity&quot;`
        PriceCents int64  `json:&quot;price_cents&quot;`
    }

    if err := json.NewDecoder(r.Body).Decode(&amp;req); err != nil {
        http.Error(w, &quot;invalid json&quot;, http.StatusBadRequest)
        return
    }

    o, err := h.service.AddItem(r.Context(), order.OrderID(id), req.ProductID, req.Quantity, req.PriceCents)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) completeOrder(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)
    o, err := h.service.CompleteOrder(r.Context(), order.OrderID(id))
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func extractID(path string) string {
    parts := strings.Split(strings.Trim(path, &quot;/&quot;), &quot;/&quot;)
    if len(parts) &gt;= 2 {
        return parts[1]
    }
    return &quot;&quot;
}

func respondJSON(w http.ResponseWriter, status int, payload any) {
    w.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
    w.WriteHeader(status)
    _ = json.NewEncoder(w).Encode(payload)
}</code></pre>
<hr />
<h1>6) Application Entry Point</h1>
<h3><code>cmd/api/main.go</code></h3>
<pre><code class="lang-go language-go go">package main

import (
    &quot;log&quot;
    &quot;net/http&quot;

    httpadapter &quot;example.com/hexagonal-go/internal/adapters/http&quot;
    &quot;example.com/hexagonal-go/internal/adapters/persistence/memory&quot;
    &quot;example.com/hexagonal-go/internal/application&quot;
)

func main() {
    repo := memory.NewOrderRepository()
    service := application.NewOrderService(repo)
    handler := httpadapter.NewOrderHandler(service)

    mux := http.NewServeMux()
    handler.RegisterRoutes(mux)

    log.Println(&quot;server started on :8080&quot;)
    if err := http.ListenAndServe(&quot;:8080&quot;, mux); err != nil {
        log.Fatal(err)
    }
}</code></pre>
<hr />
<h1>7) How It Works</h1>
<ul>
<li><strong>HTTP adapter</strong> receives the request</li>
<li><strong>Application service</strong> executes the use case</li>
<li><strong>Domain</strong> applies business rules</li>
<li><strong>Repository (port)</strong> is defined in the domain</li>
<li><strong>Adapter (memory)</strong> implements it</li>
</ul>
<p>👉 The domain layer:</p>
<ul>
<li>does NOT know <code>net/http</code></li>
<li>does NOT know databases</li>
<li>does NOT know frameworks</li>
</ul>
<hr />
<h1>8) Simple Test Example</h1>
<h3><code>internal/domain/order/order_test.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;testing&quot;

func TestOrderCompleteWithoutItems(t *testing.T) {
    o := NewOrder(&quot;1&quot;)

    if err := o.Complete(); err == nil {
        t.Fatal(&quot;expected error when completing empty order&quot;)
    }
}

func TestOrderTotal(t *testing.T) {
    o := NewOrder(&quot;1&quot;)
    price, _ := NewMoney(500)

    if err := o.AddItem(&quot;p1&quot;, 2, price); err != nil {
        t.Fatal(err)
    }

    if o.Total().Cents != 1000 {
        t.Fatalf(&quot;expected 1000, got %d&quot;, o.Total().Cents)
    }
}</code></pre>
<hr />
<h1>9) Run the Project</h1>
<pre><code class="lang-bash language-bash bash">go run ./cmd/api</code></pre>
<p>Example requests:</p>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders</code></pre>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders/ord_xxx/items \
  -H 'Content-Type: application/json' \
  -d '{&quot;product_id&quot;:&quot;p1&quot;,&quot;quantity&quot;:2,&quot;price_cents&quot;:500}'</code></pre>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders/ord_xxx/complete</code></pre>
<hr />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Hexagonal Mimari için domain kavrami  Go (Golang)</title>
		<link>https://selmantunc.com.tr/software/hexagonal-mimari-icin-domain-kavrami-go-golang/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 04:18:24 +0000</pubDate>
				<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3538</guid>

					<description><![CDATA[Klasör yapısı hexagonal-go/ ├── go.mod ├── cmd/ │ └── api/ │ └── main.go └── internal/ ├── domain/ │ └── order/ │ ├── money.go │ ├── order.go │ ├── order_id.go │&#8230;]]></description>
										<content:encoded><![CDATA[<h2>Klasör yapısı</h2>
<pre><code class="lang-text language-text text">hexagonal-go/
├── go.mod
├── cmd/
│   └── api/
│       └── main.go
└── internal/
    ├── domain/
    │   └── order/
    │       ├── money.go
    │       ├── order.go
    │       ├── order_id.go
    │       ├── order_status.go
    │       └── repository.go
    ├── application/
    │   └── order_service.go
    └── adapters/
        ├── http/
        │   └── order_handler.go
        └── persistence/
            └── memory/
                └── order_repository.go</code></pre>
<hr />
<h2>1) <code>go.mod</code></h2>
<pre><code class="lang-go language-go go">module example.com/hexagonal-go

go 1.22</code></pre>
<hr />
<h2>2) Domain katmanı</h2>
<h3><code>internal/domain/order/order_id.go</code></h3>
<pre><code class="lang-go language-go go">package order

type OrderID string</code></pre>
<h3><code>internal/domain/order/order_status.go</code></h3>
<pre><code class="lang-go language-go go">package order

type OrderStatus string

const (
    OrderStatusCreated   OrderStatus = &quot;CREATED&quot;
    OrderStatusCompleted OrderStatus = &quot;COMPLETED&quot;
)</code></pre>
<h3><code>internal/domain/order/money.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;fmt&quot;

type Money struct {
    Cents int64
}

func NewMoney(cents int64) (Money, error) {
    if cents &lt; 0 {
        return Money{}, fmt.Errorf(&quot;money cannot be negative&quot;)
    }
    return Money{Cents: cents}, nil
}

func (m Money) Add(other Money) Money {
    return Money{Cents: m.Cents + other.Cents}
}</code></pre>
<h3><code>internal/domain/order/order.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;fmt&quot;

type OrderItem struct {
    ProductID string
    Quantity  int
    UnitPrice Money
}

type Order struct {
    id     OrderID
    items  []OrderItem
    status OrderStatus
}

func NewOrder(id OrderID) *Order {
    return &amp;Order{
        id:     id,
        items:  make([]OrderItem, 0),
        status: OrderStatusCreated,
    }
}

func (o *Order) ID() OrderID {
    return o.id
}

func (o *Order) Status() OrderStatus {
    return o.status
}

func (o *Order) Items() []OrderItem {
    copied := make([]OrderItem, len(o.items))
    copy(copied, o.items)
    return copied
}

func (o *Order) AddItem(productID string, quantity int, unitPrice Money) error {
    if o.status != OrderStatusCreated {
        return fmt.Errorf(&quot;order cannot be modified after completion&quot;)
    }
    if productID == &quot;&quot; {
        return fmt.Errorf(&quot;product id cannot be empty&quot;)
    }
    if quantity &lt;= 0 {
        return fmt.Errorf(&quot;quantity must be greater than zero&quot;)
    }

    o.items = append(o.items, OrderItem{
        ProductID: productID,
        Quantity:  quantity,
        UnitPrice: unitPrice,
    })

    return nil
}

func (o *Order) Complete() error {
    if len(o.items) == 0 {
        return fmt.Errorf(&quot;order must have at least one item&quot;)
    }
    o.status = OrderStatusCompleted
    return nil
}

func (o *Order) Total() Money {
    total := Money{Cents: 0}
    for _, item := range o.items {
        total = total.Add(Money{Cents: item.UnitPrice.Cents * int64(item.Quantity)})
    }
    return total
}</code></pre>
<h3><code>internal/domain/order/repository.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;context&quot;

type Repository interface {
    Save(ctx context.Context, order *Order) error
    FindByID(ctx context.Context, id OrderID) (*Order, error)
}</code></pre>
<hr />
<h2>3) Application katmanı</h2>
<h3><code>internal/application/order_service.go</code></h3>
<pre><code class="lang-go language-go go">package application

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;time&quot;

    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderService struct {
    repo order.Repository
}

func NewOrderService(repo order.Repository) *OrderService {
    return &amp;OrderService{repo: repo}
}

func (s *OrderService) CreateOrder(ctx context.Context) (*order.Order, error) {
    id := order.OrderID(fmt.Sprintf(&quot;ord_%d&quot;, time.Now().UnixNano()))
    newOrder := order.NewOrder(id)

    if err := s.repo.Save(ctx, newOrder); err != nil {
        return nil, err
    }

    return newOrder, nil
}

func (s *OrderService) AddItem(ctx context.Context, orderID order.OrderID, productID string, quantity int, priceCents int64) (*order.Order, error) {
    o, err := s.repo.FindByID(ctx, orderID)
    if err != nil {
        return nil, err
    }

    price, err := order.NewMoney(priceCents)
    if err != nil {
        return nil, err
    }

    if err := o.AddItem(productID, quantity, price); err != nil {
        return nil, err
    }

    if err := s.repo.Save(ctx, o); err != nil {
        return nil, err
    }

    return o, nil
}

func (s *OrderService) CompleteOrder(ctx context.Context, orderID order.OrderID) (*order.Order, error) {
    o, err := s.repo.FindByID(ctx, orderID)
    if err != nil {
        return nil, err
    }

    if err := o.Complete(); err != nil {
        return nil, err
    }

    if err := s.repo.Save(ctx, o); err != nil {
        return nil, err
    }

    return o, nil
}

func (s *OrderService) GetOrder(ctx context.Context, orderID order.OrderID) (*order.Order, error) {
    return s.repo.FindByID(ctx, orderID)
}</code></pre>
<hr />
<h2>4) Persistence adapter (in-memory)</h2>
<h3><code>internal/adapters/persistence/memory/order_repository.go</code></h3>
<pre><code class="lang-go language-go go">package memory

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;sync&quot;

    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderRepository struct {
    mu     sync.RWMutex
    orders map[order.OrderID]*order.Order
}

func NewOrderRepository() *OrderRepository {
    return &amp;OrderRepository{
        orders: make(map[order.OrderID]*order.Order),
    }
}

func (r *OrderRepository) Save(ctx context.Context, o *order.Order) error {
    r.mu.Lock()
    defer r.mu.Unlock()

    r.orders[o.ID()] = o
    return nil
}

func (r *OrderRepository) FindByID(ctx context.Context, id order.OrderID) (*order.Order, error) {
    r.mu.RLock()
    defer r.mu.RUnlock()

    o, ok := r.orders[id]
    if !ok {
        return nil, fmt.Errorf(&quot;order not found: %s&quot;, id)
    }

    return o, nil
}</code></pre>
<hr />
<h2>5) HTTP adapter</h2>
<h3><code>internal/adapters/http/order_handler.go</code></h3>
<pre><code class="lang-go language-go go">package httpadapter

import (
    &quot;encoding/json&quot;
    &quot;net/http&quot;
    &quot;strings&quot;

    &quot;example.com/hexagonal-go/internal/application&quot;
    &quot;example.com/hexagonal-go/internal/domain/order&quot;
)

type OrderHandler struct {
    service *application.OrderService
}

func NewOrderHandler(service *application.OrderService) *OrderHandler {
    return &amp;OrderHandler{service: service}
}

func (h *OrderHandler) RegisterRoutes(mux *http.ServeMux) {
    mux.HandleFunc(&quot;POST /orders&quot;, h.createOrder)
    mux.HandleFunc(&quot;GET /orders/&quot;, h.getOrder)
    mux.HandleFunc(&quot;POST /orders/{id}/items&quot;, h.addItem)
    mux.HandleFunc(&quot;POST /orders/{id}/complete&quot;, h.completeOrder)
}

func (h *OrderHandler) createOrder(w http.ResponseWriter, r *http.Request) {
    o, err := h.service.CreateOrder(r.Context())
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    respondJSON(w, http.StatusCreated, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) getOrder(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)
    o, err := h.service.GetOrder(r.Context(), order.OrderID(id))
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;items&quot;:  o.Items(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) addItem(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)

    var req struct {
        ProductID string `json:&quot;product_id&quot;`
        Quantity  int    `json:&quot;quantity&quot;`
        PriceCents int64  `json:&quot;price_cents&quot;`
    }

    if err := json.NewDecoder(r.Body).Decode(&amp;req); err != nil {
        http.Error(w, &quot;invalid json&quot;, http.StatusBadRequest)
        return
    }

    o, err := h.service.AddItem(r.Context(), order.OrderID(id), req.ProductID, req.Quantity, req.PriceCents)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func (h *OrderHandler) completeOrder(w http.ResponseWriter, r *http.Request) {
    id := extractID(r.URL.Path)
    o, err := h.service.CompleteOrder(r.Context(), order.OrderID(id))
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    respondJSON(w, http.StatusOK, map[string]any{
        &quot;id&quot;:     o.ID(),
        &quot;status&quot;: o.Status(),
        &quot;total&quot;:  o.Total().Cents,
    })
}

func extractID(path string) string {
    parts := strings.Split(strings.Trim(path, &quot;/&quot;), &quot;/&quot;)
    if len(parts) &gt;= 2 {
        return parts[1]
    }
    return &quot;&quot;
}

func respondJSON(w http.ResponseWriter, status int, payload any) {
    w.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
    w.WriteHeader(status)
    _ = json.NewEncoder(w).Encode(payload)
}</code></pre>
<hr />
<h2>6) Uygulama başlangıcı</h2>
<h3><code>cmd/api/main.go</code></h3>
<pre><code class="lang-go language-go go">package main

import (
    &quot;log&quot;
    &quot;net/http&quot;

    httpadapter &quot;example.com/hexagonal-go/internal/adapters/http&quot;
    &quot;example.com/hexagonal-go/internal/adapters/persistence/memory&quot;
    &quot;example.com/hexagonal-go/internal/application&quot;
)

func main() {
    repo := memory.NewOrderRepository()
    service := application.NewOrderService(repo)
    handler := httpadapter.NewOrderHandler(service)

    mux := http.NewServeMux()
    handler.RegisterRoutes(mux)

    log.Println(&quot;server started on :8080&quot;)
    if err := http.ListenAndServe(&quot;:8080&quot;, mux); err != nil {
        log.Fatal(err)
    }
}</code></pre>
<hr />
<h2>7) Akış nasıl çalışıyor?</h2>
<ul>
<li><strong>HTTP adapter</strong> isteği alır.</li>
<li><strong>Application service</strong> use-case’i yürütür.</li>
<li><strong>Domain</strong> iş kurallarını uygular.</li>
<li><strong>Repository port</strong> domain tarafından tanımlanır.</li>
<li><strong>Memory adapter</strong> bu portu implement eder.</li>
</ul>
<p>Bu yapı sayesinde domain katmanı:</p>
<ul>
<li><code>net/http</code> bilmez,</li>
<li>database bilmez,</li>
<li>framework bilmez.</li>
</ul>
<hr />
<h2>8) Kısa test örneği</h2>
<h3><code>internal/domain/order/order_test.go</code></h3>
<pre><code class="lang-go language-go go">package order

import &quot;testing&quot;

func TestOrderCompleteWithoutItems(t *testing.T) {
    o := NewOrder(&quot;1&quot;)

    if err := o.Complete(); err == nil {
        t.Fatal(&quot;expected error when completing empty order&quot;)
    }
}

func TestOrderTotal(t *testing.T) {
    o := NewOrder(&quot;1&quot;)
    price, _ := NewMoney(500)

    if err := o.AddItem(&quot;p1&quot;, 2, price); err != nil {
        t.Fatal(err)
    }

    if o.Total().Cents != 1000 {
        t.Fatalf(&quot;expected 1000, got %d&quot;, o.Total().Cents)
    }
}</code></pre>
<hr />
<h2>9) Çalıştırma</h2>
<pre><code class="lang-bash language-bash bash">go run ./cmd/api</code></pre>
<p>Örnek istek:</p>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders</code></pre>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders/ord_xxx/items \
  -H 'Content-Type: application/json' \
  -d '{&quot;product_id&quot;:&quot;p1&quot;,&quot;quantity&quot;:2,&quot;price_cents&quot;:500}'</code></pre>
<pre><code class="lang-bash language-bash bash">curl -X POST localhost:8080/orders/ord_xxx/complete</code></pre>
<hr />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>c *fiber.Ctx bunu nasil bir fonkyon icinde init ederim</title>
		<link>https://selmantunc.com.tr/golang/c-fiber-ctx-bunu-nasil-bir-fonkyon-icinde-init-ederim/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 12 Apr 2026 03:19:49 +0000</pubDate>
				<category><![CDATA[golang]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3536</guid>

					<description><![CDATA[Fiber&#8217;deki *fiber.Ctx nesnesi, bir HTTP isteği sırasında oluşan istek (request) ve yanıt (response) döngüsünü yönetir. Bu nesne sadece bir handler (yönlendirici) fonksiyonu içinde Fiber tarafından oluşturulur. Yani *fiber.Ctx nesnesini dışarıdan&#8230;]]></description>
										<content:encoded><![CDATA[<p>Fiber&#8217;deki <code>*fiber.Ctx</code> nesnesi, bir HTTP isteği sırasında oluşan <strong>istek (request)</strong> ve <strong>yanıt (response)</strong> döngüsünü yönetir. Bu nesne sadece bir handler (yönlendirici) fonksiyonu içinde <strong>Fiber tarafından oluşturulur</strong>.</p>
<p>Yani <code>*fiber.Ctx</code> nesnesini dışarıdan manuel olarak &#8220;başlatamazsınız&#8221; (instantiate edemezsiniz). Ancak, bu nesneyi ihtiyaç duyduğunuz yardımcı fonksiyonlara <strong>parametre olarak</strong> geçirebilirsiniz.</p>
<p>İşte temiz ve modüler bir mimari için uygulayabileceğiniz yöntemler:</p>
<h3>1. Yöntem: Handler İçinde Hazırlık ve Parametre Olarak Geçirme (En İyi Pratik)</h3>
<p>Handler fonksiyonu Fiber ile konuşur, ancak asıl işi yapan &#8220;Service&#8221; katmanındaki fonksiyonlara <code>*fiber.Ctx</code> yerine sadece ihtiyacı olan verileri (örneğin sadece <code>limit</code> veya <code>search</code> değerini) geçirmek en iyi yaklaşımdır.</p>
<pre><code class="lang-go language-go go">// Service Katmanı (Logic fonksiyonu)
func GetPostsFromDB(db *gorm.DB, start int, length int, search string) ([]Post, int64, error) {
    // Sadece veriyle ilgilenir, Fiber'den bağımsızdır.
    var posts []Post
    var count int64

    // İşlemler...
    return posts, count, nil
}

// Handler Katmanı
app.Get(&quot;/api/posts&quot;, func(c *fiber.Ctx) error {
    // Fiber'den verileri al
    start := c.QueryInt(&quot;start&quot;, 0)

    // Servis fonksiyonunu &ccedil;ağır
    posts, count, _ := GetPostsFromDB(db, start, 10, &quot;&quot;)

    return c.JSON(fiber.Map{&quot;data&quot;: posts, &quot;total&quot;: count})
})</code></pre>
<h3>2. Yöntem: Context&#8217;i Fonksiyona Taşımak</h3>
<p>Eğer fonksiyonun içinde <code>c.Status()</code>, <code>c.JSON()</code> veya <code>c.Params()</code> gibi Fiber özelliklerine sürekli ihtiyacınız varsa, fonksiyon imzasını şu şekilde kurabilirsiniz:</p>
<pre><code class="lang-go language-go go">func HandleRequestData(c *fiber.Ctx) error {
    // Bu fonksiyon doğrudan Fiber context'ini kullanabilir
    search := c.Query(&quot;search&quot;)

    // ... işlemler
    return c.JSON(fiber.Map{&quot;search&quot;: search})
}

// Kullanımı
app.Get(&quot;/search&quot;, HandleRequestData)</code></pre>
<h3>3. Yöntem: <code>Locals</code> Kullanımı (Veri Paylaşımı)</h3>
<p><code>*fiber.Ctx</code> içerisindeki <code>.Locals()</code> fonksiyonunu kullanarak, middleware&#8217;de başlattığınız bir veriyi (örneğin Auth bilgisi veya User ID) tüm fonksiyonlarınızda kullanabilirsiniz.</p>
<pre><code class="lang-go language-go go">// Middleware
app.Use(func(c *fiber.Ctx) error {
    c.Locals(&quot;userID&quot;, 123) // Bir kez set et
    return c.Next()
})

// İstediğiniz herhangi bir fonksiyonda
func MyHandler(c *fiber.Ctx) error {
    userID := c.Locals(&quot;userID&quot;) // Buradan al
    return c.SendString(fmt.Sprintf(&quot;User: %v&quot;, userID))
}</code></pre>
<h3>Neden <code>*fiber.Ctx</code> ile &#8220;Init&#8221; yapmamalısınız?</h3>
<ul>
<li><strong>Test Edilebilirlik:</strong> Eğer fonksiyonlarınızı <code>*fiber.Ctx</code>&#8216;e bağımlı yaparsanız, o fonksiyonu bir HTTP isteği olmadan test edemezsiniz (Unit test yazamazsınız).</li>
<li><strong>Bağımsızlık:</strong> Fonksiyonlarınızı <code>c.Query()</code>, <code>c.Params()</code> yerine doğrudan <code>int</code>, <code>string</code> gibi standart Go tiplerini kabul edecek şekilde tasarlarsanız, aynı fonksiyonu hem HTTP API&#8217;nizde hem de bir CLI komutunda veya bir background job&#8217;da değiştirmeden kullanabilirsiniz.</li>
</ul>
<p><strong>Özetle:</strong> <code>*fiber.Ctx</code> nesnesini başlatmaya çalışmayın. <code>*fiber.Ctx</code>&#8216;ten verileri çıkarın (<code>c.QueryInt</code> gibi) ve bu saf verileri kendi yazdığınız fonksiyonlara parametre olarak gönderin. </p>
<p>Bu şekilde kodunuzu &#8220;Fiber&#8217;e bağlı&#8221; olmaktan kurtarıp &#8220;saf Go kodu&#8221; haline getirmiş olursunuz. Bu yaklaşım kod tabanınızı uzun vadede çok daha sürdürülebilir kılacaktır. Başka bir katman mimarisi (Service/Repository pattern) üzerinde çalışıyor musunuz?</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>php development-environment-comparison</title>
		<link>https://selmantunc.com.tr/php/php-development-environment-comparison/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 18 Mar 2026 08:05:06 +0000</pubDate>
				<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3531</guid>

					<description><![CDATA[https://www.servbay.com/tr/pricing ServBay&#8217;in ücretsiz sürümü, ücretli Laravel Herd Pro&#8217;yu tam anlamıyla karşılayabilir. ServBay&#8217;de özel alan adları destekleniyor mu? Elbette! ServBay, özel alan &#8230;Read more I made an App like Laravel Herd.&#8230;]]></description>
										<content:encoded><![CDATA[<p><a href="https://www.servbay.com/tr/pricing">https://www.servbay.com/tr/pricing</a></p>
<p>ServBay&#8217;in ücretsiz sürümü, ücretli Laravel Herd Pro&#8217;yu tam anlamıyla karşılayabilir. ServBay&#8217;de özel alan adları destekleniyor mu? Elbette! ServBay, özel alan &#8230;Read more</p>
<blockquote class="reddit-embed-bq" style="height:316px"><a href="https://www.reddit.com/r/macapps/comments/1bctvoy/i_made_an_app_like_laravel_herd_supports_caddy/">I made an App like Laravel Herd. supports caddy, nginx, apache, php, nodejs, mysql, mariadb, postgresql, mongodb, redis, memcached&#8230;</a><br> by<a href="https://www.reddit.com/user/PhpWebStudy/">u/PhpWebStudy</a> in<a href="https://www.reddit.com/r/macapps/">macapps</a></blockquote>

<p><a href="https://dudi.dev/laravel-development-environment-comparison">https://dudi.dev/laravel-development-environment-comparison</a></p>
<blockquote class="wp-embedded-content" data-secret="YOKpcu9dnp"><a href="https://selmantunc.com.tr/uncategorized/macos-valet-install/">macos valet install</a></blockquote>
<iframe class="wp-embedded-content" title="“macos valet install” — Selman Tunc" src="https://selmantunc.com.tr/uncategorized/macos-valet-install/embed/#?secret=eNrwc1OYev#?secret=YOKpcu9dnp" width="600" height="338" frameborder="0"></iframe>
<p>laravel valet </p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Chrome Security and Passive Mode Risks</title>
		<link>https://selmantunc.com.tr/software/chrome-security-and-passive-mode-risks/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 05 Mar 2026 07:06:24 +0000</pubDate>
				<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3527</guid>

					<description><![CDATA[No, technically, a completely disabled (deactivated) Chrome extension cannot steal new information or monitor your current browsing activity. When an extension is disabled, it is not loaded into the browser&#8217;s&#8230;]]></description>
										<content:encoded><![CDATA[<p>No, technically, a completely <strong>disabled</strong> (deactivated) Chrome extension cannot steal new information or monitor your current browsing activity. When an extension is disabled, it is not loaded into the browser&#8217;s memory and its background processes are terminated. <a href="https://support.google.com/chrome/thread/11119336/can-chrome-extensions-affect-computer-performance-even-if-they-are-turned-off?hl=en">support.google</a></p>
<p>However, there are two critical security nuances to consider:</p>
<h3>Residual Risks in Open Tabs</h3>
<p>If a malicious extension was active and you disabled it while having several tabs open, its &#8220;content scripts&#8221; might still be running in those specific pages until they are refreshed. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></p>
<ul>
<li>These scripts could potentially leak data through indirect methods like hidden images or CSS if the site&#8217;s Content Security Policy (CSP) is weak. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></li>
<li><strong>Solution:</strong> You must refresh all open tabs or restart your browser after disabling an extension to ensure all its scripts are fully cleared. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></li>
</ul>
<h3>Previously Stolen Data</h3>
<p>Disabling an extension only stops <strong>future</strong> data collection; it does not &#8220;undo&#8221; what was already stolen while the extension was active. <a href="https://www.youtube.com/watch?v=Rhxz_i8rDcM">youtube</a></p>
<ul>
<li>If a malicious extension captured your passwords, session cookies, or personal data while it was enabled, that information is likely already stored on the attacker&#8217;s server (C2 server). <a href="https://www.linkedin.com/pulse/warning-malicious-chrome-extensions-steal-your-gtrae">linkedin</a></li>
<li>Attackers often use stolen session tokens to maintain access to your accounts even after the extension is deleted. <a href="https://thehackernews.com/2026/02/malicious-chrome-extensions-caught.html">thehackernews</a></li>
</ul>
<h3>Extension Status Comparison</h3>
<p>The following table illustrates the capabilities of an extension based on its state:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Status</th>
<th style="text-align: left">Web Page Access</th>
<th style="text-align: left">Real-time Data Leak</th>
<th style="text-align: left">Historical Data Risk</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><strong>Enabled</strong></td>
<td style="text-align: left">Full Access  <a href="https://www.reddit.com/r/chrome/comments/1ckcd1s/can_chrome_extensions_scrape_my_pages_and_steal/">reddit</a></td>
<td style="text-align: left">High  <a href="https://www.youtube.com/watch?v=Rhxz_i8rDcM">youtube</a></td>
<td style="text-align: left">Continuous Access</td>
</tr>
<tr>
<td style="text-align: left"><strong>Disabled</strong></td>
<td style="text-align: left">Blocked  <a href="https://support.google.com/chrome/thread/11119336/can-chrome-extensions-affect-computer-performance-even-if-they-are-turned-off?hl=en">support.google</a></td>
<td style="text-align: left">Very Low (Residual)</td>
<td style="text-align: left">Stored on External Server</td>
</tr>
<tr>
<td style="text-align: left"><strong>Removed</strong></td>
<td style="text-align: left">Impossible</td>
<td style="text-align: left">Impossible</td>
<td style="text-align: left">Stored on External Server</td>
</tr>
</tbody>
</table>
<p>If you suspect an extension is malicious, simply disabling it is not enough. You should <strong>remove</strong> it entirely, clear your browser cookies, and change your passwords for sensitive accounts. <a href="https://support.google.com/chrome/thread/306226825/chrome-extensions-might-steal-passwords?hl=en">support.google</a></p>
<p>Which specific extension are you concerned about?</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Google Chrome&#8217;da bir eklentiyi tamamen devre dışı (deactive) birakinca bilgi calabilir mi?</title>
		<link>https://selmantunc.com.tr/software/google-chromeda-bir-eklentiyi-tamamen-devre-disi-deactive-birakinca-bilgi-calabilir-mi/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 05 Mar 2026 07:05:31 +0000</pubDate>
				<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://selmantunc.com.tr/?p=3525</guid>

					<description><![CDATA[Hayır, Google Chrome&#8217;da bir eklentiyi tamamen devre dışı (deactive) bırakmak, o eklentinin yeni veri toplamasını veya çalmasını teknik olarak engeller. Eklenti pasif durumdayken tarayıcı belleğine yüklenmez ve web sayfalarındaki trafiğinize&#8230;]]></description>
										<content:encoded><![CDATA[<p>Hayır, Google Chrome&#8217;da bir eklentiyi tamamen devre dışı (deactive) bırakmak, o eklentinin yeni veri toplamasını veya çalmasını teknik olarak engeller. Eklenti pasif durumdayken tarayıcı belleğine yüklenmez ve web sayfalarındaki trafiğinize müdahale edemez. <a href="https://support.google.com/chrome/thread/11119336/can-chrome-extensions-affect-computer-performance-even-if-they-are-turned-off?hl=en">support.google</a></p>
<p>Ancak güvenlik açısından dikkat edilmesi gereken iki önemli istisna bulunmaktadır:</p>
<h3>Aktif Sekmelerdeki Kalıntı Riskler</h3>
<p>Bir eklentiyi devre dışı bıraktığınız an, o sırada açık olan sekmelerde halihazırda enjekte edilmiş olan &#8220;içerik betikleri&#8221; (content scripts) çalışmaya devam edebilir. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></p>
<ul>
<li>Bu betikler eklenti merkezine veri gönderemez ancak sitenin kendi güvenlik politikası (CSP) zayıfsa, verileri gizli görseller veya CSS üzerinden dışarı sızdırmaya çalışabilir. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></li>
<li><strong>Çözüm:</strong> Eklentiyi kapattıktan sonra açık olan tüm sekmeleri yenilemek (Refresh) bu riski tamamen ortadan kaldırır. <a href="https://stackoverflow.com/questions/69368249/what-data-is-accessible-to-a-disabled-chrome-extension">stackoverflow</a></li>
</ul>
<h3>Geçmişte Toplanan Veriler</h3>
<p>Eklentinin devre dışı bırakılması sadece gelecekteki veri akışını keser.</p>
<ul>
<li>Eğer eklenti aktif olduğu süre boyunca şifrelerinizi, çerezlerinizi (cookies) veya kişisel verilerinizi uzak bir sunucuya (C2 server) gönderdiyse, bu veriler saldırganın elinde kalmaya devam eder. <a href="https://www.youtube.com/watch?v=Rhxz_i8rDcM">youtube</a></li>
<li>Kötü niyetli eklentiler genellikle oturum jetonlarını (session tokens) çalarak, siz eklentiyi silseniz bile hesaplarınıza erişim sağlamaya devam edebilir. <a href="https://www.linkedin.com/pulse/warning-malicious-chrome-extensions-steal-your-gtrae">linkedin</a></li>
</ul>
<h3>Güvenli Kullanım Tablosu</h3>
<p>Eklenti durumuna göre yetki ve risk dağılımı şu şekildedir:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Durum</th>
<th style="text-align: left">Web Sayfası Okuma</th>
<th style="text-align: left">Veri Sızdırma</th>
<th style="text-align: left">Geçmiş Veri Erişimi</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><strong>Aktif</strong></td>
<td style="text-align: left">Tam Yetki  <a href="https://www.reddit.com/r/chrome/comments/1ckcd1s/can_chrome_extensions_scrape_my_pages_and_steal/">reddit</a></td>
<td style="text-align: left">Mümkün  <a href="https://www.youtube.com/watch?v=Rhxz_i8rDcM">youtube</a></td>
<td style="text-align: left">Sürekli Erişim</td>
</tr>
<tr>
<td style="text-align: left"><strong>Devre Dışı</strong></td>
<td style="text-align: left">Engellenir  <a href="https://support.google.com/chrome/thread/11119336/can-chrome-extensions-affect-computer-performance-even-if-they-are-turned-off?hl=en">support.google</a></td>
<td style="text-align: left">Çok Düşük (Kalıntı Betik)</td>
<td style="text-align: left">Saldırganın Sunucusunda Saklı</td>
</tr>
<tr>
<td style="text-align: left"><strong>Kaldırılmış</strong></td>
<td style="text-align: left">İmkansız</td>
<td style="text-align: left">İmkansız</td>
<td style="text-align: left">Saldırganın Sunucusunda Saklı</td>
</tr>
</tbody>
</table>
<p>Şüphelendiğiniz bir eklenti varsa sadece devre dışı bırakmak yerine doğrudan <strong>kaldırmanız</strong> ve ardından tarayıcı çerezlerini temizleyerek şifrelerinizi değiştirmeniz en güvenli yoldur. <a href="https://thehackernews.com/2026/02/malicious-chrome-extensions-caught.html">thehackernews</a></p>
<p>Hangi eklenti hakkında bu endişeyi taşıyorsunuz?</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
