Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
jq and yq in Depth: Querying, Transforming and Editing JSON and YAML on the Command Line
jq returns a missing field as null instead of an error and exits with 0 on empty results too; add -e to every filter you use as a condition in CI. With output from Bookstore.Api, kubectl, dotnet list package and the GitHub API we show select, group_by, reduce inputs, --arg/--argjson and @csv, updating an image tag with yq while keeping comments, the two different yq tools and Windows quoting.
Validating Configuration with JSON Schema: Editor IntelliSense, SchemaStore and Validation in CI
The .NET binder silently ignores a misspelled settings key; additionalProperties: false in JSON Schema catches it while you write the file and in CI. We write a 2020-12 schema for Bookstore.Api and validate with SchemaStore, a VS Code mapping, a YAML schema comment, check-jsonschema, ajv and JsonSchema.Net, showing with real output how mixed drafts and format checking differ.
TOML, INI, .env and the Rest: Which Configuration Format When?
Choose by who reads the file: if .NET is the only reader, JSON and environment variables are enough; if several tools read the same .env, write it in the strictest common subset. We read one .env with Compose, Node.js, dotenv, python-dotenv and bash, one INI with .NET, Python and git, and show the differences, TOML 1.1's date types and Bookstore.Api's setting in five formats becoming one configuration.
YAML 2: Multiline Strings, Anchors/Aliases, Merge Keys, Multiple Documents and KYAML
Write scripts with |, long prose with >, and use |- for single-line values such as secrets, otherwise a \n is appended. The merge key (<<) is not in YAML 1.2: Compose, kubectl and kubeconform support it, GitHub Actions does not, and js-yaml 5 needs an option. We show multiple documents, the document boundary of anchors, unsafe tags, KYAML and a yamllint rule set for Bookstore with real output.
YAML 1: Syntax, Types and the "Norway Problem": Reading a YAML File Correctly
The type of an unquoted YAML value depends on the rule set the parser applies: in YAML 1.1 NO is false, 12:30 a number and 0755 octal; in YAML 1.2 all three differ. We run PyYAML, ruamel.yaml, js-yaml, YamlDotNet, yq, Docker Compose and kubectl on the same file and show three real type errors in Bookstore's compose.yaml and Kubernetes manifest.
Really Knowing JSON: RFC 8259, Number Precision, Duplicate Keys, JSONC, JSON5 and JSON Lines
Because RFC 8259 leaves duplicate keys and number precision undefined, Node.js, Python, jq and .NET can read the same JSON differently: all four take the last value of a repeated key and only JavaScript rounds an ID above 2^53. We show BOMs, NaN, leading zeros, JSONC in appsettings.json, JSON5 and a JSON Lines version of Bookstore's order export with real output.
The Cost of Regex: ReDoS, Catastrophic Backtracking, Readability and Testing Regex
A pattern with nested quantifiers, overlapping alternation or adjacent .* makes an exponential or polynomial number of attempts on an input that almost matches; in our measurement ^(a+)+$ took 10 seconds at 28 letters in .NET and 0.07 ms with NonBacktracking. We recognize dangerous constructs with PCRE2 step counts and cover Cloudflare's 2019 outage, the Angular validator and server validation, readable patterns with (?x), a test table with xUnit [Theory] and the MailAddress decision for email.
Regex in .NET: GeneratedRegex, RegexOptions, Timeouts, NonBacktracking and Span APIs
Use [GeneratedRegex] for constant patterns, create run-time patterns once and keep them, and give untrusted input a timeout or NonBacktracking; in our measurement new Regex(..., Compiled) on every call was thirty-three thousand times slower than the source generator. A BenchmarkDotNet measurement, allocation-free EnumerateMatches, timeouts and the constructs NonBacktracking rejects, when IgnoreCase reads the culture, and ISBN validation and Turkish slugs for Bookstore, with real output.
Regex on the Command Line and in the IDE: grep -E/-P, ripgrep, sed, git grep, PowerShell and Repo-Wide Find/Replace
The safe order for a repo-wide regex change is: a clean working tree, the file list from git grep, a preview with rg -r, applying with sed -E and checking with git diff. We show the regex differences of grep, ripgrep, PowerShell and the IDEs, a real refactor in Bookstore that turns interpolated log calls into message templates, and why $ does not match in a CRLF file, together with .NET 11's AnyNewLine option.
Regex Flavors: How .NET, JavaScript, PCRE2, POSIX BRE/ERE and RE2 Differ, and Telling Globs from Regex
The same pattern works, fails or silently matches something else depending on the flavor: the Perl family (.NET, JavaScript, PCRE2) offers lookaround through backtracking, RE2 and Rust regex give it up for linear time, and POSIX picks the longest match. We run one probe list in five engines, show Prometheus's full-match =~ with promtool, and the difference between globs and regex with .gitignore and PowerShell.
Lookaround, Inline Flags and Unicode: Lookahead, Lookbehind, (?i), \p{L} and Turkish Characters
Lookahead and lookbehind check what comes after or before a position without consuming characters; variable-length lookbehind works in .NET and JavaScript, is bounded in PCRE2 and absent in ripgrep. We show inline flags, JavaScript's (?i:…) modifiers, \p{L} and the v flag, and, with real output, that whether ıssız matches ISSIZ in .NET depends on the environment because IgnoreCase follows the culture.
Groups and Backreferences: Capturing, Named Groups, Non-capturing Groups, Alternation and $1/${name} in Replacements
Capturing groups are numbered by the order of their opening parentheses, but .NET puts named groups last, so the same $2/$1 replacement gives different results in .NET and JavaScript. We compare named group syntaxes, ES2025 duplicate group names, finding repeated words with backreferences, POSIX's longest-match rule and the replacement syntax of .NET, JavaScript, sed and VS Code with real output, and fix author names in Bookstore's CSV.