Sign in to view Alan’s full profile
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
Sign in to view Alan’s full profile
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
United Kingdom
Sign in to view Alan’s full profile
Alan can introduce you to 10+ people at Canonical
Join with email
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
273 followers
254 connections
Sign in to view Alan’s full profile
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
View mutual connections with Alan
Alan can introduce you to 10+ people at Canonical
Join with email
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
View mutual connections with Alan
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
Sign in to view Alan’s full profile
or
Already on LinkedIn? Sign in
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
About
Welcome back
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
New to LinkedIn? Join now
Activity
273 followers
-
Alan Griffiths reposted thisAlan Griffiths reposted thisSomething curious is happening in the "A.I." coding assistant gold rush. I'm seeing developers discovering they get better results using LLMs when they: * Prompt using test cases or examples * Work in small steps * Test continuously * Review code and refactor continuously * Commit after every small step when the tests pass * Sync with the trunk branch often At the same time, I'm seeing founders making claims of 5 developers doing the work of 50 using "A.I." (U-huh. And they could read The Mythical Man-Month in 5 hours instead of 50 if they bought 10 copies.) And it occurs to me that perhaps what's actually happening is they're discovering eXtreme Programming and attributing the benefits to chatbots, when it's actually fundamental changes to their workflow that's doing the heavy lifting. Given that there's no credible evidence that LLMs significantly improve team performance, but plenty of evidence that practices like continuous testing do, which is the more likely explanation? Think "This diet works best when you jog to the butchers instead of taking the car." ___________________________________________________ Would you believe it? It just so happens that I train and mentor teams in practices like Test-Driven Development and Specification By Example, continuous testing, refactoring and continuous integration. A happy coincidence!
-
Alan Griffiths shared thisThe first of my joint talk from the Ubuntu Summit 2024 is now online: https://lnkd.in/d62RYQZt
-
Alan Griffiths shared this" Remote work, doesn’t work" absolute clickbait? I've been working for a "remote first" organisation for over a decade. Admittedly, for me, there was some communication failure in the lead up to joining that cost a day or two. But, according to more recent joiners, this has been addressed long since. It has been one of the easiest places to be effective in that I've experienced. I've also suffered on site at organisations just as ineffective as John describes, this has nothing to do with remote or on site and has everything to do with the culture.Alan Griffiths shared thisRemote work, doesn’t work. It’s ineffective and hugely wasteful. For seven months I worked for a large enterprise company and it’s been the most frustrating role of my career. Let’s start from the beginning. In July 2023 I accepted a fully remote role with the company. My start date was set for early August. Things started to look bad just over a week before my start date. It was suddenly pushed back because they weren’t ‘ready’. Then as the start date got closer, just days away I’d still had no comms. No news of when a laptop would arrive or who to contact or what to do on day one . Day one was me tracking my new boss down to arrange a meeting to chase my onboarding. It didn’t give me a great impression of my boss. Even worse when he had no plan. I’m a grown up though. I’ve been through onboarding at many organisations so I cracked on as best I could. Which didn’t go well. The organisation was extremely bureaucratic and some people clearly had learned to use that to their advantage - looking busy, but doing the absolute minimum. This seemed to be particularly amplified by being remote. Previously in bureaucratic organisations I’d solve this problem by walking around the office and speaking to people. Then if needs be, talk to their boss/approver and figure out how to get things done. Remotely, with people spread across many timezones that just wasn’t possible. It’s too easy to be anonymous and hide behind Slack when that’s all there is. The net result, access to the very basic systems took a month, and many things I still didn’t have when I left six months later. The many sagas of this role bring me to the conclusion that remote work doesn’t work if you don’t have the right people and processes. And things haven’t improved in the month since I’ve left, I’m still trying to return their hardware to them.
-
Alan Griffiths shared thisAn old article comes back to haunt me?! It seems like a long time since I wrote this: but only four years! The world has changed a lot in that time, but this overview of app confinement is still valid.Alan Griffiths shared thisA Secure Environment for Running Apps? By Alan Griffiths Getting apps from the app store is easy. Alan Griffiths considers this from a security perspective. https://buff.ly/3Nkk8vk #ACCU #SoftwareEngineering #Throwback #Programming
-
Alan Griffiths shared thisMy talk from the Ubuntu Summit 2023 is now online. There's also a blog update covering much of the same material. https://lnkd.in/eQcWWC8i https://lnkd.in/e23gzVXq
-
Alan Griffiths shared thisThe premise of the question is flawed. Most open source contributions come from companies and organisations not individual hobbyists. And it is not "for free" as all contributors do so because they get value from doing so. That might be because it it makes the software effective for their business, or because it "scratches an itch".Alan Griffiths shared this“Who can afford to do professional work for nothing? What hobbyist can put three man-years into programming, finding all bugs, documenting his product, and distributing it for free?” — Bill Gates, 1976 An interesting question to consider with respect to FREE Open Source Software, what do you think?
-
-
Alan Griffiths shared thisAlan Griffiths shared thisIntegrating applications that have a graphic interface in embedded systems used to be a challenge. With Ubuntu Frame, building IoT devices, kiosks and digital signage solutions has never been easier. Join Canonical’s Michał Sawicz, Mir Engineering Manager, and Gabriel Aguiar Noury, Product Manager on the 7th of June to discover the 6 steps to build your digital signage solution. #Ubuntu #IoT #DigitalSignage
-
Alan Griffiths shared thisWhat does it mean to be a senior member of a team? IMO means a responsibility and ability to ensure effective practices are adopted and followed by the team. There's a certain cognitive dissonance in reading this story. What John calls "the senior" acts in a way I wouldn't expect from a "senior", while the one he calls "the junior" adopts a more mature and effective approach.Alan Griffiths shared thisLast week I witnessed a great example of the importance of soft skills as a software engineer. Two engineers were blocked on their work, one junior and one senior. The senior asked for some help from another team. An engineer on the other team reached out and offered to help and spent a couple of hours helping out. The engineer who was helping out identified that the issue might be being caused by a third party and suggested the senior reach out to them for help. In the meantime if they shared their code he’d try debugging it further. He heard nothing back. In the meantime a junior engineer reached out for help, set up a call and started pairing on the issue. The engineer and junior worked together for a few hours and found a solution to the junior engineer’s challenge. The junior engineer thanked him privately and again later in public, acknowledging the help he’d received. Meanwhile the senior engineer raised a vey public and formal complaint about the team he had asked for help’s system. This naturally put the engineer who’d helped him on the defensive (and probably the whole team) - pointing out they was helping until the senior engineer stopped trying to find a solution. Putting someone on the defensive can make them feel attacked or criticised, causing them to become guarded and less willing to collaborate or communicate effectively. This can lead to a breakdown in relationships and eventually leads to the kind of politics we all hate in the workplace. The junior on the other hand has built a good relationship that will probably lead to good future collaboration. Remember, soft skills, such as effective communication and gratitude, are just as important as technical skills for software engineers. Building ant significant bit of software is a team activity. If this pattern continues, I see the junior progressing well in his career and the senior struggling to progress. #leadership #juniordeveloper #softskills #softwareengineering
-
Alan Griffiths liked thisSafe String Parsing in Modern C++ I work on some open-source projects in my free time and I noticed a lot of unhandled "std::stoi" calls in DB layer. To avoid scattering try-catch blocks everywhere and prevent runtime crashes. In C++, conversion functions like "std::stoi" throw exception on failure. Chooseable C++23 features like "std::expected" instead of "std::optional" but i'm using C++20. An example for noexcept wrapper based on std::from_chars. Demo(godbolt): https://lnkd.in/d6HFEdWK
-
Alan Griffiths liked thisAlan Griffiths liked thisI’ve seen Metallica, Megadeth, and Tool live, but until last night’s NYC++ Meetup, I hadn’t seen Bjarne Stroustrup, the father of C++. He wasn’t just playing the classics; C++ is alive and evolving, and he articulated how the new and upcoming features are able to help realize and refine the vision he has had since the beginning. Programming languages let us express our engineering ideas, including our compassion for ourselves and our colleagues. I found myself mostly agreeing with Stroustrup but also feeling his numeric-conversion examples, while much improved from raw C++, still had more implicit conversion (albeit checked!) than I would prefer. Fortunately C++ gives us the flexibility to choose exactly how our types behave, and different solutions are appropriate for different situations. Two choice quotes: 1. On the tragedy that -1 < 2u is false: “-1 should be less than 2u. But it isn’t. Dennis [Ritchie] had a bad day.” 2. On Concepts being functions—and that while you can write them in terms of the raw language, most of us write them in terms of other Concepts, just as production functions are written in terms of other functions: “Beginners write all their code in the basic language.” I’ve thought this for years but had never heard it stated so cleanly. Thanks for a thought-provoking talk, and thanks to Daniel Katz and others for organizing and Deutsche Bank for hosting. As Tool put it, “cold silence has a tendency to atrophy any sense of compassion”, so reach out! And if you care about good C++, my team at NVIDIA, TensorRT, is hiring!
-
Alan Griffiths liked thisAlan Griffiths liked thisI often see C++ described as a "descendant of C." That's of course true, but it forgets a most important fact: C++ is a descendant of C *and* Simula. From C, it inherits the ability to manipulate hardware. From Simula, it inherits the ability to define user-defined types and build hierarchies of them them (OOP) and also the ideal of static type safety. To unify the two styles ("Paradims") it has to support Generic Programming. See https://lnkd.in/ebJSzxGF "Concept-based Generic Programming". October 2025. and https://lnkd.in/e3NP4Bjn "21st Century C++". February 2025.
-
Alan Griffiths liked thisAlan Griffiths liked thisIt’s almost 2026… and many of us still write C++98-style code So let’s fix that. Here are 5 examples of C++98 → Modern C++ that instantly make your code cleaner and more expressive. Modern C++ isn’t about fancy features — it’s safer, clearer, and looks like it belongs in 2026. 💬 Comment your favorite Modern C++ upgrade below! I’ll include the best ones in the next part. #ModernCpp #Cpp #Cpp20 #Cpp23 #CleanCode #Developers #XploreCpp #Programming #SoftwareEngineering
-
Alan Griffiths reacted on thisAlan Griffiths reacted on thisAAAAAAAHHHHHHHHHH!!!!! once again!! AAAAAAAHHHHHHHHHHH!! #TechHumor #SoftwareEngineering
-
Alan Griffiths liked thisAlan Griffiths liked thisI've been watching developers learn TDD for 25 years, and I have a reasonable ballpark on what it takes. Roughly 1,000 red-green-refactor-commit cycles for the "rules" to become habits, and to scale the learning curve enough to make TDD work in practice on everyday code bases. If you progress from regular practice (e.g., 2 hours a week) to TDD-ing on most of your code (10-15 hours a week, apparently), you're looking at 4-6 months. And that, folks, is why "We tried TDD and it didn't work"
Experience & Education
-
Canonical Ltd.
***** ********
-
******** ***
*****
-
****
*****
View Alan’s full experience
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
Welcome back
By clicking Continue to join or sign in, you agree to LinkedIn’s User Agreement, Privacy Policy, and Cookie Policy.
New to LinkedIn? Join now
Courses
-
Mathematics
-
Projects
Recommendations received
10 people have recommended Alan
Join now to viewView Alan’s full profile
-
See who you know in common
-
Get introduced
-
Contact Alan directly
Other similar profiles
Explore more posts
-
Sepehr Bijani
NXP Semiconductors • 649 followers
As software systems grow in scale and complexity, ensuring reliability becomes increasingly challenging. Subtle and preventable bugs—especially those rooted in undefined behavior and the absence of well-defined boundaries—can silently compromise system integrity. Undefined behaviors represent a broad class of preventable bugs that are nearly impossible to track or detect manually. A language that eliminates such bugs can significantly reduce the need for extensive testing and static analysis, keeping test development more manageable. Another major challenge in today’s software growth is integration, along with the increasing safety and security concerns at component boundaries. As components are integrated, the number of required test cases multiplies rapidly. Strongly typed APIs help enforce safety at software component boundaries. The compiler can catch misuse of dependencies during compilation, ensuring correctness before the system even runs.
9
-
Guillermo Gutiérrez Almazor
DNSimple • 306 followers
I've published a new blog post introducing two open source tools I've been working on: Minicrest and GWT. Minicrest brings Hamcrest-style composable matchers to Ruby's Minitest. If you value expressive, readable tests that clearly communicate intent, this library helps you build assertions that compose naturally and provide detailed failure messages. GWT is a CLI tool that simplifies git worktree management. One motivation for building it was enabling parallel work with coding agents like Claude Code. Each agent gets its own isolated worktree, making it practical to explore multiple solutions to the same problem simultaneously and compare the results. The post covers the philosophy behind both tools and how they fit into my workflow. https://lnkd.in/dYrKguGu
9
1 Comment -
❄️ Robert Roskam
Pantheon • 14K followers
Some great thoughts for pair programming with agents by Nick Radcliffe: https://lnkd.in/eya7QdqE Best set of quotes: > So it’s tempting to think that Claude’s knowledge is broad but shallow. > But that’s wrong. > So Claude’s knowledge is broad and deep. > But that is wrong too. > A library “contains” knowledge but knows nothing. There is a sense in which Claude might be said to “know” something. > Claude “knows” a lot of things but doesn’t really understand what it knows
3
-
Chase Tingley
Lilt • 1K followers
About ten years ago, I was a real nuisance to people on the XLIFF TC about what I thought were the failings of the XLIFF 1.2 specification. That spec is (I still think) too casual and too vague, and this led to a lot of interoperability problems. Surely, I argued, if XLIFF 2.0 had a clearer, more pedantic specification, these problems would disappear. I owe those people an apology. XLIFF 2.0 (and 2.1, and 2.2) are written much more clearly and carefully. But as more and more tools start producing XLIFF 2.x content, a large percentage of the XLIFF 2.0 files I see in the wild are invalid, either under the schema or the spec! The basic structure is generally correct, but the details (particularly around the ID rules) seem to trip people up. However, it's not all bad news. Unlike with XLIFF 1.2, 2.x hasn't seen the rise of full tool-specific variants of the format, and I believe the revised approach to extensibility in 2.x has been an important reason why.
46
5 Comments -
Aleksandr Kichev
Self-hosted projects • 779 followers
Rare occasion of me posting something on LinkedIn full of experts and opinions, so I’m trying to share something genuinely useful. Over the last few months I’ve been very active in agentic engineering and kept running into tooling gaps I had to close for myself (and for a few people from the community). 1. Holding a local environment together with agentic tools is still annoying and doesn’t give enough control or flexibility. If I control execution myself, I waste time on terminal babysitting. If Cursor/Claude controls it, I lose visibility: I can’t properly read logs or understand what’s going on. So I built Crux, an AI-optimized local tool to run your app and keep it observable. The idea is simple: generate a config with an LLM, run crux in the terminal, and it starts your backend, frontend, mobile app, and dependencies, with logs you can actually follow. The main “magic” is built-in MCP support, so your agentic tool can also control the execution lifecycle: read logs, restart an instance, or trigger hot reload for a Flutter app. Tested on macOS only for now. If you make it work on Linux, contributions are welcome. https://lnkd.in/gnSAnWji [1/2]
6
-
Josh Jackson
Patchworks • 400 followers
I saw a post earlier that says: “Using ORMs is generally bad practice”. What a load of rubbish. One of my dev pet hates is the use of good/bad practice. What used to be reasonable guidelines are now wielded as laws that must be adhered to regardless of the situation. Don’t get me wrong, there are definitely guidelines on what is typically better or worse. For example, never build your own encryption, never trust user data, use the same code conventions across a team. All very reasonable guidelines that could apply to the majority of projects. But things like using particular language features or tools being “bad practice” is just rubbish. Use what is best for the situation and the future of the project. In almost all cases, everything has its place. It is extremely rare that something is just blanket right or wrong.
6
2 Comments -
Chris Dunkel, MS
Career Forge • 922 followers
“Oh, my code is self-documenting.” I stared blankly at the junior engineer across from me. Then I stared back at the incomprehensible block of code he had just assured me explained itself. “Well,” I said, “unfortunately I’m not sure what any of this does, so you’re going to have to walk me through it.” At that point in my career, I already had over a decade of experience building mobile apps. I wasn’t new to engineering. What I was new to was the framework this open-source project was built on. And that’s the problem. To him, the code felt obvious. The context was fresh. The decisions were still in his head. To me, it felt unfamiliar and difficult to navigate. Could I have eventually figured it out? Absolutely. Given some time, I could have reverse-engineered the intent and made the changes I needed. But the complete lack of comments or signposts explaining why certain decisions were made turned what should have been straightforward work into something slow and frustrating. This is why “self-documenting code” is a myth. Good code can show you what the system is doing, but it rarely tells you why it exists in its current form. Why this approach instead of another? Why this edge case? Why this workaround that looks unnecessary at first glance? That context doesn’t live in variable names. It lives in comments and documentation. Documentation isn’t about explaining syntax. It’s about transferring intent across time. If you care about maintainability, onboarding, and long-term velocity, writing comments isn’t optional. It’s an act of empathy for the next engineer who has to live in your code. And, sometimes, that next engineer is you six months down the line. Be kind, comment! Happy building (and commenting)! 🚀
330
135 Comments -
Gorjan Zajkovski
BUX • 2K followers
Great step-by-step breakdown and an explanation of the latest hype around emerging AI tools. Yes, they are (and can be) incredibly powerful when given proper context, proper instructions and well defined access and blast radius... No, they are not AGI, nor are they sentient, and should not be treated as such.
7
-
Claudio Lassala
2K followers
Event sourcing and BDD scenarios share the same mental model: both capture what has happened, not what hasn't. In event sourcing, we name events in past tense: "OrderPlaced," "PaymentReceived," "InvoiceAged." In Given-When-Then scenarios, the Given section describes past conditions—things that have already occurred. Here's what this means practically: there's no "payment not made" event because nothing happened. But "time passed"? That's an event we can capture if it has meaning in the domain. This shapes how I write Given statements. Instead of "Given I have not paid my invoice," I write "Given seven days have passed and there's no record of payment." Every Given becomes something that actually occurred—making scenarios more testable and mapping better to how (not just automated) systems really work. How do you handle time-based events in your scenarios? https://lnkd.in/gcMZHdph
14
8 Comments -
Kornelis Sietsma
John Lewis Partnership • 2K followers
I wrote a post on Agentic AI and Security for our Liberis internal engineering blog, which I thought was worth sharing more widely: https://lnkd.in/eBcavNGF Full credit - this is mostly taken from Simon Willison's classic article https://lnkd.in/eh89sFuW
13
1 Comment -
Dmitry Polonsky
AZP Cloud LLC • 519 followers
I started to look into Vibe Coding last week. it's a type of project that has no sensitivity, so I rolled into it allot of objectives. .....One week into vibe coding hardly makes me an expert. AI does not see across tiers, so it was arguing with me that a Stored Proc needs to be changed and not the middle tier code. people that read my posts, know my contempt for statements that AI is responsible for the bad job market. I can't really reflect on last week and say that I have gotten further with AI then I would without. Code is at the point where it would need to be refactored, AI or my code at this stage - that is expected. I am designing a green field project, Ai is helpful in the sense that I am less destructed from system or architectural design. But AI's input in these matters is not very useful, and testing certain things at Unit level is more time consuming then me doing it from scratch. Comparable to an new, JR Developer, Can't Trust AI's code, just as I can't trust JR Developer's code. ... A Jr Developer - saw a couch in the office and decided that sleep during business hours is a good idea. ... A JR developer decided that they are smarter then every-one and it's not obvious to us their pointless miss appropriation of company resources. ..... This is where AI is better. I think that projected growth of US - IT job market can barely satisfy all displaced, it will be a while before we see binge hiring of entry level. This entry level will need to bring more maturity to the table then ever before.
-
Davs Howard
Major Digital • 527 followers
Technical debt, often a website or platform's greatest enemy, doesn't always have to be a problem. Not know what debt matters most does - unranked debt if you will. Most engineering teams already know what is wrong with their stack. The issue is that they do not agree on what matters most. Everything feels risky. Everything feels slow. So the backlog grows, and nothing fundamental changes because touching it feels, well, dangerous. I have seen this pattern repeat. Debt becomes a guilt list rather than a plan. A simple prioritisation lens helps: Stability; Speed; Control. Stability is anything that could break production or compromise compliance. Speed is what makes change expensive or painful. Control is what limits visibility, testing, and safe releases. Once issues are grouped this way, the conversation changes. You stop debating every item in the backlog and start asking where risk actually lives. Then do the hardest thing - choose. Pick how ever many fixes works for your team for the next 90 days that reduce risk the most. Not the loudest issues or the ones with the biggest architectural consequences. The ones that meaningfully improve stability, speed, or control. This is how technical debt stops feeling paralysing and starts feeling manageable.
1
-
Maciej Lesiczka
Clari • 682 followers
Sharing my personal project I've been working on in my spare time - Azof. It is a lakehouse table format on top of Parquet with point-in-time queries as a first-class capability. Think Apache Iceberg with event-time travel. The goal of this project is to create a table format that provides the same guarantees as other existing formats, but with bi-temporal query support (and most importantly, giving myself a chance to experiment with Rust). So far I've implemented the backbone of the read path and added DataFusion integration. With a little DF parser extension, it is now possible to query it with regular SQL. https://lnkd.in/d_WJYkGq
32
1 Comment -
Eamonn Faherty
Amazon Web Services (AWS) • 3K followers
I have been asked a few times to share how I think about agentic code editors, their role, how they fit in with development and if I think they are any good. I thought it may be good to share here. I see agentic code editors as members of my team who are amazing at some things but get stuck on others. I need to invest in them to get better results from them and if I do not provide quality inputs I get pretty varied results. If I want to take a risk with a less detailed / lower quality input I normally start the task going into a meeting. I perform a git diff when I return and can always revert if I am not happy with the change. As I am working, I think before asking an agent to complete a task for me and in some instances I break a task up into smaller tasks to increase the agents chance of success. I find reviewing the work of smaller tasks easier and so I get a better productivity gain when breaking complex tasks up. I find agents are really good at summarizing code bases to create artefacts such as data flow documents and gherkin specifications. When I do this I ask the agent to include references to the source code, unit tests or integration tests within the generated documents they create so I can review and approve their analysis more easily - it helps me connect the dots. Sometimes I leave their references in and at other times I remove the references as I review - it really depends what I need at the time. In all cases, they perform this work in seconds whereas I would have taken hours or even days. I find they struggle with other tasks such as adding a parameter to a method and updating multiple other methods so the parameter is passed across them. I find using my code editors refactoring tools more reliable and faster. I typically use add/extract parameter or rename parameter refactoring tools in my editor instead of using an agent. Even when performing a rename across multiple files I use a few search and replaces instead of using agents. I find them slow when working with larger files. I am not a big fan of large files of source code and so this is sort of a 'serves me right' or an encouragement to improve the code by reducing the file size.
9
-
Jeremy Kuhne
Microsoft • 311 followers
One of the coolest features of C# 14 is extension members (releasing with .NET 10 in November). You can finally add extensions to static classes and static extensions in general. This is fantastic for logical composition and discovery. https://lnkd.in/gjnNBMBw One cool use case for this is more complete polyfill when you're multi-targeting for .NET and .NET Framework (yep, this works on both!). I've been fiddling with this in one of my libraries. One example is adding throw extensions so you can do things like `ArgumentNullException.ThrowIfNull` when multi-targeting. https://lnkd.in/gQN-2uGp I'm hoping we can eventually provide this sort of assembly directly from the .NET team in the future. I'm poking on it internally because I believe it has a lot of value to long-term .NET users that still need to build for .NET Framework. If this would be valuable to you, please let me know. :)
10
3 Comments
Explore collaborative articles
We’re unlocking community knowledge in a new way. Experts add insights directly into each article, started with the help of AI.
Explore More