So have you ever stopped to think about command line interfaces, even if maybe you didn't quite realize you were using one.
Yeah, I mean think about it every time you type get commit right.
Right, or launch a Docker container.
Exactly, or even when your computer updates using things like apped on Linux or brew on macOS. That's all CLI and get this.
Even huge graphical apps like say chat GPT often have these powerful CLI tools working behind the scenes for automation advanced control.
It's pretty amazing, isn't it. They really are everywhere, They truly are. It's fascinating. Really, these tools are just incredibly omnipresent across well the whole IT landscape. And it's not just developers using the dot net cli or no jscli, you know, DevOps engineers they rely on them constantly. GitHub cli as your debub cli.
Oh yeah.
System admins manage whole infrastructures with PowerShell, Bash, package managers like Choco or wing it on Windows right, and even data scientists are in on it. Scripting with Python are Panda's sequel. They really do underpin so much of our digital world. Kind of like efficient backbones.
Efficient backbones. I like that, So welcome everyone to the deep dive.
Hello.
Today we're taking a bit of a shortcut to getting really well informed on a topic that Okay, I might sound super technical, but it's actually incredibly practical, empowering even we're talking about building COLI applications with c sharp and dot Net, and we're drawing some powerful insights from to Johnny Belloness, who is fantastic book on the subject.
It's a great resource.
Our mission today, well, it's to unpack the core ideas, some maybe unexpected benefits and the sort of step by step process for creating these cross platform command line apps and more importantly, why you listening right now should absolutely care about.
This stuff into Johnny Belminsur is really an exceptional guide for this. I mean over twenty one years of experience, especially in dot net and Azure. Wow. Yeah, and apparently he wrote his first program in quick basic when he was.
Just eight eight Okay, that's impressive, right.
So that extensive hands on background it makes them uniquely qualified to explain these sometimes complex topics. And what's interesting is how he uses cutting edge AI to like enhance the language and clarity in his writing. Oh interesting, but he ensures the actual content integrity is strictly his own. It's a neat blend.
That is a neat blend. So okay, what does this all mean for you, our listener? Why should you care about CLI apps?
Well, they aren't just obscure tools for you know, hardcore coders. They are seriously powerful productivity enhancers. They can drastically simplify your life. Also, well, for one, they help you stay focused less context switching. Right, you're not jumping between a dozen different graphical windows all the time.
Okay, yeah, I feel that pain.
And they automate those repetitive, error prone tasks that just eat up your time. And you know, they can even build things like workstation profiles.
Workstation profiles, tell me more about that.
Imagine this, Instead of spending like hours annually installing and configuring software for a new team member or even just a fresh PC, yeah the worst, a single command could potentially automate the entire setup. Curiously, Yeah, think about the time and frustration saved, Whether it's just for your personal workflow or for a whole organization. It's huge.
That is huge. So this deep dive, it's kind of offering those aha moments, right, giving you a clear path to understanding the how and the why these tools are so.
Transformative exactly a shortcut to that understanding.
Okay, let's unpack this first bit, then the unsung hero. Why are cli apps everywhere? And what are they really built on? We've touched on how widespread.
They are, Yeah, they're ubiquity, but it's worth.
Hammering home just how ingrained they are, often working silently, making things stick.
And connecting this back to productivity. Yeah, that's where they really shine, keeping.
You focus way less context switching exactly.
Every time you switch apps, email, project, tool chat, the chance of getting to rail just skyrockets, you know, totally. Celi tools minimize that you string together complex operations with simple commands and those workstation profiles. Traditionally that meant custom OS images.
Oh, the big clunky images.
Yeah, costly storage, OS updates, tool updates, human frustration. It was a mess, I can imagine. But by using CLI apps like PowerShell, scripts with package managers like Chocolatey or Wingt, it can automate the whole setup based on user rolls. Users get more autonomy, Manual installed time plummets. It's a shift from manual, air prone work to automated, repeatable.
Processes that sounds like a massive win. I can just picture the IT department breathing a collective sigh of relief. Absolutely, And what's really fascinating is you said, at the heart of all this sophistication, it's basically just a simple console application pretty much.
That's the surprising truth. It provides that basic structure before you start adding all the CLI bills and whistles.
So if you want to build these, what are the essential tools? What's the starter kit?
Okay, your developer toolkit Visual studio Code is a huge one. It's free, cross platform, super powerful, especially with all its extensions.
Right, the extensions make it.
Then you need the dot net SDK. That's crucial for c shark development, the foundation for building and running dot net apps. Got it and Get absolutely indispensable for version control, tracking changes, collaborating. You need GET.
Can't live without Get any key vus code extensions you'd recommend definitely.
The c sharp DevKit is essential now in telecode for C sharp DevKit. That gives you that AI powered whole line completion which is pretty.
Slightly oh nice.
And gitlans. It just makes working with get history inside vs codes so much easier. Boost productivity for sure.
Okay, so we start with this basic console application. How do we level it up? How do we go from just simple text in text out to something that understands more complex commands, something user friendly.
That's the next step, right, mastering user input beyond just that raw array of argument to.
Get Yeah, the string arcs exactly.
So system dot console is your starting point. Basic interactions right line and right for output, read line and read key for input.
Standard stuff.
Yeah, you can even use background color and foreground color for some visual feedback guide the user a bit. Oh, that's and and title is useful for labeling the console window. But just a heads up. It's only visible in like external terminals, not the integrated one in vs code.
Usually good to know. But okay, what if your CLI app is doing something important, something long running, and the user just hits ctrol plus.
C ah the panic button.
Right, You can't just let it crash if it's saving data or cleaning up resources, can you?
No? Absolutely not, Especially with sophisticated apps. You risk data loss, corrupted state. It's bad news. That's where the cancel keypress event is crucial.
Cancel keypress it gets.
Triggered by cutrol plus c or ctrl plus break and if you handle that event, your application gets a chance to do crucial clean before it exits, like what like saving at state, logging out of services, maybe closing database connections gracefully. It prevents those abrupt crashes and lost data, ensures a clean shutdown, vital for reliability.
Okay, that makes sense for basic console apps. But real cli apps, the ones we use daily, they have named parameters right, and subcommands. It's much clearer than just trying to remember the order of arguments in a raw string array exactly.
That's the big leap in user friendliness. Instead of my climb RG one ARC two and hoping you got the order right?
Yeah, what was R two again?
Right, you get a much more powerful discoverable interface named parameters, switches, subcommands like a bookmark, parklink, ad name my blog, you're lolo, hgtps dot my blog dot com.
Ah Okay, much clearer, way clearer.
And ps users understand what's expected, what the parameters mean, how to provide them correctly. Cuts down on guesswork and airs massively.
So if we want to build these modern intuitive cli in dot net, what's the recommended library? Is there a go to that Microsoft pushes.
Absolutely for dot net. System dot command line is the one. It's a robust dot Net Foundation project actively maintained by Microsoft.
Okay, system dot command line. And why is it better than say, older ways of doing this, Well.
The real insight is how it shifts your thinking. You move from manually parsing that messy command line input which is always a pain, to declaratively building intelligent interfaces. It uses this modern builder pattern. Think of it like defining your commands and options in a structured, readable way, building with Lego bricks, almost.
Lego bricks for commands.
I like it, yeah, And it's not just syntax. It makes your CLI inherently more robust, user friendly, and maintainable right from the start. It helps eliminate common input errors before they even happen.
And it comes with built in goodies.
Oh yeah, fantastic built in features. Command hierarchies you know like get has clone an ad automatic tab completion which users love. Even version number retrieval like version makes your CLI feel professional right out of the box.
How does it work? Structurally?
You define a root command that's the main entry point, then you add subcommands and these option t objects. The TA means they support various data types, strings, integers, booleans, file paths, you name it, plus aliases makes it super powerful and easy to use.
That does sound powerful, but for someone maybe used to older libraries. What's the biggest mental shift with this builder pattern? Is it a steep learning curve?
You know, it's surprisingly intuitive once you click with the concept. The main shift is going from imperatively grabbing stuff from ARGs and then manually checking.
It right writing lots of if statements.
To declaratively defining what your command expects. You basically tell system doc command like hey, I need a string here and it's required, or this is an integer it's optional, and it handles the parsing and the basic validation for you.
Ah, so you focus more on the actual logic of the command.
Exactly, not the tedious parsing plumbing.
Excellent point. So building on that, how do we make sure the app is truly robust, especially with with user input and how do we manage data safely?
Yeah, that leads right into proper input validation. You control the input using properties on those options like is required for mandatory ones, the user has to provide it, okay, makes sense? Or sometimes you want to accept multiple values for one option, right, like adding several bookmarks at once. Yeah, for that argumentarity one or more is super.
Flexible argumentarity got it.
And for really specific checks, say you want to assure a bookmark URL only points to like an internal corporate domain, you can use add validator to hook in your own custom validation logic. This way, bad data just doesn't even get into your application flow.
That's smart, preventing problems early. What about dealing with files? Lots of CLI tools process files or output to them. How does the book approach that.
That's a super common and critical task. Yeah. CLI apps often read from files or write.
Results like import texport or processing logs exactly.
So you can use file info options and combine those with validators like legal file names only just to make sure the file them is valid for the OS and existing.
Only ah, to make sure the input file actually exists before you try reading it.
Precisely. It prevents those nasty file not found exception errors downstream. This makes things like back up and restore features really robust, like the bookmark example in the book uses Jason importexport, or just sharing data between systems.
Okay, so validation helps a lot, but Even with the best checks, things can still go wrong. Right, Software is complex? What's the safety net for unexpected errors? And how do we actually see what our app is doing? Especially if something does go wrong.
You're absolutely right, No code is perfect. So error handling and CLI apps it follows standard best practices pretty much like any other app type.
So try catch blocks, yep.
Try cash finally is your friend, But the key is catching specific exceptions before the generic exception.
Why is that.
Important because it lets you give much better, more specific feedback to the user. Catching a file not found exception and saying, hey, that file doesn't exist is way more helpful than just a generic oops, an error occurred. Right.
Users hate generic errors exactly.
And creating your own custom exceptions like maybe a user already exists exception for the bookmark app makes your code clearer and lets you handle specific problem types cleanly.
And beyond just reacting to.
Errors, defensive programming is key, validating inputs up front, enforcing preconditions, basically trying to prevent errors before they even happen. That's your first line of defense.
Okay, so error handling helps us recover, but how do we understand why errors happen? Or just track what the app is doing over time, especially in production.
Ah. That's where structured logging is absolutely essential for diagnostics, monitoring, debugging, crucial.
Stuff, and Jason is good for that.
Jason is excellent. It's machine readable, lightweight, easily parsed by log management tools like Splunk or elastic stack.
Makes sense. Any recommend library for dot net sera, Loog is fantastic.
It's a really powerful dot net logging library that excels as structured logging.
Structured logging what does that mean exactly?
Instead of just logging a plain text message, you log events with rich typed data attached. So you might log an order placed event with properties like ordered customer, total amount.
Ah okay, so you can easily search and filter later based on those properties.
Precisely makes analyzing logs incredibly powerful. Sarah. Loog has various sinks destinations for your logs, console files, data bases, cloud services, tons of options and you can figure it yeah. Usually in appsettings dot Jason, you can set minimum log levels like only show warning and above and production to reduce noise. You can enrich logs with context like the machine name or thread id, which is super helpful for debugging tricky.
Issues id yeah for concurrent stuff.
Definitely, And one crucial thing always remember to call log dot close and flesh when your app exits. It ensures that any offered log messages are written out before the application shuts down completely. Guarantees you don't lose those last few vital log entries, especially if the app crashes.
Good tip. Okay, so we've covered the nuts and bolts robustness error handling logging, but let's be real. Staring at a black screen with plain white text, it can be a bit well dry.
Uh huh yeah, even for tech pros.
So if we want users to actually enjoy using our CLI tools, maybe even love them, how do we go beyond just basic text? How do we make the experience interactive and dare I say, visually engaging?
This is where a library like spector Console becomes an absolute game changer.
Seriously, Specter Dot Console, okay, tell me more.
It goes way beyond just simple color text. It lets you render really visually appealing elements right there in.
The terminal, Like what kind of elements?
Think ASKI art banners using figlet for a cool startup screen. Nice emojis to add a bit of personality, rich markup for bowlding, text specific colors, even clickable links in terminals that support it.
Couple links in the terminal.
Wow. Yeah, it's basically an enhanced alternative to the standard system dot console, better functionality, cross platform compatibility, and a whole suite of interactive components. Yeah. It turns that drab terminal into like a dynamic canvas.
Okay, dynamic canvas.
I like that.
So it looks good, But how does it help with actual user interaction making it feel dynamic? Not just pretty?
Great question? It excels there too. You can create dynamic experiences like selection prompts.
Selection prompts yeah.
Where the user sees a list of choices and can navigate using arrow keys and hit enter, much nicer than typing out an option number. Oh definitely, or live progress bars for long running operations. Gives the user real time feedback that something is actually happening.
That's essential for longer tasks, avoids the is it frozen feeling.
Exactly, and it's great for presenting complex data clearly using things like tree views.
Tree views like for hierarchical data yep.
Imagine organizing bookmarks by category in a nice tree structure right in the terminal output makes complex information much more digestible and honestly more engaging for the user. It really transforms that passive display into an active conversation.
That sounds incredibly powerful for making CLIs more approachable, especially for maybe less technical users. Yeah, but is there a downside? Can too much interactivity be a bad thing?
Sometimes you've hit on a really crucial point there. Balance interactivity is fantastic for human users, no doubt, but you have to use it wisely.
Why is that?
Think about automation. What if your CLI tool is also meant to be used in say a CICD pipeline.
AH continuous integration, continuous delivery, automated builds and deployment.
Right, those automated processes can't answer interactive prompts. An unexpected prompt would just hang the pipeline.
Okay, so that's a problem. How do you handle that?
You need to provide a non interactive mode. A common pattern is to add an interactive flag or option.
So humans can run it with interactive to get the nice prompts in progress bars.
Exactly, and the automated scripts run it without that flag, so it just executes non interactively. Maybe using default values or taking all input via parameters.
That makes sense. Designed for different ways people and machines will use it.
Flexibility precisely, it's about designing for different consumption patterns.
Okay, So let's say our app is growing, We're adding features, interactivity, maybe talking to external services. How do we stop the code from turning into a giant, tangled mess. What are the foundations for scalable design, modularity integrating services cleanly?
That's a critical concern as apps evolve. That program dot cs file in the book's example, it apparently swelled from one hundred and ninety one lines to four hundred and seventy nine.
Wow. Yeah, that gets on wieldy fast.
So refactoring fromodularity becomes essential. One useful technique mentioned is using a code map, a visualization tool to see the relationships between different parts of your code. Helps you spot complexity.
A codemap interesting.
The goal is a logical project structure, maybe separate folders for commands and services. This improves readability, makes it easier to maintain, and crucially, it makes it easier to add new features without breaking existing ones and easier for new developers to onboard.
Makes sense and are there core software design principles that guide this?
Absolutely? The dependency inversion principle or DIP is key here. It's one of the solid principles fundamental ideas for building maintainable, scalable.
Software dependency inversions. Fancy, what's the core idea?
It basically says that high level parts of your system shouldn't depend directly on low level concrete implementations. They should depend on abstractions, usually interfaces.
Okay, can you give an analogy.
Maybe think of your car steering wheel. It's not welded directly to the wheels, right now, that'd be weird. There's an interface that the steering column, the linkage, a standardized connection. If you want to swap your regular tires for I don't know, monster truck tires, Okay, you change the tires, but the steering wheel and how it can generally stays the same. The interface decouples them.
Ah. I see, So the steering wheel depends on the idea of steerable wheels, not one specific type of wheel exactly.
In code, this means your command logic depends on an ibookmark service interface, not directly on the concrete bookmark service class that might talk to a specific database and the benefit decoupling. It makes the system way more flexible, easier to maintain. If you change how bookmarks are stored, maybe move from a file to a database, you only change the concrete bookmark service implementation. The commands using the ibookmark
service interface don't need to change at all. It stops changes rippling through your whole codebase.
That decoupling sounds incredibly valuable. So how does dot net actually help us implement this? Put DIP into action.
Dot Net has excellent built in support for dependency injection or DEI is the technique that makes DIP practical.
Okay, Dependency injection.
Instead of your command code manually creating a new bookmark service, the DI container, managed by things like host builder or anservice collection and modern dot Net automatically provides an instance of the required service I bookmark service when the command needs it.
So the framework handles creating and providing the dependencies.
Right it injects them. This makes future changes much easier because you typically only need to register the service and its implementation in one central place your startup configuration. You don't have to hunt down every place the service is used and update it much cleaner, much easier to manage as the app grows.
That sounds much better. What about reaching outside our CLI app using other systems or services.
Yeah, consuming external APIs and services super common and powerful. Why reinvent the wheel right exactly? It lets you focus on your core logic and delegate other things, maybe payments, advanced logging, or like in the books, example, a separate bookmark synchronization service to specialized external systems. It leverages expert solutions.
So how do we talk to those external services properly and securely? In dot Net? We need good performance, good resource management for talking.
To external APIs. Dot Net's HTTP client is the tool, but crucially you should use IHTTP client.
Factory HTP client factory. Why that Specifically?
It manages the life cycle of HTTP client instances properly. Helps avoid common problems like socket exhaustion, which can happen if you create and dispose of too many HTP client instances directly. It pools and reuses them efficiently. Better performance, better resource management.
Okay, good practice. Any architectural patterns recommended here?
Yes, the service agent pattern is really insightful here. Think of it like a dedicated diplomat or translator for your app. When talking to a specific external service a service agent. Yeah, instead of your main CLI command logic making raw HTDP calls, figuring out URLs, header's authentication for some external API, which can get messy, it just talks to this specific agent class, like maybe a bookmark sinkur agent. It tells the agent, hey,
sink these bookmarks. The agent then handles all the nitty gritty details of talking to the actual external bookmark sinker API, formatting the request, handling API quarks, retries, authentication, parsing the response AH.
So it encapsulates all the communication logic for that specific external service exactly.
It dramatically simplifies your core command logic, centralizes the API interaction details, and makes it much easier to change or update how you talk to that external service later without messing up your main application code.
Reduces that tight coupling That service agent pattern sounds really clean, and it also leads us nicely into our next really critical area, quality assurance and security. How do we make sure this app we've built is reliable, trustworthy and safe for users?
Absolutely crucial. Testing is your safety net? Simple as that your safety net. It ensures new features work obviously, but just as importantly it prevents regressions, you know, accidentally breaking something that used to work when you add a new feature or fix a bug.
Yeah, regressions are the worst. So how do we approach testing systematic?
The pyramid of testing is a good mental model. It outlines different levels.
Okay, what are the levels?
At the broad base, you have unit tests small fast tests verifying individual methods or functions in isolation, often using mocking, which we should talk about unit tests first. Then integration tests. These check that different components work together correctly, like does your service layer talk to the database properly?
Got it?
Above that? System tests These are end to end tests verifying the entire applications functionality from the user's perspective, Does the bookmark ad command actually add a bookmark?
A whole flow?
Right? And at the peak acceptance tests which confirm the app meets the actual user requirements. You also have functional tests what it does versus non functional tests? How well it does it? Like performance or security testing.
That's a comprehensive pyramid for a practical approach, though, what should we really focus on testing? And maybe what shouldn't we waste time testing?
Good question? Focus on testing the happy path everything works is expected, but also critically test the unhappy paths invalid input errors, user hitting sutrol plus.
Two okay, both success and failure cases exactly.
Test method behavior, check fortoon values, ensure exceptions are thrown and handled correctly. What not to test? Generally, don't test external frameworks themselves or simple data transfer objects DTOs those plain data structures. Their creators should have tested them. Focus on your logic and when?
Do these different tests typically run in the development cycle.
Unit tests run them frequently, like before every code commit. Ideally they should be fast. Integration tests usually run after unit tests pass. Maybe in your CI pipeline. Smoke tests are quick checks right after deployment to make sure the basics are working. System tests often run in a staging environment before the final production release.
How do you set up testing in dot net?
It's easy. Dot Net new ms test or x unit end unit creates a test project. Then you structure your test classes logically, maybe mirroring your application structure, like link command tests for the Bookmark apps link command.
Okay, you mentioned mocking for unit tests. What's that about, especially when dealing with external things like databases or web services that can be slow or unreliable during tests.
Right, This is where mocking is essential for effective unit testing. Think of it like using a stand in act or during a play rehearsal the stand in Yeah, libraries like n substitute or mock fake ad easy let you create fake controlled versions of your dependencies, like a fig ibookmark service that doesn't actually talk to a database, but just returns pre defined data or verifies that certain methods were called.
Ah, So you can test your command logic without needing a real database or web service running exactly.
It lets you test your method in complete isolation. It eliminates failures caused by external factors slow network service being down. If a unit test fails when using mocks, you know the bug is almost certainly in your code, not the dependency makes debugging way faster and moraliable.
That makes a lot of sense for isolating tests. Now, shifting gears slightly but equally critical security. Is this something we just tack on at the end?
Oh? Absolutely not. That's a recipe for disaster security is an afterthought. It has to be woven through the entire application life cycle.
The entire life cycle from the very beginning.
Ye yes. Starting with design, use threat modeling techniques like STRIDE.
Or dread Stride dread.
There are structured ways to brainstorm potential threats. STRIDE stands for spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege. It helps you think like an attacker early on.
Okay, thinking like an attacker during design. What else?
Architecture using principles like defense and depth, securing communication channels, development, following secure coding practices, being aware of things like the OATS top ten common vulnerabilities, keeping your libraries and dependencies up to date.
Right outdated libraries are a big risk, huge risk.
Then testing penetration, testing, vulnerability assessments, deploy security ICD pipelines, managing secrets properly, no apikes, and source code definitely not ongoing usage, monitoring for suspicious activity, patching vulnerabilities promptly, and even logging being careful not the logs sensitive data or using tools like sarah log to sanitize it if you must. Security is everywhere.
Wow, Okay, it really is a continuous process. Are there any specific tools, maybe simpler ones that developers can use to check the security of their dot net apps without being full blown security experts.
Yeah, definitely, there are comprehensive tools like sonar, cub snack, mend bolt. But for a great starting point right within the dot net ecosystem, check out dot net audit.
Dot net audit built in yep.
You can run dot netlist package vulnerable. It checks your project's Newgit packages against the GitHub advisory database and tells you if you're using any versions with known vulnerabilities.
Oh, that's super useful and easy it is.
And dot netlist package outdated is also helpful if flags libraries that aren't necessarily vulnerable now but are old and might not be getting security patches anymore, prompting you to upgrade. Quick checks anyone can do.
Fantastic. Okay, let's circle back to that bookmark singer external service example. How do we actually secure the communication between our CLI app and that service, especially if something like an apike or token is involved?
Good question. Typically you'd implement authentication using something like a personal access token or pit a PET.
Okay, how does that work?
Your CLI app needs to send this PT to the external service with each request. A common way is via a custom HGTP header like xpat.
So the token goes in the header securely hopefully over HTTPS.
Absolutely acts is non negotiable. There The external service then receives a request, extracts a paid and validates to checks if it's known, if it's still valid, not expired, has the right permissions.
And the CLI app needs to handle the responses like if the token is invalid exactly.
The service might respond with a four to H one and off rised or four H three forbidden. Your cli needs to handle those responses gracefully, maybe prompt the user to re enter their token or update it.
Where should the user store this pat? Not hard coded?
Right, definitely not hard coded. A common approach is to store it in an environment variable like bookmark pat. The cli app can then read it from the environment when needed. Keeps the token out of source code and separate from the application deployment much more secure.
Okay, environment variable for the pet. Got it? So I've built it, made it robust, interactive, modular, secure, tested it. Wow. Now the final hurdle. How do we actually get this amazing CLI app into the hands of our users. Let's talk packaging and deployment.
Right the final mile. First, let's just clarify the terms because they sometimes get mixed up.
Okay.
Packaging is bundling everything needed to your app's code dependencies into a deployable unit. Distribution is making that package available like putting on our website or repository, and deployment is the actual act of installing and configuring it on the user's machine.
Package, distribute, deploy Got it? So for our cross platform dot netcli app? What are the main options?
You've got several good ones, and the best choice often depends on your target audience. Like well, first, you can package it as a dot net tool, a.
Dot Net tool like dot net tool install exactly.
You package your app as a standard nugat package using dot netpack, then publish it to NuGet dot org or a private feed. This is ideal for other developers or it pros who already have the dot Net SDK installed. They just run dot net tool installed global your tool name. Super easy for that audience.
Okay, cool for devs.
What else? Second option a dock or container. You write a Docker file that describes how to build an image containing your app and its runtime dependencies.
Ah containerization yep.
You build the image, Docker build, push it to Docker hub or another registry. Users then just need Docker Desktop or WSL installed and they can Docker pull your image and Docker run it. Great for portability, consistency across environments, and often a reduced footprint.
Nice. Any options more geared towards say typical Windows users.
Yes, Third option a wingt package. Wing it is the Windows package managed.
Oh yeah, wing it install right.
You create a manifest file basically metadata describing your app using the wind create cli tool. You typically use dot net published first to create a self contained executable that includes the dot Net run time so the user doesn't need dot Net installed separately. Then you submit your manifest to the official wing itt repository. Windows users can then just wing it install your app aid very seamless for them.
Three solid options dot Net tool, Docker wing it. Once it's out there, though, how do we manage updates? Users need a way to get new versions fixed bugs?
Versioning is crucial. The standard way is semantic versioning.
Or sever major dot minor dot exactly.
Major version bumps for breaking changes, minor for new features, backward compatible, and patch for bug fixes. It clearly communicates the nature of changes to users.
How does that work with the different packaging methods for dot net tools.
You update the version number in your projects dot cs pro file, run dot netpack and push the new nugat package version. Users can update with dot a tool update global or install specific versions for docer. You use tags when building your image doctor build, DASTMIAPP, dot one, dot one, bond zero. Users pull the specific tag they need. For wing it, you update the version in your manifest file and resubmit it. Wing It handles the upgrade process for users via wing it upgrade.
Okay, version and handled. What about performance? We want our Coli app to be fast, especially in production. Do these packaging choices matter? And how do we optimize?
Performance?
Is?
Definitely key and yes, packaging choices can influence it. First rule, always compile and release mode for production build plug debug mode, never debug mode for production. Release mode enables significant compiler optimizations that make your code run much faster and often use less memory.
Okay, release mode? What else?
For maximum efficiency, specially startup time, consider platform specific compilation. This tailor's the output binary for a specific OS and CPU architecture, or even go step further with ahead of time AOT compilation. AOT What's that it precompiles your dot net code directly to nat a machine code before deployment instead of relying on the just in time JIT compiler at run time. This can dramatically improve startup performance and
reduce the app size and dependencies. Makes it feel incredibly snappy.
Nice. The book had some examples too, right, like optimizing JSON serialization.
Yeah, optimizing things like Jason serializer serialized ACNC by using filestream directly can improve ioperformance significantly compared to say, writing to a memory stream. First, little things add up.
How do we find these performance bottlenecks in the first place?
Profiling is key. Tools like benchmark dot net are fantastic for micro benchmarking specific pieces of code. It gives you precise metrics mean execution time, error margin, standard deviation for consistency allocated memory very detailed, helps you identify hotspots, methods that are called very frequently, hot spots, and hot paths the code execution paths taken most often target your optimization
efforts there for the biggest impact. And for monitoring and production, tools like Azure Application Insights can give you real time performance data and help you spot issues as they happen.
Okay, profiling and monitoring essential. So wrapping this all up. What does this journey mean for you, our listener.
Well, we've gone from understanding what CLI apps even.
Are, right, they're surprising ubiquity.
Through building them with powerful dot Net tools like system dot command line, making them interactive and user friendly with Spectro dot.
Console, making them robust with validation, air handling logging.
Designing them well using modularity, DIPDI, integrating external services.
Safely, securing them, testing them thoroughly.
Optimizing for performance, and finally packaging and deploying them using various methods like dot net tools, Docker or wing it.
It's quite a journey, it really is, and it shows that these CLI applications, even without a fancy graphical interface, are incredibly powerful tools for automation for products.
Absolutely, they streamline workflows, solve real problems efficiently. Don't underestimate the power of the command line.
So here's a final thought, maybe a provocative one for you to chew on. Think about that bookmark application or just your own daily computer. Use those simple tasks you do over and over with a mouse clicking through menus? What if you could automate them? What comment maybe even slightly annoying repetitive tasks in your workflow, personal or professional could be dramatically sped up if you built a small, simple CLI tool for them.
Yeah, think about the hidden value there. Saving clicks, sure, but also saving context switches, reducing cognitive load. A simple command could bring surprising benefits to.
Your day to day exactly. So we really encourage you to explore the resources we've mentioned, especially to Johnny Bilminser's book building CLI applications with c sharp and dot net, and maybe check out libraries like system dot command line and Spectro dot console.
Because you know, at the end of the day, as the book wisely points out, your users aren't really interested in your amazing coding skills or how elegantyourprogram dot cs.
Is huhuh, probably not.
What they're interested in is the value your application, your CLI application brings to them. Does it solve their problem? Does it make their life easier?
That's the bottom line. So if this deep dive has sparked an idea, however small, grab those resources, start experimenting. You might surprise yourself with the power you can unlock with CLI tools in your own world.
It's all about the value you create.
Couldn't agree more
