When a service accumulates 50+ command-line parameters, the limitations of static configuration become impossible to ignore. Servy v7.6 tackles this by replacing those parameters with an SQLite-based configuration system. This change isn’t just about storage — it enables runtime adjustments, built-in validation, and compatibility with tools like ORMs and migration scripts. Static configuration formats struggle under the weight of dynamic, versioned state — a problem SQLite solves with structure and persistence. This shift reflects a deeper principle: backend systems should evolve by adopting infrastructure that scales with complexity, not by adding layers of workarounds. I believe choosing the right tool for configuration is as critical as choosing the right architecture for the service itself. #CSharp #DotNet #Programming #SoftwareDevelopment
Servy v7.6: SQLite Configuration for Scalable Backend Systems
More Relevant Posts
-
Your API returns 10,000 rows and you're loading them into a `List<T>` before doing anything. Bold strategy. `IAsyncEnumerable<T>` lets you stream data asynchronously, processing each item as it arrives instead of waiting for the whole payload. It pairs with `await foreach` and it just works. --- await foreach (var tick in GetLiveTicker()) Console.WriteLine($"${tick.Symbol}: {tick.Price:F2}"); --- Shipped in C# 8 and .NET Core 3.0 back in 2019, it quietly solved the "why is my app eating 2GB of RAM" problem for a lot of teams. Run it, break it, learn it: https://lnkd.in/e5jMbUvr #dotnet #csharp #programming #asyncprogramming
To view or add a comment, sign in
-
-
Been working with concurrent code lately and thought I'd share some patterns that keep coming up. Mutex locks are the basics - they make sure only one thread touches shared data at a time. Pretty straightforward but easy to mess up if you forget to unlock. Read-write locks are nice when you have lots of reads and few writes. Multiple readers can work at once, but writers get exclusive access. Semaphores control how many threads can access something at the same time. Think of it like limiting connections to a database pool. Producer-consumer pattern with queues is everywhere. One part creates work, another processes it. Decouples things nicely. Futures and promises let you write async code that's easier to follow than callbacks. Not saying you need all of these all the time. But knowing they exist makes it easier to pick the right tool when you actually need concurrent code. What patterns do you reach for most often? #SoftwareEngineering #Concurrency #Programming
To view or add a comment, sign in
-
Most C# developers typically use lock(_syncObj) to synchronize access to shared state, a pattern that has been standard for two decades. However, each use of lock(object) introduces hidden runtime overhead, including SyncBlock indirection, thin-lock to fat-lock inflation under contention, and additional bookkeeping on a System.Object that was not designed for synchronization. With the introduction of .NET 9, a new type has been introduced: System.Threading.Lock. This dedicated lock offers a slimmer fast path, eliminates SyncBlock overhead, and provides a ref struct scope guard returned from EnterScope() that automatically releases. When using lock(object), the runtime must: - Look up or allocate a SyncBlock for the target object - Inflate from thin lock to fat lock when contention occurs - Carry the SyncBlock cost on every operation against that object - Pay indirection on every acquire, even on the uncontended fast path In contrast, System.Threading.Lock: - Is purpose-built with no SyncBlock indirection - Offers a faster uncontended fast path in pure managed code - Returns a ref struct from EnterScope() that auto-releases at the end of the scope - Eliminates "lock on a string/this/Type" anti-patterns by making them errors This pattern is particularly effective for hot, often-uncontended critical sections, including: - Per-instance state guards in services and middleware - LRU and TTL cache mutations - Counter and metric increments under low contention - Singleton initialization paths - Any lock(_obj) accessed by multiple threads in steady state Implementing this change can significantly enhance performance in critical paths. Benchmark results show approximately 7 ns per uncontended acquire on System.Threading.Lock compared to around 14 ns on lock(object)—a roughly 2x speedup on the fast path, with no allocations in either case. #csharp #dotnet #dotnet9 #dotnet10 #performance #threading #programming #tips #coding #softwaredevelopment #aspnetcore #cleancode
To view or add a comment, sign in
-
-
💻 Great .NET insights from Steven Giesel. This post dives into practical development concepts with clear explanations and real code examples—always a great resource for developers looking to sharpen their skills. 👉 https://lnkd.in/gp8vTSkr #dotnet #SoftwareDevelopment #Programming #DevCommunity
To view or add a comment, sign in
-
Still writing verbose DTOs like this? C# has evolved — and so should we. 💡 Records vs Traditional DTOs ❌ DTO (class) Mutable → data can change anytime More boilerplate Reference-based comparison ✅ Record Immutable by default → safer & predictable Minimal, clean code Value-based equality (compares data, not memory) Easy updates with with ⚡ Why it matters (Performance & Design) No unintended mutations → fewer bugs Better for multi-threading (no locks needed) Optimized equality checks out of the box Cleaner code = easier maintenance 🚀 Bottom line: Records aren’t just shorter — they’re smarter. #CSharp #DotNet #CleanCode #SoftwareDevelopment #Programming #Performance
To view or add a comment, sign in
-
-
𝗟𝗼𝗰𝗸-𝗙𝗿𝗲𝗲 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 𝗯𝘆 𝗛𝗲𝗿𝗯 𝗦𝘂𝘁𝘁𝗲𝗿 𝗖𝗽𝗽𝗖𝗼𝗻 𝟮𝟬𝟭𝟰 "If you think using atomics is easy, you're either jaded, one of 50 people in the world — or not being careful enough." That opening line from Herb Sutter's iconic CppCon 2014 talk Lock-Free Programming (or, Juggling Razor Blades) sets the tone perfectly. This is a two-hour deep dive that every serious C++ engineer should have in their back pocket. Here are the core ideas that stuck with me: 𝗟𝗼𝗰𝗸-𝗳𝗿𝗲𝗲 𝗶𝘀 𝗮𝗻 𝗼𝗽𝘁𝗶𝗺𝗶𝘇𝗮𝘁𝗶𝗼𝗻 𝘁𝗼𝗼𝗹, 𝗻𝗼𝘁 𝘁𝗵𝗲 𝗱𝗲𝗳𝗮𝘂𝗹𝘁 𝘀𝗲𝘁𝘁𝗶𝗻𝗴. Before using atomics, you should measure first. After writing your shiny new lock-free algorithm, measure again. Measure again. More often than not, the expected improvement simply isn't there. 𝗧𝗵𝗶𝗻𝗸 𝗶𝗻 𝘁𝗲𝗿𝗺𝘀 𝗼𝗳 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀. Model every member function and every locked region as a transition from one valid state to another. This mental model makes lock-free reasoning possible. A single atomic write can cause a whole graph of objects to come into existence for other threads. This is powerful, but only if you reason about it rigorously. 𝗟𝗼𝗰𝗸𝘀 𝗮𝗻𝗱 𝗮𝘁𝗼𝗺𝗶𝗰𝘀 𝗮𝗿𝗲 𝗻𝗼𝘁 𝗺𝘂𝘁𝘂𝗮𝗹𝗹𝘆 𝗲𝘅𝗰𝗹𝘂𝘀𝗶𝘃𝗲. Sutter explains producer-consumer designs in which ownership transitions between subsystems. In one phase, the transition is protected by a mutex; in the next phase, it is handed off via an atomic. The rule is simple: at any given moment in an object's lifetime, all threads must agree on how access is synchronized. This mechanism can change across phases. 𝗪𝗲𝗶𝗴𝗵𝘁-𝗳𝗿𝗲𝗲 → 𝗹𝗼𝗰𝗸-𝗳𝗿𝗲𝗲 → 𝗼𝗯𝘀𝘁𝗿𝘂𝗰𝘁𝗶𝗼𝗻-𝗳𝗿𝗲𝗲. These aren't just academic labels. They provide meaningful guarantees about system-wide throughput, starvation, and liveness. Knowing which level your algorithm achieves is important for reasoning about scalability under load. 𝗧𝗵𝗲 𝘀𝗶𝘇𝗲 𝗼𝗳 𝘁𝗵𝗲 𝗰𝗿𝗶𝘁𝗶𝗰𝗮𝗹 𝘀𝗲𝗰𝘁𝗶𝗼𝗻 𝗶𝘀 𝗮 𝘀𝗰𝗮𝗹𝗮𝗯𝗶𝗹𝗶𝘁𝘆 𝗱𝗶𝗮𝗹. The mail-slots example illustrates this beautifully. Releasing a slot before or after doing the work is a subtle yet consequential decision, and the correct answer depends on whether the bottleneck is your producer or your consumers. The code looks almost identical either way. However, the performance implications are not. 💡 If you work in systems programming, high-performance infrastructure, or any field where concurrency matters, this talk is worth your time. It won't make lock-free programming easy. But it will help you understand exactly why it isn't. 𝗥𝗲𝗳𝗲𝗿𝗲𝗻𝗰𝗲𝘀 🎥 Herb Sutter, "Lock-Free Programming (or, Juggling Razor Blades), Part I", CppCon 2014, 16 Oct 2014, https://lnkd.in/dXM3uS-v 🎥 Herb Sutter, "Lock-Free Programming (or, Juggling Razor Blades), Part II", CppCon 2014, 16 Oct 2014, https://lnkd.in/dQvQcSYx #cpp #concurrency #lockfree #cppcon #performanceengineering
CppCon 2014: Herb Sutter "Lock-Free Programming (or, Juggling Razor Blades), Part II"
https://www.youtube.com/
To view or add a comment, sign in
-
💡 𝐂#/.𝐍𝐄𝐓 𝐄𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧 𝐇𝐚𝐧𝐝𝐥𝐢𝐧𝐠 𝐓𝐢𝐩 🔥 💎𝐃𝐨𝐧'𝐭 𝐮𝐬𝐞 𝐭𝐡𝐫𝐨𝐰 𝐞𝐱 𝐢𝐧 𝐜𝐚𝐭𝐜𝐡 𝐛𝐥𝐨𝐠 🚫 𝐭𝐡𝐫𝐨𝐰 𝐞𝐱; updates the StackTrace property of ex. If you throw the "ex", 𝐭𝐡𝐞 𝐬𝐭𝐚𝐜𝐤 𝐭𝐫𝐚𝐜𝐞 𝐢𝐬 𝐥𝐨𝐬𝐭! ✅ 𝐭𝐡𝐫𝐨𝐰; preserves the original stack trace of exception stored in the 𝐄𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧.𝐒𝐭𝐚𝐜𝐤𝐓𝐫𝐚𝐜𝐞 property. ⚡ In this way, 𝐰𝐞 𝐝𝐨𝐧𝐭 𝐥𝐨𝐬𝐞 𝐭𝐡𝐞 𝐬𝐭𝐚𝐜𝐤 𝐭𝐫𝐚𝐜𝐞 and can quickly find the root cause of the error. ⚠️ 𝐂𝐀𝟐𝟐𝟎𝟎 𝐖𝐚𝐫𝐧𝐢𝐧𝐠 • CA2200 is a code analysis rule that detects improper exception re-throwing. • It triggers when you use throw ex; instead of throw; in catch blocks. • Following this rule helps maintain complete error information for troubleshooting. ⚠️ 𝐭𝐡𝐫𝐨𝐰 𝐞𝐱, 𝐰𝐢𝐥𝐥 𝐫𝐞𝐬𝐞𝐭 𝐭𝐡𝐞 𝐜𝐚𝐥𝐥 𝐬𝐭𝐚𝐜𝐤 𝐢𝐧 𝐭𝐡𝐞 𝐞𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧 𝐭𝐨 𝐭𝐡𝐞 𝐩𝐨𝐢𝐧𝐭 𝐰𝐡𝐞𝐫𝐞 𝐭𝐡𝐢𝐬 𝐭𝐡𝐫𝐨𝐰 𝐬𝐭𝐚𝐭𝐞𝐦𝐞𝐧𝐭 𝐥𝐨𝐬𝐞𝐬 𝐭𝐡𝐞 𝐢𝐧𝐟𝐨𝐫𝐦𝐚𝐭𝐢𝐨𝐧 𝐚𝐛𝐨𝐮𝐭 𝐰𝐡𝐞𝐫𝐞 𝐭𝐡𝐞 𝐞𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧 𝐰𝐚𝐬 𝐜𝐫𝐞𝐚𝐭𝐞𝐝. So, we can't see the original stack trace and you may spend days to find the root cause. #csharp #dotnet #programming #softwareengineering #softwaredevelopment
To view or add a comment, sign in
-
-
When modeling scenarios with a fixed set of outcomes — such as parsing user input or handling HTTP requests — developers often rely on enums or inheritance, which can compromise clarity and type safety. C# 15 introduces union types as a more robust alternative. These allow you to define a closed set of types with implicit conversions and pattern matching, ensuring compile-time exhaustiveness. This means the compiler will catch missing cases, reducing runtime errors. For example, a Result<int, Error> type cleanly represents success or failure, aligning with functional programming patterns and improving code safety. I believe union types offer a design shift that makes C# more expressive and safer — especially for handling domain events or API responses. What do you think — how have you handled similar scenarios before union types? #CSharp #DotNet #Programming #SoftwareDevelopment
To view or add a comment, sign in
-
💡𝐂#/.𝐍𝐄𝐓 𝐀𝐬𝐲𝐧𝐜 𝐎𝐩𝐞𝐫𝐚𝐭𝐢𝐨𝐧 𝐓𝐢𝐩 🚀 💎𝐇𝐨𝐰 𝐚𝐧𝐝 𝐰𝐡𝐞𝐧 𝐭𝐨 𝐮𝐬𝐞 ‘𝐚𝐬𝐲𝐧𝐜’ 𝐚𝐧𝐝 ‘𝐚𝐰𝐚𝐢𝐭’ 💡 '𝐚𝐬𝐲𝐧𝐜' and '𝐚𝐰𝐚𝐢𝐭' keywords introduced in C# 5.0 were designed to make it easier to write asynchronous code, which can run in the background while other code is executing. The "async" keyword marks a method asynchronous, meaning it can be run in the background while another code executes. ⚡ When using 𝐚𝐬𝐲𝐧𝐜 and 𝐚𝐰𝐚𝐢𝐭 the compiler generates a state machine in the background. 🔥 Let's look at the other high-level details in the example; 🔸 𝐓𝐚𝐬𝐤<𝐢𝐧𝐭> 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 = 𝐋𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐎𝐩𝐞𝐫𝐚𝐭𝐢𝐨𝐧𝐀𝐬𝐲𝐧𝐜(); starts executing 𝐋𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐎𝐩𝐞𝐫𝐚𝐭𝐢𝐨𝐧. 🔸 Independent work is done on let's assume the Main Thread (Thread ID = 1) then 𝐚𝐰𝐚𝐢𝐭 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 is reached. 🔸 Now, if the 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 hasn't finished and it is still running, 𝐃𝐨𝐒𝐨𝐦𝐞𝐭𝐡𝐢𝐧𝐠𝐀𝐬𝐲𝐧𝐜() will return to its calling method, this the main thread doesn't get blocked. When the 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 is done then a thread from the ThreadPool (can be any thread) will return to 𝐃𝐨𝐒𝐨𝐦𝐞𝐭𝐡𝐢𝐧𝐠𝐀𝐬𝐲𝐧𝐜() in its previous context and continue execution (in this case printing the result to the console). ✅ A second case would be that the 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 has already finished its execution and the result is available. When reaching the 𝐚𝐰𝐚𝐢𝐭 𝐥𝐨𝐧𝐠𝐑𝐮𝐧𝐧𝐢𝐧𝐠𝐓𝐚𝐬𝐤 we already have the result so the code will continue executing on the very same thread. (in this case printing result to console). Of course this is not the case for in the example, where there's a 𝐓𝐚𝐬𝐤.𝐃𝐞𝐥𝐚𝐲(1000) involved. 🎯 𝐖𝐡𝐚𝐭 𝐝𝐨 𝐲𝐨𝐮 𝐭𝐡𝐢𝐧𝐤 𝐚𝐛𝐨𝐮𝐭 𝐚𝐬𝐲𝐧𝐜 𝐨𝐩𝐞𝐫𝐚𝐭𝐢𝐨𝐧𝐬? #csharp #dotnet #programming #softwareengineering #softwaredevelopment
To view or add a comment, sign in
-
-
𝗪𝗵𝘆 𝗰𝗹𝘂𝘁𝘁𝗲𝗿 𝘆𝗼𝘂𝗿 𝗰𝗼𝗱𝗲𝗯𝗮𝘀𝗲 𝘄𝗶𝘁𝗵 𝗻𝗲𝘀𝘁𝗲𝗱 "𝗶𝗳" 𝘀𝘁𝗮𝘁𝗲𝗺𝗲𝗻𝘁𝘀 𝘄𝗵𝗲𝗻 𝗖# 𝗽𝗿𝗼𝘃𝗶𝗱𝗲𝘀 𝗮 𝗯𝘂𝗶𝗹𝘁-𝗶𝗻 𝘀𝗵𝗼𝗿𝘁𝗰𝘂𝘁 𝗳𝗼𝗿 𝗲𝗹𝗲𝗴𝗮𝗻𝗰𝗲? 🚀 Stop manually checking for nulls—C# 8.0 changed the game with Nullable Reference Types, yet many are still missing out on this built-in power. By leveraging the Null-Conditional operator (?.), you can collapse complex nested logic into a single, elegant line that is cleaner, safer, and infinitely more readable. #CleanCode #DotNet #CSharp #ProgrammingTips #SoftwareEngineering
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development
A service should not have more than 4-5 command line parameters. 50 is a huge number and indicates a deeper design issue. Regardless of that, one big advantage of using a database like sqlite3 is, you can hot-reload your microservice after a config change. If you use command line args (or config files), then you have to stop and restart the microservice whenever there is a change in any parameter.