Mert
Kuveyt Sivil Havacılık Kurumu: Havalimanına İHA'larla düzenlenen saldırıda radar sistemleri zarar gördü
YAPAY ZEKANIN ETİK SINAVI – Görsel medyadaki manipülatif içeriklerin tespitinde sorumluluk şirketlere düşüyor
Telefonlarda 5G'yi kullanabilmek için şebeke ayarı gerekiyor
OLED monitörler yaygınlaşıyor: En çok satan markalar açıklandı
OLED monitör pazarı 2025’te yüzde 92 büyüdü. Asus liderliğe yükselirken, Samsung ve MSI gibi markalar da rekabeti artırmaya devam ediyor. İşte en çok satan markalar…Selection Through the Looking Glass: A 3D Stack Component for Mantine
A Mantine component that turns flat item selection into a spatial, 3D card-stack browsing experience — with keyboard, wheel, touch, and click navigation built in.
Introduction
Remember the first time you used macOS Time Machine? That moment when your desktop peeled away into an infinite corridor of snapshots, and navigating through time suddenly felt physical. That spatial metaphor stuck with us. mantine-depth-select brings that same sense of depth to any selection UI in your React application — pricing plans, document versions, onboarding steps, or anything else where browsing through stacked content beats scrolling a flat list. It’s a single component with zero extra dependencies, built entirely on Mantine 8’s Styles API.
What is DepthSelect?
DepthSelect renders an array of items as a 3D stack of cards. The frontmost card is the active selection; cards behind it recede with progressive scale, vertical offset, opacity, and blur — all configurable per-level. When the user navigates (via keyboard, mouse wheel, trackpad swipe, click, or arrow controls), cards animate smoothly in and out of the stack with CSS transitions.
The component follows Mantine’s compound component pattern. Built-in arrow controls appear by default, but you can hide them and wire up your own UI through controlled value/onChange. It supports both string and numeric values, loop mode, and respects prefers-reduced-motion.
✨ Key Features
3D Perspective Stack
Each card in the stack receives progressive CSS transforms based on its depth. Four props control the effect:
<DepthSelect
data={items}
scaleStep={0.1} // scale reduction per level (default)
translateYStep={30} // vertical offset in px per level
opacityStep={0.15} // opacity reduction per level
blurStep={1} // blur in px per level
w={400}
h={300}
/>
Cards that exit the stack (when navigating forward) animate toward the viewer with a scale-up and fade-out. Cards entering from behind animate in from the deepest visible position.
Multi-Input Navigation
Every common input method works out of the box:
-
Keyboard:
ArrowUp/ArrowDownto step through,Home/Endto jump -
Mouse wheel / Trackpad: Scroll over the component to navigate (page scroll is blocked automatically). Disable with
withScrollNavigation={false} - Touch: Vertical swipe gestures for mobile
- Click: Click the second card (depth 1) to advance
- Controls: Built-in arrow buttons with optional label
Built-in Controls with controlsProps
The default controls sit to the right of the stack. You can reposition them, add a label, set a fixed width, change alignment, or swap the icons — all through a single controlsProps object:
<DepthSelect
data={items}
controlsPosition="left"
controlsProps={{
w: 100,
justify: 'end',
labelFormatter: (item) => `Step ${item.value}`,
upIcon: <IconChevronUp size={16} />,
downIcon: <IconChevronDown size={16} />,
}}
w={400}
h={300}
/>
Compound Component Pattern
Need full layout control? Set withControls={false} and use DepthSelect.Controls as a child:
<DepthSelect data={items} withControls={false} w={400} h={300}>
<DepthSelect.Controls labelFormatter={(item) => String(item.value)} />
</DepthSelect>
Or skip the built-in controls entirely and build your own navigation with value and onChange.
Loop Mode
Enable loop to let navigation wrap from the last item back to the first (and vice versa). The arrow controls never show a disabled state in loop mode:
<DepthSelect data={items} loop w={400} h={200} />
🚀 Getting Started
npm install @gfazioli/mantine-depth-select
Import the styles at the root of your application:
import '@gfazioli/mantine-depth-select/styles.css';
Minimal example:
import { Card, Text } from '@mantine/core';
import { DepthSelect, DepthSelectItem } from '@gfazioli/mantine-depth-select';
const data: DepthSelectItem[] = [
{ value: 'first', view: <Card p="lg" withBorder h="100%"><Text>First item</Text></Card> },
{ value: 'second', view: <Card p="lg" withBorder h="100%"><Text>Second item</Text></Card> },
{ value: 'third', view: <Card p="lg" withBorder h="100%"><Text>Third item</Text></Card> },
];
function Demo() {
return <DepthSelect data={data} w={400} h={200} />;
}
The w and h props define the area where cards live. Cards should use h="100%" to fill the available height.
Props & API
DepthSelect
-
data—DepthSelectItem[]— Array of{ value, view }objects.valuecan bestringornumber,viewis anyReactNode -
value/defaultValue/onChange— Standard controlled/uncontrolled pattern -
w/h— Dimensions of the card area (passed to the inner stack container) -
visibleCards— Number of cards visible in the stack (default:4) -
withControls— Show built-in arrow controls (default:true) -
controlsPosition—"right"(default) or"left" -
controlsProps— AllDepthSelectControlsPropspassed to the built-in controls -
loop— Enable wrap-around navigation (default:false) -
withScrollNavigation— Enable mouse wheel / trackpad navigation (default:true) -
transitionDuration— Animation duration in ms (default:400) -
scaleStep/translateYStep/opacityStep/blurStep— Per-level depth effect parameters
DepthSelect.Controls
-
labelFormatter—(item: DepthSelectItem) => ReactNode— Custom label between arrows -
upIcon/downIcon— Custom icons for the arrow buttons -
justify— Vertical alignment:"start","center"(default),"end" - Plus all Mantine
BoxProps(w,h,style, etc.)
🎨 Styles API
Selectors: root, stack, card, controls, controlUp, controlDown, controlLabel
Data attributes:
-
data-active— Frontmost (selected) card -
data-depth="N"— Card depth level (0 = front) -
data-exited— Card that has animated out -
data-disabled— Disabled control button -
data-controls-position—"right"or"left"on root
CSS variables: --ds-transition-duration, --ds-scale-step, --ds-translate-y-step, --ds-opacity-step, --ds-blur-step, --ds-visible-cards
⚡ Performance
-
Render window: Only
activeIndex - 1throughactiveIndex + visibleCards + 1are in the DOM. A dataset of 100 items renders ~6 nodes -
Memoized styles: Card CSS is computed once per navigation change via
useMemo -
Targeted
will-change: Only visible cards get GPU layer promotion; hidden cards usewill-change: auto - Non-passive wheel listener: Blocks page scroll without layout thrashing
-
prefers-reduced-motion: Transitions are disabled automatically for users who prefer reduced motion
Live Demo & Documentation
Explore interactive demos — including a configurator with live props, rich card examples, pricing plan selector, version history browser, onboarding wizard, and more:
gfazioli.github.io/mantine-depth-select
Links
- 📦 npm: @gfazioli/mantine-depth-select
- 📖 Docs: gfazioli.github.io/mantine-depth-select
- 🔗 GitHub: github.com/gfazioli/mantine-depth-select
- 🧩 Mantine Extensions: mantine-extensions.vercel.app
Data Modeling in Power BI: Joins, Relationships, and Schemas Explained
Data modeling is where raw data becomes usable intelligence. In Power BI, it’s not a preliminary step you rush through. It’s the architectural foundation that determines whether your reports are fast or sluggish, your DAX is clean or convoluted, and your numbers are right or wrong.
Under the hood, Power BI runs the Analysis Services VertiPaq engine, an in-memory columnar database that relies on structured relationships and compressed tables to aggregate millions of rows quickly. A well-built model means near-instant visualizations and precise DAX calculations. A poorly built one means slow performance, memory exhaustion, circular dependencies, and incorrect results.
This article covers the full landscape: Fact vs. Dimension tables, Star/Snowflake/Flat Table schemas, all six Power Query join types with practical scenarios, Power BI relationship configuration (cardinality, cross-filter direction, active/inactive states), role-playing dimensions, and common modeling pitfalls like ambiguous paths and circular dependencies.
Fact Tables vs. Dimension Tables
Every optimized analytical model starts by separating data into two types: Fact tables (the numbers) and Dimension tables (the context). This separation is the cornerstone of dimensional modeling, and VertiPaq is specifically designed to leverage it. Mixing quantitative metrics with descriptive text in a single table compromises compression efficiency and query speed.
Fact Tables
Fact tables hold the quantitative metrics, measurements, and transactional events generated by a business process. They represent the numerical reality of what happened: how much was sold, how many units shipped, what discount was applied.
Structurally, Fact tables have a massive number of rows (potentially hundreds of millions) but a narrow column footprint. They contain two types of columns: Foreign Keys (integer-based IDs like EmployeeID, StoreID, DateKey that link back to Dimension tables) and Numeric Measures (the actual values being aggregated: Transaction_Amount, Units_Sold, Discount_Applied).
One critical principle: every Fact table must have a consistent grain. The grain defines what a single row represents. “One row per product sold per receipt per store,” for example. Mixing grains (daily transactions alongside monthly aggregates in the same table) causes double-counting and forces convoluted DAX to resolve.
Dimension Tables
Dimension tables provide the qualitative context that makes the numbers meaningful. They answer “who,” “where,” “what,” and “why.” Customers, Products, Sales Representatives, Geographic Regions.
Structurally, they’re the inverse of Fact tables: relatively few rows but many columns. A Customer dimension might have 100,000 rows but 80 columns capturing everything from First_Name to Lifetime_Value_Tier to Acquisition_Channel. Every Dimension table needs a Primary Key (a column with strictly unique values) that matches the Foreign Key in the Fact table.
When an analyst drags Region_Name onto a chart axis, they’re using a Dimension table attribute to slice the raw numeric data in the Fact table. That’s the entire relationship in action.
Schemas: Star, Snowflake, and Flat Table
The spatial arrangement and normalization level connecting Facts and Dimensions defines your schema. Your choice directly impacts VertiPaq performance, model memory footprint, and DAX complexity.
Star Schema (the Gold Standard)
The Star Schema is universally recommended for Power BI. It features a single, compressed central Fact table surrounded by multiple Dimension tables, each joined directly via a simple one-to-many relationship. No intermediate lookup tables, no secondary dimension branches, no complex relationship chains.
To achieve this, Dimension tables are deliberately denormalized during data preparation. Instead of separate tables for Product, Product_Subcategory, and Product_Category, everything collapses into a single Product dimension.
Why this works so well in Power BI:
Performance. Only one relationship “hop” from any dimension attribute to the fact data. VertiPaq is engineered to traverse these single-tier relationships with maximum efficiency.
Simple DAX. Filter context flows cleanly from dimension slicer to Fact table. No need for complex filter-modification functions.
Intuitive for users. One business entity equals one table. Self-service report authors don’t get lost.
The trade-off is data redundancy: a long string like “Industrial Manufacturing Equipment” might repeat across thousands of product rows. But VertiPaq handles this through dictionary encoding, storing the string once and using a tiny integer reference everywhere else. The theoretical storage penalty is virtually eliminated in memory.
Snowflake Schema
A Snowflake Schema normalizes one or more Dimension tables into hierarchical sub-tables. Instead of one Product table, you get Product joined to Product_Subcategory joined to Product_Category, branching outward.
The advantage is storage efficiency and strict data conformity. The disadvantage in Power BI is severe: multi-hop traversal degrades reporting performance, and DAX authoring gets significantly more complex. Filters must propagate through intermediate tables, leading to unexpected behaviors and potential ambiguous pathway errors.
The universal recommendation: use Power Query to merge and denormalize Snowflake structures into a Star Schema before loading into the model.
Flat Table (DLAT / “One Big Table”)
The Flat Table abandons Fact/Dimension separation entirely, joining everything into a single massive table with potentially hundreds of columns.
In Power BI Import mode, this is a severe anti-pattern. Appending text-heavy dimensional attributes alongside millions of transaction rows causes catastrophic data duplication, bloats the in-memory cache, slows refreshes, and complicates DAX. Overriding filter context on a single attribute in a Star Schema is trivial (CALCULATE([Measure], ALL('Product'))). In a Flat Table, you must list every column individually.
There is one legitimate exception: DirectQuery mode. When Power BI passes DAX as SQL queries to a backend warehouse (Snowflake, BigQuery, Databricks), a pre-joined materialized Flat Table eliminates runtime SQL JOINs, which can be computationally expensive. In this specific scenario, a DLAT can yield faster visual rendering. For Import mode (the vast majority of implementations), Star Schema remains the imperative.
Power Query Joins: Combining Data at the Source Layer
Before data enters VertiPaq, it’s extracted, cleaned, and transformed in Power Query. Joins (merges) in Power Query are physical operations: they permanently combine columns from two tables based on matching keys during ETL. This is fundamentally different from Power BI Relationships, which are virtual, dynamic filter mechanisms applied in memory during user interaction.
Power Query supports six join types, all derived from standard SQL relational algebra.
1. Inner Join
Returns only rows with matching keys in both tables. Unmatched rows from either side are discarded.
Scenario: Sales analysis limited to currently active employees. Inner Join on EmployeeID drops sales records tied to terminated employees and active employees with no sales.
2. Left Outer Join
The most commonly used join for data modeling. Preserves all rows from the left table. Matching rows from the right table are appended; unmatched left rows get null values in the right-table columns.
Scenario: A Customer master list enriched with campaign responses. Customers who didn’t respond still appear with null in the feedback columns.
3. Right Outer Join
The inverse: preserves all rows from the right table, appending only matching rows from the left.
Scenario: Ensuring all new products from a supplier catalog appear in your model, even if no sales exist yet.
4. Full Outer Join
Preserves all rows from both tables. Matched rows are combined; unmatched rows from either side are retained with null values for the missing columns.
Scenario: Reconciling employee records across two separate HR systems. Every employee from both systems appears, with gaps showing where records don’t align.
5. Left Anti Join (“Rows only in first”)
Returns strictly the rows from the left table that have no match in the right table. Every matched row is discarded.
Scenario: Generating a list of campaign targets who haven’t been contacted yet. Left Anti Join subtracts contacted customers from the target list.
6. Right Anti Join (“Rows only in second”)
Returns strictly the rows from the right table that have no match in the left table.
Scenario: Comparing a digital inventory system against a physical warehouse audit. Right Anti Join reveals items found on the warehouse floor that don’t exist in the system, flagging undocumented overstock or data entry failures.
Step-by-Step: Merging in Power Query
- From the Home ribbon in Power BI Desktop, click Transform data to open Power Query Editor.
- In the Queries pane, select the table that will act as the Left (primary) table.
- On the Home ribbon, in the Combine group, click Merge Queries (or “Merge Queries as New” to preserve originals).
- In the Merge dialog, click the matching column header(s) in the Left table preview. Select the Right table from the dropdown, then click its matching column header(s).
- Select your Join Kind from the dropdown at the bottom.
- Power Query shows an estimated match count. Validate, then click OK.
- The merge adds a column of nested
Tableobjects. Click the expand icon (divergent arrows) in the column header, select which columns to flatten, and click OK. - Click Close & Apply to load the result into VertiPaq.
Power BI Relationships: The Semantic Layer
While Power Query joins weld data together during ETL, Relationships are virtual, logical connections established post-load. They propagate filter context between tables. Selecting “2024” in a Date slicer generates a filter that travels down the relationship pathway to isolate matching rows in the Fact table.
Important: Power BI relationships do not enforce data integrity (no prevention of orphan records, no cascading deletes like SQL). They define filter propagation rules only.
Cardinality
One-to-Many (1:) / Many-to-One (:1): The same relationship viewed from opposite sides. The “one” side is the Primary Key (unique values in the Dimension); the “many” side is the Foreign Key (duplicates in the Fact). This is the structural glue of the Star Schema and the optimal relationship type.
One-to-One (1:1): Both columns contain unique values. Rare, and often indicates the tables should be merged into one. Legitimate exceptions: isolating columns for row-level security or separating rarely-queried wide text columns to save memory.
Many-to-Many (:): Both columns contain duplicates. Common in scenarios like students enrolled in multiple courses. Connecting two many-to-many dimensions directly causes extreme ambiguity and incorrect aggregations. The solution is a Bridge Table (junction table) capturing every unique combination, transforming the relationship into two predictable one-to-many connections.
Cross-Filter Direction
Single Direction (default and recommended). Filters flow from the Dimension (“one” side) down to the Fact (“many” side). A single arrowhead on the relationship line, pointing toward the Fact.
Both Directions (bi-directional). Filters flow both ways. Denoted by a double arrowhead. Occasionally necessary (dynamically shrinking a slicer list, propagating across Bridge tables), but deploy with extreme caution. Indiscriminate bi-directional filtering forces massive cross-table permutations and is the leading cause of ambiguous path errors.
Active vs. Inactive Relationships
Power BI allows multiple relationships between the same two tables but enforces that only one can be Active at a time.
Active (solid line): the default filter path. Standard DAX measures use this automatically.
Inactive (dashed line): dormant until explicitly invoked via USERELATIONSHIP() in a DAX measure.
Step-by-Step: Creating Relationships
Method 1: Model View. Click the network icon on the left nav to open the Model View canvas. Click and drag a Primary Key column from the Dimension table to the Foreign Key column in the Fact table. Power BI auto-detects cardinality and cross-filter direction. Double-click the line to edit.
Method 2: Manage Relationships Dialog. From the Modeling tab, click Manage relationships > New. Select tables and columns from dropdowns, review the auto-detected settings, confirm the “Make this relationship active” checkbox, and click OK.
Joins vs. Relationships: When to Use Which
| Feature | Power Query Join (Physical) | Power BI Relationship (Logical) |
|---|---|---|
| What it does | Physically combines columns into one table | Virtual connection for dynamic filter propagation |
| When it runs | During ETL/data refresh | In-memory at query time during user interaction |
| Memory impact | Can inflate row counts and duplicate text strings | Maintains compressed, narrow tables |
| Flexibility | Static until next refresh | Dynamic; can toggle via DAX (USERELATIONSHIP, CROSSFILTER) |
| Best use case | Denormalizing Snowflake to Star; appending columns from tiny lookups | Building Star Schemas; connecting Fact to Dimension tables |
The rule: for Import mode, rely on Relationships to build a Star Schema. Use Power Query joins to flatten hyper-normalized data or append a few columns from minor lookup tables. Don’t join everything into a Flat Table in Import mode.
Role-Playing Dimensions
A classic challenge: a single Dimension table needs multiple roles. A Date table relating to a Sales fact might connect on OrderDate, ShipDate, and DeliveryDate. Power BI only allows one active relationship between any two tables, so you get one solid line and two dashed lines.
Option 1: Duplicate the Dimension
Use Power Query to reference and duplicate the Date table into independent Order_Date, Ship_Date, and Delivery_Date tables. Each gets its own active relationship.
Pros: Intuitive for self-service users. Easy to visualize two roles simultaneously on one chart.
Cons: Inflates the model. Duplicating a small Date table (3,650 rows) is negligible. Duplicating a multi-million row Customer table (acting as both BillTo and ShipTo) is costly.
Option 2: USERELATIONSHIP() in DAX
Keep one Dimension table with one active relationship. Author DAX measures that temporarily activate the inactive paths:
Sales_by_ShipDate =
CALCULATE(
SUM(Sales[Amount]),
USERELATIONSHIP('Date'[Date], Sales[ShipDate])
)
Pros: Minimal model size. Single source of truth.
Cons: Every metric for a secondary role needs its own measure. Analyzing two roles in the same visual requires advanced DAX.
General guideline: duplicate small lookup tables; use USERELATIONSHIP() for large dimensions.
Common Modeling Pitfalls
Ambiguous Paths
These errors occur when VertiPaq detects multiple possible routes for a filter to travel between two tables. The engine can’t guess which path you intended, so it throws an error or disables relationships.
The most common cause: reckless bi-directional filtering across multiple tables, creating loops that interact with existing single-direction paths. Another cause: a shared parent dimension (like Location) filtering both Customer and Store, which both filter the same Sales Fact, creating competing parallel paths.
Fix: return to strict Star Schema architecture. Use single-direction, one-to-many relationships exclusively. If Bridge tables are required, enable bi-directional filtering on only one side. Better yet, disable bi-directional filtering globally and manage it via the CROSSFILTER DAX function only where explicitly needed.
Circular Dependencies
A circular dependency is an infinite computational loop: Object A requires Object B, but Object B requires Object A. Power BI detects this and blocks the operation.
These rarely come from obvious formulas. They typically emerge from context transition in Calculated Columns. When a Calculated Column uses CALCULATE(), DAX transforms the current row context into a filter context, making the column depend on all other columns in the table. A second Calculated Column using CALCULATE() in the same table creates a mutual dependency lock.
Fixes:
- Switch to a Measure. Measures evaluate dynamically at query time, bypassing the row-level context transition issue entirely.
-
Exclude conflicting columns. Use
ALLEXCEPT()orREMOVEFILTERS()to strip the dependency. - Move the logic upstream. Perform complex row-level arithmetic in Power Query or the source database before VertiPaq ever sees it.
Power BI data modeling rewards discipline. Star Schema, clean cardinality, single-direction filtering, and deliberate separation of physical joins from logical relationships. Get those fundamentals right and everything downstream (DAX, performance, user adoption) gets dramatically easier. The article was submitted in fulfilment of a LuxDevHQ Cohort 7 DataEngieering assignment ©adev3loper
What AI Actually Changed About My Work as a Technical Writer
For me, the most frustrating part of technical writing was never the writing.
It was the waiting.
Waiting for a subject matter expert to have a free hour. Waiting for a developer to confirm whether something changed between releases. The information existed. It just lived in someone else’s head, or somewhere in a codebase I wasn’t expected to touch.
To be fair, waiting wasn’t always the only option. I’ve always preferred finding things out for myself, digging into a ticket, tracing a thread, unblocking my own work rather than sitting on a question. But self-directed digging has its own cost. It takes time, it can send you down the wrong path, and without the right tools it’s easy to spend an hour finding half an answer. The codebase was there. I just didn’t have a good way in.
That changed when my team started experimenting with AI-assisted documentation workflows.
Where I started
I didn’t build the workflow. I was asked to test it.
A colleague had been developing an AI-assisted approach to documentation and brought me in to try it, break it, and help refine it before we rolled it out to the wider team. That process taught me more about how AI actually works in practice than any course I’ve taken.
The core idea was straightforward. Instead of waiting for a developer to explain a feature, we used AI tools to investigate the codebase directly. Read the source. Check the specs. Cross-reference existing documentation. Then plan what to write before touching a single file.
Refining the workflow felt a lot like optimizing a character build in a game. You start with what you have, figure out what works, pick up better tools along the way, and keep tweaking until the whole thing plays smoothly. There’s no perfect final state. You just keep improving the build.
What I noticed
Three things stood out.
The first was speed. Not because AI writes faster, but because the back-and-forth shrinks. Fewer dependency chains. Less time blocked waiting for input that may or may not arrive before the deadline.
The second was confidence. I could start a piece of work with a clearer picture of what I was walking into. Instead of beginning from a blank page and a vague (sometimes even empty, shocker, I know) ticket description, I had a verified starting point grounded in what the code actually does. That changes how you work.
The third was autonomy. I could start work on a ticket without needing anyone’s permission or availability. That shift is harder to explain than it sounds. After years of structuring your work around other people’s calendars, being able to just start is genuinely different.
What I also learned
Three things here too, and none of them are about prompting.
The first is that AI-assisted workflows are only as good as the information they work with. Garbage in, garbage out. If the source material is incomplete or inconsistent, the output reflects that. You still need to know what good documentation looks like. You still need to catch what the AI misses. Judgment doesn’t go away. It just gets applied differently.
The second is that critical thinking becomes more important, not less. You’re not just reviewing writing anymore. You’re reviewing claims. Every output needs to be read with the question: is this actually true, or does it just sound true? AI doesn’t flag uncertainty the way a careful human writer might. It states things. Confidently. Whether they’re correct or not. In an age where misinformation spreads faster than corrections, accuracy and fact-checking are non-negotiable. That doesn’t change just because the content came from an AI. If anything, it becomes more important.
The third is that domain knowledge and attention to detail are not optional. They’re your last line of defense. AI will describe a configuration property that doesn’t exist, get the behavior of an endpoint backwards, and do it in perfect sentences. It also skips style rules, not always because it doesn’t know them, but because context window limits or what I can only describe as selective laziness means it stops applying them mid-document. Directional language, incorrect linking patterns, inconsistent terminology. If you don’t know the subject matter well enough to catch a wrong answer, or the style guide well enough to catch a broken rule, those errors walk straight out the door into your published docs.
Where I think this is going
Technical writing is changing. The role is shifting from producing content to something broader: building the gates, constraints, and workflows that ensure content is accurate before it ever reaches a reader.
The core purpose stays the same. Technically accurate content, usable by a specific audience. But the way we get there is different.
I started this by talking about waiting. Waiting for the right person, the right meeting, the right moment to get unblocked. What I’ve learned is that the writers who thrive won’t be the ones who wait less. They’ll be the ones who bring more to the table when they show up: domain knowledge, critical thinking, a sharp eye for detail, and the ability to build workflows that catch what they miss.
The build is never finished. You just keep improving it.
That suits me fine.
I’m sharing this because I want to hear how others are navigating the same shift. There’s been no shortage of hype and fear around AI in our industry, and honestly, some of that fear is justified. Across the industry, roles are changing. But changing isn’t the same as disappearing. What I’ve experienced is less replacement and more transformation. The job looks different, demands different things, and rewards different skills than it did a few years ago. If you’re in the middle of that shift too, I’d genuinely love to hear how you’re doing it.
I’m currently exploring new opportunities in AI-assisted documentation, developer experience, and technical solutions roles. If this resonates, let’s connect on LinkedIn.
7 Mac Apps for Developers Who Ship on Tight Deadlines in 2026
Deadlines don’t care about your setup. They don’t care that your terminal theme looks perfect or that you spent an hour configuring your dotfiles. When you’ve got 48 hours to ship a feature — or a whole product — the only tools that matter are the ones that remove friction and keep you moving.
Here are 7 Mac apps I rely on when the clock is ticking and every minute counts.
1. Raycast — Launch Anything Instantly
When you’re shipping fast, switching between apps with Cmd+Tab is death by a thousand cuts. Raycast replaces Spotlight with a launcher that does everything: open projects, run scripts, manage clipboard history, convert units, search docs — all from one keystroke. The built-in snippets and window management mean you never leave the keyboard. During crunch time, that adds up to hours saved.
Price: Free (Pro $8/mo)
2. Warp — A Terminal That Keeps Up With You
Traditional terminals weren’t built for speed-coding sessions. Warp is. It groups your command output into blocks you can copy, share, and scroll through independently. The AI command search is legitimately useful when you can’t remember that one Docker flag at 2 AM. Auto-complete is fast and context-aware, which matters when you’re running 30 commands an hour.
Price: Free (Teams $22/user/mo)
3. CleanShot X — Screenshot, Annotate, Ship
Deadlines mean lots of quick screenshots — for PRs, bug reports, Slack threads, docs. CleanShot X handles all of it: scrolling captures, screen recording, instant annotation, OCR, and cloud upload with a shareable link. The “pin screenshot” feature is a lifesaver when you need to reference a design while coding. Way faster than the built-in screenshot tool.
Price: $29 one-time
4. TokenBar — Know What Your AI Is Costing in Real Time
If you’re using Cursor, Claude, or any LLM API to ship faster, costs can spiral during a crunch. TokenBar sits in your menu bar and shows real-time token usage and spend across providers. One glance tells you whether that aggressive prompting strategy is costing $2 or $20. When you’re moving fast and leaning on AI to hit a deadline, this is the difference between shipping on budget and getting a nasty surprise on your invoice.
Price: $5 lifetime
5. Monk Mode — Kill Distractions at the Feed Level
Deadline mode means zero tolerance for distractions, but most blockers are too blunt — they kill entire apps. Monk Mode is smarter: it blocks feeds and addictive content inside apps you still need. Twitter feed gone, but DMs still work. YouTube recommendations hidden, but you can still search for that tutorial. Reddit front page blocked, but direct links to Stack Overflow threads pass through. It’s surgical, and it’s the reason I can actually sustain focus during 6-hour coding stretches.
Price: $15 lifetime
6. Rectangle — Window Management That Doesn’t Require Thought
When you’re deep in crunch mode, arranging windows shouldn’t require any brain cycles. Rectangle gives you keyboard shortcuts for every window layout you need: half-screen, thirds, quarters, maximize. Drag a window to a screen edge and it snaps. It’s dead simple, completely free, and it turns multi-monitor setups into something you can rearrange in under a second. I keep my editor left, terminal right, and browser on the second monitor — Rectangle makes resetting that layout instant.
Price: Free
7. Fantastical — See Your Deadline Coming
When you’re heads-down shipping, it’s easy to lose track of time entirely. Fantastical lives in the menu bar and shows your schedule at a glance — upcoming meetings, deadlines, and time blocks. Natural language event creation means you can type “deploy review tomorrow 2pm” and it just works. The calendar sets integration is great for separating “crunch sprint” events from your regular schedule. When deadlines get tight, knowing exactly how much uninterrupted time you have left is critical.
Price: Free (Premium $4.75/mo)
The Real Deadline Stack
Tools don’t ship code — you do. But when you’re racing the clock, the wrong tool can slow you down just enough to miss it. Every app on this list does one thing: removes a specific type of friction so you can stay in flow longer.
The common thread? They’re all lightweight, fast to access, and stay out of your way until you need them. No complex setup, no onboarding flow, no “sync your account to get started.” Just open and go.
If you’ve got a deadline coming up, set these up before the crunch starts. Future-you will be grateful.
What’s in your deadline toolkit? Drop your must-haves in the comments.
OpenAI, Codex uygulamasına “plugin/eklenti” desteği ekledi
OpenAI, doğrudan geliştiricilere ve kodlamaya odaklanan Codex uygulamasına “plugin/eklenti” desteği eklediğini duyurdu. Bu konuda yaptığı açıklamada, “Codex, eklentilerle birlikte artık sadece kod yazmakla kalmıyor; kodlama öncesi planlama ve araştırma gibi hazırlık aşamalarından, kodlama sonrasındaki iş akışlarına kadar pek çok gerçek göreve destek veriyor. Örneğin Google Drive eklentisi, Codex’in Google Drive, Dokümanlar, Tablolar ve Slaytlar genelinde birleşik iş akışlarıyla tek bir döngü içerisinde çalışmasına olanak tanıyor.” ifadelerini kullanan şirket, bu altyapı ile sisteme Gmail eklentisi üzerinden e-posta okuma ve yönetme, Slack eklentisi üzerindense kanal özetleme veya yanıt taslağı hazırlama gibi özelliklerin eklenebileceğini belirtiyor. OpenAI süreçte kullanılabilecek eklentilerin hepsini uygulamaya yeni eklenen “plugin/eklenti” menüsünün altında sunuyor.
OpenAI, Codex uygulamasına “plugin/eklenti” desteği ekledi yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

